X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fintel_rdt.c;h=446dc6559d6d722b3bef7d7fd5e9ac60f2864267;hb=62be067773ebc9d9d958c9707332bfeaecedac8a;hp=b254ba78d0a20ed74f38e6f4ba3f69df3a512db8;hpb=bf0d5c93adbc022d3e5b3e691fb363a60f1c3a41;p=collectd.git diff --git a/src/intel_rdt.c b/src/intel_rdt.c index b254ba78..446dc655 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -1,7 +1,7 @@ /** * collectd - src/intel_rdt.c * - * Copyright(c) 2016 Intel Corporation. All rights reserved. + * Copyright(c) 2016-2018 Intel Corporation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,13 +23,12 @@ * * Authors: * Serhiy Pshyk + * Starzyk, Mateusz **/ -#include "common.h" #include "collectd.h" - -#include "utils_config_cores.h" - +#include "utils/common/common.h" +#include "utils/config_cores/config_cores.h" #include #define RDT_PLUGIN "intel_rdt" @@ -37,6 +36,11 @@ #define RDT_MAX_SOCKETS 8 #define RDT_MAX_SOCKET_CORES 64 #define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS) +/* + * Process name inside comm file is limited to 16 chars. + * More info here: http://man7.org/linux/man-pages/man5/proc.5.html + */ +#define RDT_MAX_PROC_COMM_LENGTH 16 typedef enum { UNKNOWN = 0, @@ -54,7 +58,7 @@ struct rdt_ctx_s { }; typedef struct rdt_ctx_s rdt_ctx_t; -static rdt_ctx_t *g_rdt = NULL; +static rdt_ctx_t *g_rdt; static rdt_config_status g_state = UNKNOWN; @@ -66,18 +70,18 @@ static void rdt_dump_cgroups(void) { return; DEBUG(RDT_PLUGIN ": Core Groups Dump"); - DEBUG(RDT_PLUGIN ": groups count: %zu", g_rdt->num_groups); + DEBUG(RDT_PLUGIN ": groups count: %" PRIsz, g_rdt->num_groups); - for (int i = 0; i < g_rdt->num_groups; i++) { + for (size_t i = 0; i < g_rdt->num_groups; i++) { core_group_t *cgroup = g_rdt->cores.cgroups + i; memset(cores, 0, sizeof(cores)); - for (int j = 0; j < cgroup->num_cores; j++) { + for (size_t j = 0; j < cgroup->num_cores; j++) { snprintf(cores + strlen(cores), sizeof(cores) - strlen(cores) - 1, " %d", cgroup->cores[j]); } - DEBUG(RDT_PLUGIN ": group[%d]:", i); + DEBUG(RDT_PLUGIN ": group[%zu]:", i); DEBUG(RDT_PLUGIN ": description: %s", cgroup->desc); DEBUG(RDT_PLUGIN ": cores: %s", cores); DEBUG(RDT_PLUGIN ": events: 0x%X", g_rdt->events[i]); @@ -101,8 +105,7 @@ static void rdt_dump_data(void) { * MBR - remote memory bandwidth */ DEBUG(" CORE RMID LLC[KB] MBL[MB] MBR[MB]"); - for (int i = 0; i < g_rdt->num_groups; i++) { - + for (size_t i = 0; i < g_rdt->num_groups; i++) { const struct pqos_event_values *pv = &g_rdt->pgroups[i]->values; double llc = bytes_to_kb(pv->llc); @@ -125,7 +128,7 @@ static void rdt_free_cgroups(void) { static int rdt_default_cgroups(void) { unsigned num_cores = g_rdt->pqos_cpu->num_cores; - g_rdt->cores.cgroups = calloc(num_cores, sizeof(*(g_rdt->cores.cgroups))); + g_rdt->cores.cgroups = calloc(num_cores, sizeof(*g_rdt->cores.cgroups)); if (g_rdt->cores.cgroups == NULL) { ERROR(RDT_PLUGIN ": Error allocating core groups array"); return -ENOMEM; @@ -138,7 +141,7 @@ static int rdt_default_cgroups(void) { char desc[DATA_MAX_NAME_LEN]; /* set core group info */ - cgroup->cores = calloc(1, sizeof(*(cgroup->cores))); + cgroup->cores = calloc(1, sizeof(*cgroup->cores)); if (cgroup->cores == NULL) { ERROR(RDT_PLUGIN ": Error allocating cores array"); rdt_free_cgroups(); @@ -159,9 +162,9 @@ static int rdt_default_cgroups(void) { return num_cores; } -static int rdt_is_core_id_valid(int core_id) { +static int rdt_is_core_id_valid(unsigned int core_id) { - for (int i = 0; i < g_rdt->pqos_cpu->num_cores; i++) + for (unsigned int i = 0; i < g_rdt->pqos_cpu->num_cores; i++) if (core_id == g_rdt->pqos_cpu->cores[i].lcore) return 1; @@ -183,9 +186,9 @@ static int rdt_config_cgroups(oconfig_item_t *item) { for (size_t group_idx = 0; group_idx < n; group_idx++) { core_group_t *cgroup = g_rdt->cores.cgroups + group_idx; for (size_t core_idx = 0; core_idx < cgroup->num_cores; core_idx++) { - if (!rdt_is_core_id_valid((int) cgroup->cores[core_idx])) { - ERROR(RDT_PLUGIN ": Core group '%s' contains invalid core id '%d'", - cgroup->desc, (int)cgroup->cores[core_idx]); + if (!rdt_is_core_id_valid(cgroup->cores[core_idx])) { + ERROR(RDT_PLUGIN ": Core group '%s' contains invalid core id '%u'", + cgroup->desc, cgroup->cores[core_idx]); rdt_free_cgroups(); return -EINVAL; } @@ -200,13 +203,13 @@ static int rdt_config_cgroups(oconfig_item_t *item) { ERROR(RDT_PLUGIN ": Error creating default core groups configuration."); return ret; } - n = (size_t) ret; + n = (size_t)ret; INFO(RDT_PLUGIN ": No core groups configured. Default core groups created."); } /* Get all available events on this platform */ - for (int i = 0; i < g_rdt->cap_mon->u.mon->num_events; i++) + for (unsigned int i = 0; i < g_rdt->cap_mon->u.mon->num_events; i++) events |= g_rdt->cap_mon->u.mon->events[i].type; events &= ~(PQOS_PERF_EVENT_LLC_MISS); @@ -240,6 +243,226 @@ static int rdt_config_cgroups(oconfig_item_t *item) { return 0; } +/* Helper typedef for process name array + * Extra 1 char is added for string null termination. + */ +typedef char proc_comm_t[RDT_MAX_PROC_COMM_LENGTH + 1]; + +/* Linked one-way list of pids. */ +typedef struct pids_list_s { + pid_t pid; + struct pids_list_s *next; +} pids_list_t; + +/* Holds process name and list of pids assigned to that name */ +typedef struct proc_pids_s { + proc_comm_t proccess_name; + pids_list_t *pids; +} proc_pids_t; + +/* + * NAME + * pids_list_add_pid + * + * DESCRIPTION + * Adds pid at the end of the pids list. + * Allocates memory for new pid element, it is up to user to free it. + * + * PARAMETERS + * `list' Head of target pids_list. + * `pid' Pid to be added. + * + * RETURN VALUE + * On success, returns 0. + * -1 on memory allocation error. + */ +static int pids_list_add_pid(pids_list_t **list, const pid_t pid) { + pids_list_t *new_element = calloc(1, sizeof(*new_element)); + + if (new_element == NULL) { + ERROR(RDT_PLUGIN ": Alloc error\n"); + return -1; + } + new_element->pid = pid; + new_element->next = NULL; + + pids_list_t **current = list; + while (*current != NULL) { + current = &((*current)->next); + } + *current = new_element; + return 0; +} + +/* + * NAME + * read_proc_name + * + * DESCRIPTION + * Reads process name from given pid directory. + * Strips new-line character (\n). + * + * PARAMETERS + * `procfs_path` Path to systems proc directory (e.g. /proc) + * `pid_entry' Dirent for PID directory + * `name' Output buffer for process name, recommended proc_comm. + * `out_size' Output buffer size, recommended sizeof(proc_comm) + * + * RETURN VALUE + * On success, the number of read bytes (includes stripped \n). + * -1 on file open error + */ +static int read_proc_name(const char *procfs_path, + const struct dirent *pid_entry, char *name, + const size_t out_size) { + assert(procfs_path); + assert(pid_entry); + assert(name); + assert(out_size); + memset(name, 0, out_size); + + const char *comm_file_name = "comm"; + + char *path = ssnprintf_alloc("%s/%s/%s", procfs_path, pid_entry->d_name, + comm_file_name); + + FILE *f = fopen(path, "r"); + if (f == NULL) { + ERROR(RDT_PLUGIN ": Failed to open comm file, error: %d\n", errno); + sfree(path); + return -1; + } + size_t read_length = fread(name, sizeof(char), out_size, f); + fclose(f); + sfree(path); + /* strip new line ending */ + char *newline = strchr(name, '\n'); + if (newline) { + *newline = '\0'; + } + + return read_length; +} + +/* + * NAME + * get_pid_number + * + * DESCRIPTION + * Gets pid number for given /proc/pid directory entry or + * returns error if input directory does not hold PID information. + * + * PARAMETERS + * `entry' Dirent for PID directory + * `pid' PID number to be filled + * + * RETURN VALUE + * 0 on success. Negative number on error: + * -1: given entry is not a directory + * -2: PID conversion error + */ +static int get_pid_number(struct dirent *entry, pid_t *pid) { + char *tmp_end; /* used for strtoul error check*/ + + if (pid == NULL || entry == NULL) + return -1; + + if (entry->d_type != DT_DIR) + return -1; + + /* trying to get pid number from directory name*/ + *pid = strtoul(entry->d_name, &tmp_end, 10); + if (*tmp_end != '\0') { + return -2; /* conversion failed, not proc-pid */ + } + /* all checks passed, marking as success */ + return 0; +} + +/* + * NAME + * fetch_pids_for_procs + * + * DESCRIPTION + * Finds PIDs matching given process's names. + * Searches all PID directories in /proc fs and + * allocates memory for proc_pids structs, it is up to user to free it. + * Output array will have same element count as input array. + * + * PARAMETERS + * `procfs_path' Path to systems proc directory (e.g. /proc) + * `procs' Array of null-terminated strings with + * process' names to search for + * `procs_size' procs array element count + * `proc_pids_array' Address of pointer, under which new + * array of proc_pids will be allocated. Must be NULL. + * + * RETURN VALUE + * 0 on success. Negative number on error: + * -1: could not open /proc dir + */ +__attribute__((unused)) /* TODO: remove this attribute when PID monitoring is + implemented */ +static int +fetch_pids_for_procs(const char *procfs_path, const char **procs_names_array, + const size_t procs_names_array_size, + proc_pids_t **proc_pids_array) { + assert(procfs_path); + assert(procs_names_array); + assert(procs_names_array_size); + assert(proc_pids_array); + assert(NULL == *proc_pids_array); + + DIR *proc_dir = opendir(procfs_path); + if (proc_dir == NULL) { + ERROR(RDT_PLUGIN ": Could not open %s directory, error: %d", procfs_path, + errno); + return -1; + } + + /* Copy procs names to output array. Initialize pids list with NULL value. */ + (*proc_pids_array) = + calloc(procs_names_array_size, sizeof(**proc_pids_array)); + for (size_t i = 0; i < procs_names_array_size; ++i) { + sstrncpy((*proc_pids_array)[i].proccess_name, procs_names_array[i], + STATIC_ARRAY_SIZE((*proc_pids_array)[i].proccess_name)); + (*proc_pids_array)[i].pids = NULL; + } + + /* Go through procfs and find PIDS and their comms */ + struct dirent *entry; + while ((entry = readdir(proc_dir)) != NULL) { + + pid_t pid; + int pid_conversion = get_pid_number(entry, &pid); + if (pid_conversion < 0) + continue; + + proc_comm_t comm; + int read_result = + read_proc_name(procfs_path, entry, comm, sizeof(proc_comm_t)); + if (read_result <= 0) { + ERROR(RDT_PLUGIN ": Comm file skipped. Read result: %d", read_result); + continue; + } + + /* Try to find comm in input procs array (proc_pids_array has same names) */ + for (size_t i = 0; i < procs_names_array_size; ++i) { + if (0 == strncmp(comm, (*proc_pids_array)[i].proccess_name, + STATIC_ARRAY_SIZE(comm))) + pids_list_add_pid(&((*proc_pids_array)[i].pids), pid); + } + } + + int close_result = closedir(proc_dir); + if (0 != close_result) { + ERROR(RDT_PLUGIN ": failed to close %s directory, error: %d", procfs_path, + errno); + return -1; + } + return 0; +} + static void rdt_pqos_log(void *context, const size_t size, const char *msg) { DEBUG(RDT_PLUGIN ": %s", msg); } @@ -337,8 +560,8 @@ static int rdt_config(oconfig_item_t *ci) { return 0; } -static void rdt_submit_derive(char *cgroup, char *type, char *type_instance, - derive_t value) { +static void rdt_submit_derive(const char *cgroup, const char *type, + const char *type_instance, derive_t value) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.derive = value}; @@ -353,8 +576,8 @@ static void rdt_submit_derive(char *cgroup, char *type, char *type_instance, plugin_dispatch_values(&vl); } -static void rdt_submit_gauge(char *cgroup, char *type, char *type_instance, - gauge_t value) { +static void rdt_submit_gauge(const char *cgroup, const char *type, + const char *type_instance, gauge_t value) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.gauge = value}; @@ -387,7 +610,7 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) { rdt_dump_data(); #endif /* COLLECT_DEBUG */ - for (int i = 0; i < g_rdt->num_groups; i++) { + for (size_t i = 0; i < g_rdt->num_groups; i++) { core_group_t *cgroup = g_rdt->cores.cgroups + i; enum pqos_mon_event mbm_events = @@ -426,7 +649,7 @@ static int rdt_init(void) { return ret; /* Start monitoring */ - for (int i = 0; i < g_rdt->num_groups; i++) { + for (size_t i = 0; i < g_rdt->num_groups; i++) { core_group_t *cg = g_rdt->cores.cgroups + i; ret = pqos_mon_start(cg->num_cores, cg->cores, g_rdt->events[i], @@ -449,7 +672,7 @@ static int rdt_shutdown(void) { return 0; /* Stop monitoring */ - for (int i = 0; i < g_rdt->num_groups; i++) { + for (size_t i = 0; i < g_rdt->num_groups; i++) { pqos_mon_stop(g_rdt->pgroups[i]); }