+ submit_derive((int)cpu_num, (int)state, s->conv.last_value.derive);
+ }
+ }
+} /* }}} void cpu_commit_without_aggregation */
+
+/* Aggregates the internal state and dispatches the metrics. */
+static void cpu_commit(void) /* {{{ */
+{
+ gauge_t global_rates[COLLECTD_CPU_STATE_MAX] = {
+ NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
+ };
+
+ if (report_num_cpu)
+ cpu_commit_num_cpu((gauge_t)global_cpu_num);
+
+ if (report_by_state && report_by_cpu && !report_percent) {
+ cpu_commit_without_aggregation();
+ return;
+ }
+
+ aggregate(global_rates);
+
+ if (!report_by_cpu) {
+ cpu_commit_one(-1, global_rates);
+ return;
+ }
+
+ for (size_t cpu_num = 0; cpu_num < global_cpu_num; cpu_num++) {
+ cpu_state_t *this_cpu_states = get_cpu_state(cpu_num, 0);
+ gauge_t local_rates[COLLECTD_CPU_STATE_MAX] = {NAN, NAN, NAN, NAN, NAN,
+ NAN, NAN, NAN, NAN, NAN};
+
+ for (size_t state = 0; state < COLLECTD_CPU_STATE_MAX; state++)
+ if (this_cpu_states[state].has_value)
+ local_rates[state] = this_cpu_states[state].rate;
+
+ cpu_commit_one((int)cpu_num, local_rates);
+ }
+} /* }}} void cpu_commit */
+
+/* Adds a derive value to the internal state. This should be used by each read
+ * function for each state. At the end of the iteration, the read function
+ * should call cpu_commit(). */
+static int cpu_stage(size_t cpu_num, size_t state, derive_t d,
+ cdtime_t now) /* {{{ */
+{
+ int status;
+ cpu_state_t *s;
+ gauge_t rate = NAN;
+ value_t val = {.derive = d};
+
+ if (state >= COLLECTD_CPU_STATE_ACTIVE)
+ return (EINVAL);
+
+ status = cpu_states_alloc(cpu_num);
+ if (status != 0)
+ return (status);
+
+ if (global_cpu_num <= cpu_num)
+ global_cpu_num = cpu_num + 1;
+
+ s = get_cpu_state(cpu_num, state);
+
+ status = value_to_rate(&rate, val, DS_TYPE_DERIVE, now, &s->conv);
+ if (status != 0)
+ return (status);
+
+ s->rate = rate;
+ s->has_value = 1;
+ return (0);
+} /* }}} int cpu_stage */
+
+static int cpu_read(void) {
+ cdtime_t now = cdtime();
+
+#if PROCESSOR_CPU_LOAD_INFO /* {{{ */
+ kern_return_t status;
+
+ processor_cpu_load_info_data_t cpu_info;
+ mach_msg_type_number_t cpu_info_len;
+
+ host_t cpu_host;
+
+ for (mach_msg_type_number_t cpu = 0; cpu < cpu_list_len; cpu++) {
+ cpu_host = 0;
+ cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
+
+ status = processor_info(cpu_list[cpu], PROCESSOR_CPU_LOAD_INFO, &cpu_host,
+ (processor_info_t)&cpu_info, &cpu_info_len);
+ if (status != KERN_SUCCESS) {
+ ERROR("cpu plugin: processor_info (PROCESSOR_CPU_LOAD_INFO) failed: %s",
+ mach_error_string(status));
+ continue;
+ }
+
+ if (cpu_info_len < CPU_STATE_MAX) {
+ ERROR("cpu plugin: processor_info returned only %i elements..",
+ cpu_info_len);
+ continue;
+ }
+
+ cpu_stage(cpu, COLLECTD_CPU_STATE_USER,
+ (derive_t)cpu_info.cpu_ticks[CPU_STATE_USER], now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_NICE,
+ (derive_t)cpu_info.cpu_ticks[CPU_STATE_NICE], now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_SYSTEM,
+ (derive_t)cpu_info.cpu_ticks[CPU_STATE_SYSTEM], now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_IDLE,
+ (derive_t)cpu_info.cpu_ticks[CPU_STATE_IDLE], now);
+ }
+/* }}} #endif PROCESSOR_CPU_LOAD_INFO */
+
+#elif defined(KERNEL_LINUX) /* {{{ */
+ int cpu;
+ FILE *fh;
+ char buf[1024];
+
+ char *fields[9];
+ int numfields;
+
+ if ((fh = fopen("/proc/stat", "r")) == NULL) {
+ char errbuf[1024];
+ ERROR("cpu plugin: fopen (/proc/stat) failed: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ return (-1);
+ }
+
+ while (fgets(buf, 1024, fh) != NULL) {
+ if (strncmp(buf, "cpu", 3))
+ continue;
+ if ((buf[3] < '0') || (buf[3] > '9'))
+ continue;
+
+ numfields = strsplit(buf, fields, 9);
+ if (numfields < 5)
+ continue;
+
+ cpu = atoi(fields[0] + 3);
+
+ cpu_stage(cpu, COLLECTD_CPU_STATE_USER, (derive_t)atoll(fields[1]), now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)atoll(fields[2]), now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_SYSTEM, (derive_t)atoll(fields[3]), now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_IDLE, (derive_t)atoll(fields[4]), now);
+
+ if (numfields >= 8) {
+ cpu_stage(cpu, COLLECTD_CPU_STATE_WAIT, (derive_t)atoll(fields[5]), now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_INTERRUPT, (derive_t)atoll(fields[6]),
+ now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_SOFTIRQ, (derive_t)atoll(fields[7]),
+ now);
+
+ if (numfields >= 9)
+ cpu_stage(cpu, COLLECTD_CPU_STATE_STEAL, (derive_t)atoll(fields[8]),
+ now);
+ }
+ }
+ fclose(fh);
+/* }}} #endif defined(KERNEL_LINUX) */
+
+#elif defined(HAVE_LIBKSTAT) /* {{{ */
+ static cpu_stat_t cs;
+
+ if (kc == NULL)
+ return (-1);
+
+ for (int cpu = 0; cpu < numcpu; cpu++) {
+ if (kstat_read(kc, ksp[cpu], &cs) == -1)
+ continue; /* error message? */
+
+ cpu_stage(ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_IDLE,
+ (derive_t)cs.cpu_sysinfo.cpu[CPU_IDLE], now);
+ cpu_stage(ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_USER,
+ (derive_t)cs.cpu_sysinfo.cpu[CPU_USER], now);
+ cpu_stage(ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_SYSTEM,
+ (derive_t)cs.cpu_sysinfo.cpu[CPU_KERNEL], now);
+ cpu_stage(ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_WAIT,
+ (derive_t)cs.cpu_sysinfo.cpu[CPU_WAIT], now);
+ }
+/* }}} #endif defined(HAVE_LIBKSTAT) */
+
+#elif CAN_USE_SYSCTL /* {{{ */
+ uint64_t cpuinfo[numcpu][CPUSTATES];
+ size_t cpuinfo_size;
+ int status;
+
+ if (numcpu < 1) {
+ ERROR("cpu plugin: Could not determine number of "
+ "installed CPUs using sysctl(3).");
+ return (-1);
+ }
+
+ memset(cpuinfo, 0, sizeof(cpuinfo));