X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fprocesses.c;h=f556912348b04585e6d360255918382b35adab7b;hp=82a485900537e891336ac5185c67cd951ed33d28;hb=da11ce02eb202b3e01d3e2d1b40f248a84430973;hpb=867ad628dc6fcd05bd584b605d7093cfc00c3d07 diff --git a/src/processes.c b/src/processes.c index 82a48590..f5569123 100644 --- a/src/processes.c +++ b/src/processes.c @@ -33,6 +33,7 @@ * Clément Stenac * Cosmin Ioiart * Pavel Rochnyack + * Wilfried Goesgens **/ #include "collectd.h" @@ -168,6 +169,7 @@ typedef struct process_entry_s { unsigned long num_proc; unsigned long num_lwp; unsigned long num_fd; + unsigned long num_maps; unsigned long vmem_size; unsigned long vmem_rss; unsigned long vmem_data; @@ -185,6 +187,8 @@ typedef struct process_entry_s { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; _Bool has_io; derive_t cswitch_vol; @@ -192,6 +196,8 @@ typedef struct process_entry_s { _Bool has_cswitch; _Bool has_fd; + + _Bool has_maps; } process_entry_t; typedef struct procstat_entry_s { @@ -209,6 +215,8 @@ typedef struct procstat_entry_s { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; derive_t cswitch_vol; derive_t cswitch_invol; @@ -225,6 +233,7 @@ typedef struct procstat { unsigned long num_proc; unsigned long num_lwp; unsigned long num_fd; + unsigned long num_maps; unsigned long vmem_size; unsigned long vmem_rss; unsigned long vmem_data; @@ -242,11 +251,14 @@ typedef struct procstat { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; derive_t cswitch_vol; derive_t cswitch_invol; _Bool report_fd_num; + _Bool report_maps_num; _Bool report_ctx_switch; struct procstat *next; @@ -258,6 +270,7 @@ static procstat_t *list_head_g = NULL; static _Bool want_init = 1; static _Bool report_ctx_switch = 0; static _Bool report_fd_num = 0; +static _Bool report_maps_num = 0; #if HAVE_THREAD_INFO static mach_port_t port_host_self; @@ -310,10 +323,13 @@ static procstat_t *ps_list_register(const char *name, const char *regexp) { new->io_wchar = -1; new->io_syscr = -1; new->io_syscw = -1; + new->io_diskr = -1; + new->io_diskw = -1; new->cswitch_vol = -1; new->cswitch_invol = -1; new->report_fd_num = report_fd_num; + new->report_maps_num = report_maps_num; new->report_ctx_switch = report_ctx_switch; #if HAVE_REGEX_H @@ -464,6 +480,7 @@ static void ps_list_add(const char *name, const char *cmdline, ps->num_proc += entry->num_proc; ps->num_lwp += entry->num_lwp; ps->num_fd += entry->num_fd; + ps->num_maps += entry->num_maps; ps->vmem_size += entry->vmem_size; ps->vmem_rss += entry->vmem_rss; ps->vmem_data += entry->vmem_data; @@ -480,7 +497,12 @@ static void ps_list_add(const char *name, const char *cmdline, ps_update_counter(&ps->io_syscw, &pse->io_syscw, entry->io_syscw); } - if ((entry->cswitch_vol != -1) && (entry->cswitch_vol != -1)) { + if ((entry->io_diskr != -1) && (entry->io_diskw != -1)) { + ps_update_counter(&ps->io_diskr, &pse->io_diskr, entry->io_diskr); + ps_update_counter(&ps->io_diskw, &pse->io_diskw, entry->io_diskw); + } + + if ((entry->cswitch_vol != -1) && (entry->cswitch_invol != -1)) { ps_update_counter(&ps->cswitch_vol, &pse->cswitch_vol, entry->cswitch_vol); ps_update_counter(&ps->cswitch_invol, &pse->cswitch_invol, @@ -508,6 +530,7 @@ static void ps_list_reset(void) { ps->num_proc = 0; ps->num_lwp = 0; ps->num_fd = 0; + ps->num_maps = 0; ps->vmem_size = 0; ps->vmem_rss = 0; ps->vmem_data = 0; @@ -548,6 +571,8 @@ static void ps_tune_instance(oconfig_item_t *ci, procstat_t *ps) { cf_util_get_boolean(c, &ps->report_ctx_switch); else if (strcasecmp(c->key, "CollectFileDescriptor") == 0) cf_util_get_boolean(c, &ps->report_fd_num); + else if (strcasecmp(c->key, "CollectMemoryMaps") == 0) + cf_util_get_boolean(c, &ps->report_maps_num); else { ERROR("processes plugin: Option `%s' not allowed here.", c->key); } @@ -606,6 +631,8 @@ static int ps_config(oconfig_item_t *ci) { cf_util_get_boolean(c, &report_ctx_switch); } else if (strcasecmp(c->key, "CollectFileDescriptor") == 0) { cf_util_get_boolean(c, &report_fd_num); + } else if (strcasecmp(c->key, "CollectMemoryMaps") == 0) { + cf_util_get_boolean(c, &report_maps_num); } else { ERROR("processes plugin: The `%s' configuration option is not " "understood and will be ignored.", @@ -725,7 +752,7 @@ static void ps_submit_proc_list(procstat_t *ps) { plugin_dispatch_values(&vl); if ((ps->io_rchar != -1) && (ps->io_wchar != -1)) { - sstrncpy(vl.type, "ps_disk_octets", sizeof(vl.type)); + sstrncpy(vl.type, "io_octets", sizeof(vl.type)); vl.values[0].derive = ps->io_rchar; vl.values[1].derive = ps->io_wchar; vl.values_len = 2; @@ -733,13 +760,21 @@ static void ps_submit_proc_list(procstat_t *ps) { } if ((ps->io_syscr != -1) && (ps->io_syscw != -1)) { - sstrncpy(vl.type, "ps_disk_ops", sizeof(vl.type)); + sstrncpy(vl.type, "io_ops", sizeof(vl.type)); vl.values[0].derive = ps->io_syscr; vl.values[1].derive = ps->io_syscw; vl.values_len = 2; plugin_dispatch_values(&vl); } + if ((ps->io_diskr != -1) && (ps->io_diskw != -1)) { + sstrncpy(vl.type, "disk_octets", sizeof(vl.type)); + vl.values[0].derive = ps->io_diskr; + vl.values[1].derive = ps->io_diskw; + vl.values_len = 2; + plugin_dispatch_values(&vl); + } + if (ps->num_fd > 0) { sstrncpy(vl.type, "file_handles", sizeof(vl.type)); vl.values[0].gauge = ps->num_fd; @@ -747,6 +782,14 @@ static void ps_submit_proc_list(procstat_t *ps) { plugin_dispatch_values(&vl); } + if (ps->num_maps > 0) { + sstrncpy(vl.type, "file_handles", sizeof(vl.type)); + sstrncpy(vl.type_instance, "mapped", sizeof(vl.type_instance)); + vl.values[0].gauge = ps->num_maps; + vl.values_len = 1; + plugin_dispatch_values(&vl); + } + if ((ps->cswitch_vol != -1) && (ps->cswitch_invol != -1)) { sstrncpy(vl.type, "contextswitch", sizeof(vl.type)); sstrncpy(vl.type_instance, "voluntary", sizeof(vl.type_instance)); @@ -761,19 +804,23 @@ static void ps_submit_proc_list(procstat_t *ps) { plugin_dispatch_values(&vl); } - DEBUG("name = %s; num_proc = %lu; num_lwp = %lu; num_fd = %lu; " - "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; " - "vmem_code = %lu; " - "vmem_minflt_counter = %" PRIi64 "; vmem_majflt_counter = %" PRIi64 "; " - "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; " - "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; " - "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; " - "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";", - ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->vmem_size, - ps->vmem_rss, ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter, - ps->vmem_majflt_counter, ps->cpu_user_counter, ps->cpu_system_counter, - ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->cswitch_vol, - ps->cswitch_invol); + DEBUG( + "name = %s; num_proc = %lu; num_lwp = %lu; num_fd = %lu; num_maps = %lu; " + "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; " + "vmem_code = %lu; " + "vmem_minflt_counter = %" PRIi64 "; vmem_majflt_counter = %" PRIi64 "; " + "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; " + "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; " + "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; " + "io_diskr = %" PRIi64 "; io_diskw = %" PRIi64 "; " + "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";", + ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->num_maps, + ps->vmem_size, ps->vmem_rss, ps->vmem_data, ps->vmem_code, + ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter, + ps->cpu_system_counter, ps->io_rchar, ps->io_wchar, ps->io_syscr, + ps->io_syscw, ps->io_diskr, ps->io_diskw, ps->cswitch_vol, + ps->cswitch_invol); + } /* void ps_submit_proc_list */ #if KERNEL_LINUX || KERNEL_SOLARIS @@ -805,7 +852,7 @@ static int ps_read_tasks_status(process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id); + snprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id); if ((dh = opendir(dirname)) == NULL) { DEBUG("Failed to open directory `%s'", dirname); @@ -820,8 +867,12 @@ static int ps_read_tasks_status(process_entry_t *ps) { tpid = ent->d_name; - ssnprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id, - tpid); + if (snprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id, + tpid) >= sizeof(filename)) { + DEBUG("Filename too long: `%s'", filename); + continue; + } + if ((fh = fopen(filename, "r")) == NULL) { DEBUG("Failed to open file `%s'", filename); continue; @@ -878,7 +929,7 @@ static int ps_read_status(long pid, process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(filename, sizeof(filename), "/proc/%li/status", pid); + snprintf(filename, sizeof(filename), "/proc/%li/status", pid); if ((fh = fopen(filename, "r")) == NULL) return -1; @@ -931,7 +982,7 @@ static int ps_read_io(process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(filename, sizeof(filename), "/proc/%li/io", ps->id); + snprintf(filename, sizeof(filename), "/proc/%li/io", ps->id); if ((fh = fopen(filename, "r")) == NULL) { DEBUG("ps_read_io: Failed to open file `%s'", filename); return -1; @@ -950,6 +1001,10 @@ static int ps_read_io(process_entry_t *ps) { val = &(ps->io_syscr); else if (strncasecmp(buffer, "syscw:", 6) == 0) val = &(ps->io_syscw); + else if (strncasecmp(buffer, "read_bytes:", 11) == 0) + val = &(ps->io_diskr); + else if (strncasecmp(buffer, "write_bytes:", 12) == 0) + val = &(ps->io_diskw); else continue; @@ -974,13 +1029,38 @@ static int ps_read_io(process_entry_t *ps) { return 0; } /* int ps_read_io (...) */ +static int ps_count_maps(pid_t pid) { + FILE *fh; + char buffer[1024]; + char filename[64]; + int count = 0; + + snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); + if ((fh = fopen(filename, "r")) == NULL) { + DEBUG("ps_count_maps: Failed to open file `%s'", filename); + return -1; + } + + while (fgets(buffer, sizeof(buffer), fh) != NULL) { + if (strchr(buffer, '\n')) { + count++; + } + } /* while (fgets) */ + + if (fclose(fh)) { + char errbuf[1024]; + WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf))); + } + return count; +} /* int ps_count_maps (...) */ + static int ps_count_fd(int pid) { char dirname[64]; DIR *dh; struct dirent *ent; int count = 0; - ssnprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid); + snprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid); if ((dh = opendir(dirname)) == NULL) { DEBUG("Failed to open directory `%s'", dirname); @@ -1010,6 +1090,14 @@ static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) { } } + if (ps->report_maps_num) { + int num_maps; + if (entry->has_maps == 0 && (num_maps = ps_count_maps(entry->id)) > 0) { + entry->num_maps = num_maps; + } + entry->has_maps = 1; + } + if (ps->report_fd_num) { int num_fd; if (entry->has_fd == 0 && (num_fd = ps_count_fd(entry->id)) > 0) { @@ -1041,7 +1129,7 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ssize_t status; - ssnprintf(filename, sizeof(filename), "/proc/%li/stat", pid); + snprintf(filename, sizeof(filename), "/proc/%li/stat", pid); status = read_file_contents(filename, buffer, sizeof(buffer) - 1); if (status <= 0) @@ -1145,6 +1233,8 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ps->io_wchar = -1; ps->io_syscr = -1; ps->io_syscw = -1; + ps->io_diskr = -1; + ps->io_diskw = -1; ps->cswitch_vol = -1; ps->cswitch_invol = -1; @@ -1165,7 +1255,7 @@ static char *ps_get_cmdline(long pid, char *name, char *buf, size_t buf_len) { if ((pid < 1) || (NULL == buf) || (buf_len < 2)) return NULL; - ssnprintf(file, sizeof(file), "/proc/%li/cmdline", pid); + snprintf(file, sizeof(file), "/proc/%li/cmdline", pid); errno = 0; fd = open(file, O_RDONLY); @@ -1220,7 +1310,7 @@ static char *ps_get_cmdline(long pid, char *name, char *buf, size_t buf_len) { if (NULL == name) return NULL; - ssnprintf(buf, buf_len, "[%s]", name); + snprintf(buf, buf_len, "[%s]", name); return buf; } @@ -1389,6 +1479,9 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { */ ps->num_fd = 0; + /* Number of memory mappings */ + ps->num_maps = 0; + /* * Calculating input/ouput chars * Formula used is total chars / total blocks => chars/block @@ -1403,6 +1496,8 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ps->io_wchar = myUsage->pr_oublk * chars_per_block; ps->io_syscr = myUsage->pr_sysc; ps->io_syscw = myUsage->pr_sysc; + ps->io_diskr = -1; + ps->io_diskw = -1; /* * TODO: context switch counters for Solaris @@ -1616,10 +1711,15 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* File descriptor count not implemented */ pse.num_fd = 0; + /* Number of memory mappings */ + pse.num_maps = 0; + pse.vmem_minflt_counter = task_events_info.cow_faults; pse.vmem_majflt_counter = task_events_info.faults; @@ -1919,10 +2019,15 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* file descriptor count not implemented */ pse.num_fd = 0; + /* Number of memory mappings */ + pse.num_maps = 0; + /* context switch counters not implemented */ pse.cswitch_vol = -1; pse.cswitch_invol = -1; @@ -2058,10 +2163,15 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* file descriptor count not implemented */ pse.num_fd = 0; + /* Number of memory mappings */ + pse.num_maps = 0; + /* context switch counters not implemented */ pse.cswitch_vol = -1; pse.cswitch_invol = -1; @@ -2221,8 +2331,11 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; pse.num_fd = 0; + pse.num_maps = 0; pse.cswitch_vol = -1; pse.cswitch_invol = -1;