typedef struct process_entry_s {
unsigned long id;
char name[PROCSTAT_NAME_LEN];
+ // The time the process started after system boot.
+ // Value is in jiffies.
+ unsigned long long starttime;
unsigned long num_proc;
unsigned long num_lwp;
typedef struct procstat_entry_s {
unsigned long id;
unsigned char age;
+ // The time the process started after system boot.
+ // Value is in jiffies.
+ unsigned long long starttime;
derive_t vmem_minflt_counter;
derive_t vmem_majflt_counter;
static bool report_fd_num;
static bool report_maps_num;
static bool report_delay;
+static bool report_sys_ctxt_switch;
#if HAVE_THREAD_INFO
static mach_port_t port_host_self;
if ((pse->id == entry->id) || (pse->next == NULL))
break;
- if ((pse == NULL) || (pse->id != entry->id)) {
+ if ((pse == NULL) || (pse->id != entry->id) ||
+ (pse->starttime != entry->starttime)) {
+ if (pse != NULL && pse->id == entry->id) {
+ WARNING("pid %lu reused between two reads, ignoring existing "
+ "procstat_entry for %s",
+ pse->id, name);
+ }
procstat_entry_t *new;
new = calloc(1, sizeof(*new));
if (new == NULL)
return;
new->id = entry->id;
+ new->starttime = entry->starttime;
if (pse == NULL)
ps->instances = new;
WARNING("processes plugin: The plugin has been compiled without support "
"for the \"CollectDelayAccounting\" option.");
#endif
+ } else if (strcasecmp(c->key, "CollectSystemContextSwitch") == 0) {
+ cf_util_get_boolean(c, &report_sys_ctxt_switch);
} else {
ERROR("processes plugin: The `%s' configuration option is not "
"understood and will be ignored.",
} /* void ps_submit_proc_list */
#if KERNEL_LINUX || KERNEL_SOLARIS
-static void ps_submit_fork_rate(derive_t value) {
+static void ps_submit_global_stat(const char *type_name, derive_t value) {
value_list_t vl = VALUE_LIST_INIT;
vl.values = &(value_t){.derive = value};
vl.values_len = 1;
sstrncpy(vl.plugin, "processes", sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, "", sizeof(vl.plugin_instance));
- sstrncpy(vl.type, "fork_rate", sizeof(vl.type));
+ sstrncpy(vl.type, type_name, sizeof(vl.type));
sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
plugin_dispatch_values(&vl);
ps->cswitch_vol = -1;
ps->cswitch_invol = -1;
+ ps->starttime = strtoull(fields[19], NULL, 10);
/* success */
return 0;
} /* int ps_read_process (...) */
-static int procs_running(void) {
- char buffer[65536] = {};
+static int procs_running(const char *buffer) {
char id[] = "procs_running "; /* white space terminated */
char *running;
char *endptr = NULL;
long result = 0L;
- ssize_t status;
-
- status = read_file_contents("/proc/stat", buffer, sizeof(buffer) - 1);
- if (status <= 0) {
- return -1;
- }
-
/* the data contains :
* the literal string 'procs_running',
* a whitespace
*/
running = strstr(buffer, id);
if (!running) {
- WARNING("procs_running not found");
+ WARNING("'procs_running ' not found in /proc/stat");
return -1;
}
running += strlen(id);
return buf;
} /* char *ps_get_cmdline (...) */
-static int read_fork_rate(void) {
- FILE *proc_stat;
- char buffer[1024];
+static int read_fork_rate(const char *buffer) {
value_t value;
- bool value_valid = 0;
+ char id[] = "processes ";
+ char *processes;
- proc_stat = fopen("/proc/stat", "r");
- if (proc_stat == NULL) {
- ERROR("processes plugin: fopen (/proc/stat) failed: %s", STRERRNO);
+ int status;
+ char *fields[2];
+ int fields_num;
+ const int expected = STATIC_ARRAY_SIZE(fields);
+
+ processes = strstr(buffer, id);
+ if (!processes) {
+ WARNING("'processes ' not found in /proc/stat");
return -1;
}
- while (fgets(buffer, sizeof(buffer), proc_stat) != NULL) {
- int status;
- char *fields[3];
- int fields_num;
+ fields_num = strsplit(processes, fields, expected);
+ if (fields_num != expected)
+ return -1;
- fields_num = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
- if (fields_num != 2)
- continue;
+ status = parse_value(fields[1], &value, DS_TYPE_DERIVE);
+ if (status != 0)
+ return -1;
- if (strcmp("processes", fields[0]) != 0)
- continue;
+ ps_submit_global_stat("fork_rate", value.derive);
+ return 0;
+}
- status = parse_value(fields[1], &value, DS_TYPE_DERIVE);
- if (status == 0)
- value_valid = 1;
+static int read_sys_ctxt_switch(const char *buffer) {
+ value_t value;
+ char id[] = "ctxt ";
+ char *ctxt;
+
+ int status;
+ char *fields[2];
+ int fields_num;
+ const int expected = STATIC_ARRAY_SIZE(fields);
- break;
+ ctxt = strstr(buffer, id);
+ if (!ctxt) {
+ WARNING("'ctxt ' not found in /proc/stat");
+ return -1;
}
- fclose(proc_stat);
- if (!value_valid)
+ fields_num = strsplit(ctxt, fields, expected);
+ if (fields_num != expected)
+ return -1;
+
+ status = parse_value(fields[1], &value, DS_TYPE_DERIVE);
+ if (status != 0)
return -1;
- ps_submit_fork_rate(value.derive);
+ ps_submit_global_stat("contextswitch", value.derive);
return 0;
}
#endif /*KERNEL_LINUX */
snprintf(f_psinfo, sizeof(f_psinfo), "/proc/%li/psinfo", pid);
snprintf(f_usage, sizeof(f_usage), "/proc/%li/usage", pid);
- buffer = calloc(1, sizeof(pstatus_t));
+ buffer = scalloc(1, sizeof(pstatus_t));
read_file_contents(filename, buffer, sizeof(pstatus_t));
myStatus = (pstatus_t *)buffer;
- buffer = calloc(1, sizeof(psinfo_t));
+ buffer = scalloc(1, sizeof(psinfo_t));
read_file_contents(f_psinfo, buffer, sizeof(psinfo_t));
myInfo = (psinfo_t *)buffer;
- buffer = calloc(1, sizeof(prusage_t));
+ buffer = scalloc(1, sizeof(prusage_t));
read_file_contents(f_usage, buffer, sizeof(prusage_t));
myUsage = (prusage_t *)buffer;
}
}
- ps_submit_fork_rate(result);
+ ps_submit_global_stat("fork_rate", result);
return 0;
}
#endif /* KERNEL_SOLARIS */
DIR *proc;
long pid;
+ char buffer[65536] = {};
char cmdline[CMDLINE_BUFFER_SIZE];
int status;
}
switch (state) {
- case 'R':
- running++;
- break;
case 'S':
sleeping++;
break;
closedir(proc);
+ if (read_file_contents("/proc/stat", buffer, sizeof(buffer) - 1) <= 0) {
+ ERROR("Cannot read `/proc/stat`");
+ return -1;
+ }
/* get procs_running from /proc/stat
* scanning /proc/stat AND computing other process stats takes too much time.
* Consequently, the number of running processes based on the occurences
* stat(s).
* The 'procs_running' number in /proc/stat on the other hand is more
* accurate, and can be retrieved in a single 'read' call. */
- running = procs_running();
+ running = procs_running(buffer);
ps_submit_state("running", running);
ps_submit_state("sleeping", sleeping);
for (procstat_t *ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
ps_submit_proc_list(ps_ptr);
- read_fork_rate();
- /* #endif KERNEL_LINUX */
+ read_fork_rate(buffer);
+ if (report_sys_ctxt_switch)
+ read_sys_ctxt_switch(buffer);
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
int running = 0;