diff --git a/src/turbostat.c b/src/turbostat.c
index 2d124fdc972df969b30ca5c313e6f3f102c7e572..fc1b5dccc0dd3c4b2c2c848b1de1f9a57c95c156 100644 (file)
--- a/src/turbostat.c
+++ b/src/turbostat.c
#include "utils_time.h"
#include <asm/msr-index.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <err.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <string.h>
-#include <ctype.h>
-#include <sched.h>
#include <cpuid.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif /* HAVE_SYS_CAPABILITY_H */
#define PLUGIN_NAME "turbostat"
* Currently supported C-states (by this plugin): 3, 6, 7
*/
static unsigned int do_core_cstate;
+static unsigned int config_core_cstate;
+static _Bool apply_config_core_cstate;
/*
* Bitmask of the list of pacages C states supported by the processor.
* Currently supported C-states (by this plugin): 2, 3, 6, 7, 8, 9, 10
*/
static unsigned int do_pkg_cstate;
+static unsigned int config_pkg_cstate;
+static _Bool apply_config_pkg_cstate;
+
+/*
+ * Boolean indicating if the processor supports 'I/O System-Management Interrupt counter'
+ */
+static _Bool do_smi;
+static _Bool config_smi;
+static _Bool apply_config_smi;
/*
* Boolean indicating if the processor supports 'Digital temperature sensor'
* - Temperatures above the tcc_activation_temp are not recorded
*/
static _Bool do_dts;
+static _Bool config_dts;
+static _Bool apply_config_dts;
/*
* Boolean indicating if the processor supports 'Package thermal management'
* - Temperatures above the tcc_activation_temp are not recorded
*/
static _Bool do_ptm;
+static _Bool config_ptm;
+static _Bool apply_config_ptm;
/*
* Thermal Control Circuit Activation Temperature as configured by the user.
static unsigned int tcc_activation_temp;
static unsigned int do_rapl;
+static unsigned int config_rapl;
+static _Bool apply_config_rapl;
static double rapl_energy_units;
#define RAPL_PKG (1 << 0)
/* 0x610 MSR_PKG_POWER_LIMIT */
/* 0x611 MSR_PKG_ENERGY_STATUS */
-#define RAPL_PKG_PERF_STATUS (1 << 1)
- /* 0x613 MSR_PKG_PERF_STATUS */
-#define RAPL_PKG_POWER_INFO (1 << 2)
- /* 0x614 MSR_PKG_POWER_INFO */
-
-#define RAPL_DRAM (1 << 3)
+#define RAPL_DRAM (1 << 1)
/* 0x618 MSR_DRAM_POWER_LIMIT */
/* 0x619 MSR_DRAM_ENERGY_STATUS */
/* 0x61c MSR_DRAM_POWER_INFO */
-#define RAPL_DRAM_PERF_STATUS (1 << 4)
- /* 0x61b MSR_DRAM_PERF_STATUS */
-
-#define RAPL_CORES (1 << 5)
+#define RAPL_CORES (1 << 2)
/* 0x638 MSR_PP0_POWER_LIMIT */
/* 0x639 MSR_PP0_ENERGY_STATUS */
-#define RAPL_CORE_POLICY (1 << 6)
- /* 0x63a MSR_PP0_POLICY */
-
-#define RAPL_GFX (1 << 7)
+#define RAPL_GFX (1 << 3)
/* 0x640 MSR_PP1_POWER_LIMIT */
/* 0x641 MSR_PP1_ENERGY_STATUS */
/* 0x642 MSR_PP1_POLICY */
unsigned long long pc9;
unsigned long long pc10;
unsigned int package_id;
- unsigned int energy_pkg; /* MSR_PKG_ENERGY_STATUS */
- unsigned int energy_dram; /* MSR_DRAM_ENERGY_STATUS */
- unsigned int energy_cores; /* MSR_PP0_ENERGY_STATUS */
- unsigned int energy_gfx; /* MSR_PP1_ENERGY_STATUS */
- unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */
- unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */
+ uint32_t energy_pkg; /* MSR_PKG_ENERGY_STATUS */
+ uint32_t energy_dram; /* MSR_DRAM_ENERGY_STATUS */
+ uint32_t energy_cores; /* MSR_PP0_ENERGY_STATUS */
+ uint32_t energy_gfx; /* MSR_PP1_ENERGY_STATUS */
unsigned int tcc_activation_temp;
unsigned int pkg_temp_c;
} *package_delta, *package_even, *package_odd;
#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
struct cpu_topology {
- int package_id;
- int core_id;
+ unsigned int package_id;
+ unsigned int core_id;
_Bool first_core_in_package;
_Bool first_thread_in_core;
};
static struct topology {
- int max_cpu_id;
- int num_packages;
- int num_cores;
- int num_threads;
+ unsigned int max_cpu_id;
+ unsigned int num_packages;
+ unsigned int num_cores;
+ unsigned int num_threads;
struct cpu_topology *cpus;
} topology;
static const char *config_keys[] =
{
+ "CoreCstates",
+ "PackageCstates",
+ "SystemManagementInterrupt",
+ "DigitalTemperatureSensor",
+ "PackageThermalManagement",
"TCCActivationTemp",
+ "RunningAveragePowerLimit",
};
static const int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
* Can change the scheduling affinity of the current process if multiple_read is 1
*/
static int __attribute__((warn_unused_result))
-open_msr(int cpu, _Bool multiple_read)
+open_msr(unsigned int cpu, _Bool multiple_read)
{
char pathname[32];
int fd;
CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) {
- ERROR("Turbostat plugin: Could not migrate to CPU %d", cpu);
+ ERROR("turbostat plugin: Could not migrate to CPU %d", cpu);
return -1;
}
}
ssnprintf(pathname, sizeof(pathname), "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY);
if (fd < 0) {
- ERROR("Turbostat plugin: failed to open %s", pathname);
+ ERROR("turbostat plugin: failed to open %s", pathname);
return -1;
}
return fd;
retval = pread(fd, msr, sizeof *msr, offset);
if (retval != sizeof *msr) {
- ERROR("Turbostat plugin: MSR offset 0x%llx read failed",
+ ERROR("turbostat plugin: MSR offset 0x%llx read failed",
(unsigned long long)offset);
return -1;
}
* Open a MSR device for reading, read the value asked for and close it.
* This call will not affect the scheduling affinity of this thread.
*/
-static int __attribute__((warn_unused_result))
-get_msr(int cpu, off_t offset, unsigned long long *msr)
+static ssize_t __attribute__((warn_unused_result))
+get_msr(unsigned int cpu, off_t offset, unsigned long long *msr)
{
ssize_t retval;
int fd;
static int __attribute__((warn_unused_result))
get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
{
- int cpu = t->cpu_id;
+ unsigned int cpu = t->cpu_id;
unsigned long long msr;
int msr_fd;
int retval = 0;
#define READ_MSR(msr, dst) \
do { \
if (read_msr(msr_fd, msr, dst)) { \
- ERROR("Turbostat plugin: Unable to read " #msr); \
+ ERROR("turbostat plugin: Unable to read " #msr); \
retval = -1; \
goto out; \
} \
READ_MSR(MSR_IA32_APERF, &t->aperf);
READ_MSR(MSR_IA32_MPERF, &t->mperf);
- READ_MSR(MSR_SMI_COUNT, &msr);
- t->smi_count = msr & 0xFFFFFFFF;
+ if (do_smi) {
+ READ_MSR(MSR_SMI_COUNT, &msr);
+ t->smi_count = msr & 0xFFFFFFFF;
+ }
/* collect core counters only for 1st thread in core */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) {
READ_MSR(MSR_PP1_ENERGY_STATUS, &msr);
p->energy_gfx = msr & 0xFFFFFFFF;
}
- if (do_rapl & RAPL_PKG_PERF_STATUS) {
- READ_MSR(MSR_PKG_PERF_STATUS, &msr);
- p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
- }
- if (do_rapl & RAPL_DRAM_PERF_STATUS) {
- READ_MSR(MSR_DRAM_PERF_STATUS, &msr);
- p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
- }
if (do_ptm) {
READ_MSR(MSR_IA32_PACKAGE_THERM_STATUS, &msr);
p->pkg_temp_c = p->tcc_activation_temp - ((msr >> 16) & 0x7F);
* Evaluating the changes (1 CPU) *
**********************************/
-/*
- * Do delta = new - old on 32bits cyclique intergers
- */
-#define DELTA_WRAP32(delta, new, old) \
- if (new > old) { \
- delta = new - old; \
- } else { \
- delta = 0x100000000 + new - old; \
- }
-
/*
* Extract the evolution old->new in delta at a package level
* (some are not new-delta, e.g. temperature)
@@ -450,12 +432,10 @@ delta_package(struct pkg_data *delta, const struct pkg_data *new, const struct p
delta->pc10 = new->pc10 - old->pc10;
delta->pkg_temp_c = new->pkg_temp_c;
- DELTA_WRAP32(delta->energy_pkg, new->energy_pkg, old->energy_pkg);
- DELTA_WRAP32(delta->energy_cores, new->energy_cores, old->energy_cores);
- DELTA_WRAP32(delta->energy_gfx, new->energy_gfx, old->energy_gfx);
- DELTA_WRAP32(delta->energy_dram, new->energy_dram, old->energy_dram);
- DELTA_WRAP32(delta->rapl_pkg_perf_status, new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
- DELTA_WRAP32(delta->rapl_dram_perf_status, new->rapl_dram_perf_status, old->rapl_dram_perf_status);
+ delta->energy_pkg = new->energy_pkg - old->energy_pkg;
+ delta->energy_cores = new->energy_cores - old->energy_cores;
+ delta->energy_gfx = new->energy_gfx - old->energy_gfx;
+ delta->energy_dram = new->energy_dram - old->energy_dram;
}
/*
@@ -477,13 +457,13 @@ delta_core(struct core_data *delta, const struct core_data *new, const struct co
*/
static inline int __attribute__((warn_unused_result))
delta_thread(struct thread_data *delta, const struct thread_data *new, const struct thread_data *old,
- const struct core_data *core_delta)
+ const struct core_data *cdelta)
{
delta->tsc = new->tsc - old->tsc;
/* check for TSC < 1 Mcycles over interval */
if (delta->tsc < (1000 * 1000)) {
- WARNING("Turbostat plugin: Insanely slow TSC rate, TSC stops "
+ WARNING("turbostat plugin: Insanely slow TSC rate, TSC stops "
"in idle? You can disable all c-states by booting with"
" 'idle=poll' or just the deep ones with"
" 'processor.max_cstate=1'");
@@ -497,7 +477,7 @@ delta_thread(struct thread_data *delta, const struct thread_data *new, const str
delta->mperf = new->mperf - old->mperf;
} else {
if (!aperf_mperf_unstable) {
- WARNING("Turbostat plugin: APERF or MPERF went "
+ WARNING("turbostat plugin: APERF or MPERF went "
"backwards. Frequency results do not cover "
"the entire interval. Fix this by running "
"Linux-2.6.30 or later.");
@@ -511,20 +491,21 @@ delta_thread(struct thread_data *delta, const struct thread_data *new, const str
* it is possible for mperf's non-halted cycles + idle states
* to exceed TSC's all cycles: show c1 = 0% in that case.
*/
- if ((delta->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > delta->tsc)
+ if ((delta->mperf + cdelta->c3 + cdelta->c6 + cdelta->c7) > delta->tsc)
delta->c1 = 0;
else {
/* normal case, derive c1 */
- delta->c1 = delta->tsc - delta->mperf - core_delta->c3
- - core_delta->c6 - core_delta->c7;
+ delta->c1 = delta->tsc - delta->mperf - cdelta->c3
+ - cdelta->c6 - cdelta->c7;
}
if (delta->mperf == 0) {
- WARNING("Turbostat plugin: cpu%d MPERF 0!", old->cpu_id);
+ WARNING("turbostat plugin: cpu%d MPERF 0!", old->cpu_id);
delta->mperf = 1; /* divide by 0 protection */
}
- delta->smi_count = new->smi_count - old->smi_count;
+ if (do_smi)
+ delta->smi_count = new->smi_count - old->smi_count;
return 0;
}
@@ -579,12 +560,17 @@ submit_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
if (!aperf_mperf_unstable)
turbostat_submit(name, "percent", "c1", 100.0 * t->c1/t->tsc);
- /* GHz */
+ turbostat_submit(name, "frequency", "average", 1.0 / 1000000 * t->aperf / interval_float);
+
if ((!aperf_mperf_unstable) || (!(t->aperf > t->tsc || t->mperf > t->tsc)))
- turbostat_submit(NULL, "frequency", name, 1.0 * t->tsc / 1000000000 * t->aperf / t->mperf / interval_float);
+ turbostat_submit(name, "frequency", "busy", 1.0 * t->tsc / 1000000 * t->aperf / t->mperf / interval_float);
+
+ /* Sanity check (should stay stable) */
+ turbostat_submit(name, "gauge", "TSC", 1.0 * t->tsc / 1000000 / interval_float);
/* SMI */
- turbostat_submit(NULL, "current", name, t->smi_count);
+ if (do_smi)
+ turbostat_submit(name, "count", NULL, t->smi_count);
/* submit per-core data only for 1st thread in core */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
turbostat_submit(name, "percent", "c7", 100.0 * c->c7/t->tsc);
if (do_dts)
- turbostat_submit(NULL, "temperature", name, c->core_temp_c);
+ turbostat_submit(name, "temperature", NULL, c->core_temp_c);
/* submit per-package data only for 1st core in package */
if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
ssnprintf(name, sizeof(name), "pkg%02d", p->package_id);
if (do_ptm)
- turbostat_submit(NULL, "temperature", name, p->pkg_temp_c);
+ turbostat_submit(name, "temperature", NULL, p->pkg_temp_c);
if (do_pkg_cstate & (1 << 2))
turbostat_submit(name, "percent", "pc2", 100.0 * p->pc2/t->tsc);
@@ -628,13 +614,13 @@ submit_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
if (do_rapl) {
if (do_rapl & RAPL_PKG)
- turbostat_submit(name, "power", "Pkg_W", p->energy_pkg * rapl_energy_units / interval_float);
+ turbostat_submit(name, "power", "pkg", p->energy_pkg * rapl_energy_units / interval_float);
if (do_rapl & RAPL_CORES)
- turbostat_submit(name, "power", "Cor_W", p->energy_cores * rapl_energy_units / interval_float);
+ turbostat_submit(name, "power", "cores", p->energy_cores * rapl_energy_units / interval_float);
if (do_rapl & RAPL_GFX)
- turbostat_submit(name, "power", "GFX_W", p->energy_gfx * rapl_energy_units / interval_float);
+ turbostat_submit(name, "power", "GFX", p->energy_gfx * rapl_energy_units / interval_float);
if (do_rapl & RAPL_DRAM)
- turbostat_submit(name, "power", "RAM_W", p->energy_dram * rapl_energy_units / interval_float);
+ turbostat_submit(name, "power", "DRAM", p->energy_dram * rapl_energy_units / interval_float);
}
done:
return 0;
* Check if a given cpu id is in our compiled list of existing CPUs
*/
static int
-cpu_is_not_present(int cpu)
+cpu_is_not_present(unsigned int cpu)
{
return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
}
for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
{
- int retval, pkg_no, core_no, thread_no;
+ int retval;
+ unsigned int pkg_no, core_no, thread_no;
for (pkg_no = 0; pkg_no < topology.num_packages; ++pkg_no) {
for (core_no = 0; core_no < topology.num_cores; ++core_no) {
for_all_cpus_delta(const struct thread_data *thread_new_base, const struct core_data *core_new_base, const struct pkg_data *pkg_new_base,
const struct thread_data *thread_old_base, const struct core_data *core_old_base, const struct pkg_data *pkg_old_base)
{
- int retval, pkg_no, core_no, thread_no;
+ int retval;
+ unsigned int pkg_no, core_no, thread_no;
for (pkg_no = 0; pkg_no < topology.num_packages; ++pkg_no) {
for (core_no = 0; core_no < topology.num_cores; ++core_no) {
@@ -806,7 +794,7 @@ set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_da
guess:
p->tcc_activation_temp = TJMAX_DEFAULT;
- WARNING("Turbostat plugin: cpu%d: Guessing tjMax %d C,"
+ WARNING("turbostat plugin: cpu%d: Guessing tjMax %d C,"
" Please use TCCActivationTemp to specify it.",
t->cpu_id, p->tcc_activation_temp);
* Identify the functionality of the CPU
*/
static int __attribute__((warn_unused_result))
-probe_cpu()
+probe_cpu(void)
{
unsigned int eax, ebx, ecx, edx, max_level;
unsigned int fms, family, model;
max_level = ebx = ecx = edx = 0;
__get_cpuid(0, &max_level, &ebx, &ecx, &edx);
if (ebx != 0x756e6547 && edx != 0x49656e69 && ecx != 0x6c65746e) {
- ERROR("Turbostat plugin: Unsupported CPU (not Intel)");
+ ERROR("turbostat plugin: Unsupported CPU (not Intel)");
return -1;
}
if (family == 6 || family == 0xf)
model += ((fms >> 16) & 0xf) << 4;
if (!(edx & (1 << 5))) {
- ERROR("Turbostat plugin: Unsupported CPU (no MSR support)");
- return -1;
- }
-
- /*
- * CPUID(0x80000000):
- * - EAX: Maximum Input Value for Extended Function CPUID Information
- *
- * This allows us to verify if the CPUID(0x80000007) can be called
- *
- * This check is valid for both Intel and AMD.
- */
- max_level = ebx = ecx = edx = 0;
- __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx);
- if (max_level < 0x80000007) {
- ERROR("Turbostat plugin: Unsupported CPU (no invariant TSC, "
- " Maximum Extended Function: 0x%x)", max_level);
- return -1;
- }
-
- /*
- * CPUID(0x80000007):
- * - EDX:
- * + 8: Invariant TSC available if set
- *
- * This check is valid for both Intel and AMD
- */
- eax = ebx = ecx = edx = 0;
- __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
- if (!(edx & (1 << 8))) {
- ERROR("Turbostat plugin: Unsupported CPU (No invariant TSC)");
+ ERROR("turbostat plugin: Unsupported CPU (no MSR support)");
return -1;
}
do_dts = eax & (1 << 0);
do_ptm = eax & (1 << 6);
if (!(ecx & (1 << 0))) {
- ERROR("Turbostat plugin: Unsupported CPU (No APERF)");
+ ERROR("turbostat plugin: Unsupported CPU (No APERF)");
return -1;
}
switch (model) {
/* Atom (partial) */
case 0x27:
+ do_smi = 0;
do_core_cstate = 0;
do_pkg_cstate = (1 << 2) | (1 << 4) | (1 << 6);
break;
/* Silvermont */
case 0x37: /* BYT */
- case 0x4A:
case 0x4D: /* AVN */
- case 0x5A:
- case 0x5D:
+ do_smi = 1;
do_core_cstate = (1 << 1) | (1 << 6);
do_pkg_cstate = (1 << 6);
break;
case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
case 0x2E: /* Nehalem-EX Xeon - Beckton */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6);
do_pkg_cstate = (1 << 3) | (1 << 6) | (1 << 7);
break;
case 0x25: /* Westmere Client - Clarkdale, Arrandale */
case 0x2C: /* Westmere EP - Gulftown */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6);
do_pkg_cstate = (1 << 3) | (1 << 6) | (1 << 7);
break;
/* Sandy Bridge */
case 0x2A: /* SNB */
case 0x2D: /* SNB Xeon */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7);
break;
/* Ivy Bridge */
case 0x3A: /* IVB */
case 0x3E: /* IVB Xeon */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7);
break;
case 0x3C: /* HSW */
case 0x3F: /* HSW */
case 0x46: /* HSW */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7);
break;
case 0x45: /* HSW */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10);
break;
/* Broadwel */
case 0x4F: /* BDW */
case 0x56: /* BDX-DE */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7);
break;
case 0x3D: /* BDW */
+ do_smi = 1;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10);
break;
default:
- ERROR("Turbostat plugin: Unsupported CPU (family: %#x,"
- " model: %#x)", family, model);
+ do_smi = 0;
+ do_core_cstate = 0;
+ do_pkg_cstate = 0;
+ break;
}
switch (model) {
- case 0x2A:
- case 0x3A:
- case 0x3C:
- case 0x45:
- case 0x46:
- do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_PKG_POWER_INFO | RAPL_GFX;
+ case 0x2A: /* SNB */
+ case 0x3A: /* IVB */
+ case 0x3C: /* HSW */
+ case 0x45: /* HSW */
+ case 0x46: /* HSW */
+ case 0x3D: /* BDW */
+ do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
break;
- case 0x3F:
- do_rapl = RAPL_PKG | RAPL_PKG_POWER_INFO | RAPL_PKG_PERF_STATUS | RAPL_DRAM | RAPL_DRAM_PERF_STATUS;
+ case 0x3F: /* HSX */
+ case 0x4F: /* BDX */
+ case 0x56: /* BDX-DE */
+ do_rapl = RAPL_PKG | RAPL_DRAM ;
break;
- case 0x2D:
- case 0x3E:
- do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_PKG_POWER_INFO | RAPL_PKG_PERF_STATUS | RAPL_DRAM | RAPL_DRAM_PERF_STATUS;
+ case 0x2D: /* SNB Xeon */
+ case 0x3E: /* IVB Xeon */
+ do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM;
break;
- case 0x37:
- case 0x4D:
+ case 0x37: /* BYT */
+ case 0x4D: /* AVN */
do_rapl = RAPL_PKG | RAPL_CORES;
break;
default:
do_rapl = 0;
}
} else {
- ERROR("Turbostat plugin: Unsupported CPU (family: %#x, "
+ ERROR("turbostat plugin: Unsupported CPU (family: %#x, "
"model: %#x)", family, model);
return -1;
}
+ /* Override detected values with configuration */
+ if (apply_config_core_cstate)
+ do_core_cstate = config_core_cstate;
+ if (apply_config_pkg_cstate)
+ do_pkg_cstate = config_pkg_cstate;
+ if (apply_config_smi)
+ do_smi = config_smi;
+ if (apply_config_dts)
+ do_dts = config_dts;
+ if (apply_config_ptm)
+ do_ptm = config_ptm;
+ if (apply_config_rapl)
+ do_rapl = config_rapl;
+
if (do_rapl) {
unsigned long long msr;
if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr))
len = vsnprintf(path, sizeof(path), fmt, args);
va_end(args);
if (len < 0 || len >= PATH_MAX) {
- ERROR("Turbostat plugin: path truncated: '%s'", path);
+ ERROR("turbostat plugin: path truncated: '%s'", path);
return -1;
}
filep = fopen(path, "r");
if (!filep) {
- ERROR("Turbostat plugin: Failed to open '%s'", path);
+ ERROR("turbostat plugin: Failed to open '%s'", path);
return -1;
}
if (fscanf(filep, "%d", &value) != 1) {
- ERROR("Turbostat plugin: Failed to parse number from '%s'", path);
+ ERROR("turbostat plugin: Failed to parse number from '%s'", path);
+ fclose(filep);
return -1;
}
fclose(filep);
}
static int
-get_threads_on_core(int cpu)
+get_threads_on_core(unsigned int cpu)
{
char path[80];
FILE *filep;
ssnprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
filep = fopen(path, "r");
if (!filep) {
- ERROR("Turbostat plugin: Failed to open '%s'", path);
+ ERROR("turbostat plugin: Failed to open '%s'", path);
return -1;
}
/*
* return max_cpu number
*/
static int __attribute__((warn_unused_result))
-for_all_proc_cpus(int (func)(int))
+for_all_proc_cpus(int (func)(unsigned int))
{
FILE *fp;
- int cpu_num;
+ unsigned int cpu_num;
int retval;
fp = fopen("/proc/stat", "r");
if (!fp) {
- ERROR("Turbostat plugin: Failed to open /proc/stat");
+ ERROR("turbostat plugin: Failed to open /proc/stat");
return -1;
}
retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
if (retval != 0) {
- ERROR("Turbostat plugin: Failed to parse /proc/stat");
+ ERROR("turbostat plugin: Failed to parse /proc/stat");
fclose(fp);
return -1;
}
* Update the stored topology.max_cpu_id
*/
static int
-update_max_cpu_id(int cpu)
+update_max_cpu_id(unsigned int cpu)
{
if (topology.max_cpu_id < cpu)
topology.max_cpu_id = cpu;
}
static int
-mark_cpu_present(int cpu)
+mark_cpu_present(unsigned int cpu)
{
CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
return 0;
allocate_cpu_set(cpu_set_t ** set, size_t * size) {
*set = CPU_ALLOC(topology.max_cpu_id + 1);
if (*set == NULL) {
- ERROR("Turbostat plugin: Unable to allocate CPU state");
+ ERROR("turbostat plugin: Unable to allocate CPU state");
return -1;
}
*size = CPU_ALLOC_SIZE(topology.max_cpu_id + 1);
* Build a local representation of the cpu distribution
*/
static int __attribute__((warn_unused_result))
-topology_probe()
+topology_probe(void)
{
- int i;
+ unsigned int i;
int ret;
- int max_package_id, max_core_id, max_thread_id;
- max_package_id = max_core_id = max_thread_id = 0;
+ unsigned int max_package_id, max_core_id, max_threads;
+ max_package_id = max_core_id = max_threads = 0;
/* Clean topology */
free(topology.cpus);
topology.cpus = calloc(1, (topology.max_cpu_id + 1) * sizeof(struct cpu_topology));
if (topology.cpus == NULL) {
- ERROR("Turbostat plugin: Unable to allocate memory for CPU topology");
+ ERROR("turbostat plugin: Unable to allocate memory for CPU topology");
return -1;
}
* find max_core_id, max_package_id
*/
for (i = 0; i <= topology.max_cpu_id; ++i) {
- int num_threads;
+ unsigned int num_threads;
struct cpu_topology *cpu = &topology.cpus[i];
if (cpu_is_not_present(i)) {
- WARNING("Turbostat plugin: cpu%d NOT PRESENT", i);
+ WARNING("turbostat plugin: cpu%d NOT PRESENT", i);
continue;
}
if (ret < 0)
goto err;
else
- cpu->package_id = ret;
+ cpu->package_id = (unsigned int) ret;
if (cpu->package_id > max_package_id)
max_package_id = cpu->package_id;
if (ret < 0)
goto err;
else
- cpu->core_id = ret;
+ cpu->core_id = (unsigned int) ret;
if (cpu->core_id > max_core_id)
max_core_id = cpu->core_id;
ret = parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", i);
if (ret < 0)
goto err;
- else if (ret == i)
+ else if ((unsigned int) ret == i)
cpu->first_core_in_package = 1;
ret = get_threads_on_core(i);
if (ret < 0)
goto err;
else
- num_threads = ret;
- if (num_threads > max_thread_id)
- max_thread_id = num_threads;
+ num_threads = (unsigned int) ret;
+ if (num_threads > max_threads)
+ max_threads = num_threads;
ret = parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i);
if (ret < 0)
goto err;
- else if (ret == i)
+ else if ((unsigned int) ret == i)
cpu->first_thread_in_core = 1;
- DEBUG("Turbostat plugin: cpu %d pkg %d core %d\n",
+ DEBUG("turbostat plugin: cpu %d pkg %d core %d\n",
i, cpu->package_id, cpu->core_id);
}
/* Num is max + 1 (need to count 0) */
topology.num_packages = max_package_id + 1;
topology.num_cores = max_core_id + 1;
- topology.num_threads = max_thread_id + 1;
+ topology.num_threads = max_threads;
return 0;
err:
static int
allocate_counters(struct thread_data **threads, struct core_data **cores, struct pkg_data **packages)
{
- int i;
- int total_threads, total_cores;
+ unsigned int i;
+ unsigned int total_threads, total_cores;
+
+ if ((topology.num_threads == 0)
+ || (topology.num_cores == 0)
+ || (topology.num_packages == 0))
+ {
+ ERROR ("turbostat plugin: Invalid topology: %u threads, %u cores, %u packages",
+ topology.num_threads, topology.num_cores, topology.num_packages);
+ return -1;
+ }
total_threads = topology.num_threads * topology.num_cores * topology.num_packages;
*threads = calloc(total_threads, sizeof(struct thread_data));
if (*threads == NULL)
- goto err;
+ {
+ ERROR ("turbostat plugin: calloc failed");
+ return -1;
+ }
for (i = 0; i < total_threads; ++i)
- (*threads)[i].cpu_id = -1;
+ (*threads)[i].cpu_id = topology.max_cpu_id + 1;
total_cores = topology.num_cores * topology.num_packages;
*cores = calloc(total_cores, sizeof(struct core_data));
if (*cores == NULL)
- goto err_clean_threads;
-
- for (i = 0; i < total_cores; ++i)
- (*cores)[i].core_id = -1;
+ {
+ ERROR ("turbostat plugin: calloc failed");
+ sfree (threads);
+ return -1;
+ }
*packages = calloc(topology.num_packages, sizeof(struct pkg_data));
if (*packages == NULL)
- goto err_clean_cores;
-
- for (i = 0; i < topology.num_packages; i++)
- (*packages)[i].package_id = i;
+ {
+ ERROR ("turbostat plugin: calloc failed");
+ sfree (cores);
+ sfree (threads);
+ return -1;
+ }
return 0;
-
-err_clean_cores:
- free(*cores);
-err_clean_threads:
- free(*threads);
-err:
- ERROR("Turbostat plugin: Failled to allocate memory for counters");
- return -1;
}
static void
init_counter(struct thread_data *thread_base, struct core_data *core_base,
- struct pkg_data *pkg_base, int cpu_id)
+ struct pkg_data *pkg_base, unsigned int cpu_id)
{
struct thread_data *t;
struct core_data *c;
static void
initialize_counters(void)
{
- int cpu_id;
+ unsigned int cpu_id;
for (cpu_id = 0; cpu_id <= topology.max_cpu_id; ++cpu_id) {
if (cpu_is_not_present(cpu_id))
if ((ret = setup_all_buffers()) < 0)
return ret;
if (for_all_proc_cpus(cpu_is_not_present)) {
- ERROR("Turbostat plugin: CPU appeared just after "
+ ERROR("turbostat plugin: CPU appeared just after "
"initialization");
return -1;
}
/* Saving the scheduling affinity, as it will be modified by get_counters */
if (sched_getaffinity(0, cpu_saved_affinity_setsize, cpu_saved_affinity_set) != 0) {
- ERROR("Turbostat plugin: Unable to save the CPU affinity");
+ ERROR("turbostat plugin: Unable to save the CPU affinity");
return -1;
}
}
static int
-turbostat_init(void)
+check_permissions(void)
{
- struct stat sb;
- int ret;
+#ifdef HAVE_SYS_CAPABILITY_H
+ struct __user_cap_header_struct cap_header_data;
+ cap_user_header_t cap_header = &cap_header_data;
+ struct __user_cap_data_struct cap_data_data;
+ cap_user_data_t cap_data = &cap_data_data;
+ int ret = 0;
+#endif /* HAVE_SYS_CAPABILITY_H */
+
+ if (getuid() == 0) {
+ /* We have everything we need */
+ return 0;
+#ifndef HAVE_SYS_CAPABILITY_H
+ } else {
+ ERROR("turbostat plugin: Initialization failed: this plugin "
+ "requires collectd to run as root");
+ return -1;
+ }
+#else /* HAVE_SYS_CAPABILITY_H */
+ }
- if (getuid() != 0) {
- ERROR("Turbostat plugin: Initialization failed: this plugin "
- "requires collectd to run as root in order to read "
- "special CPU registers");
+ /* check for CAP_SYS_RAWIO */
+ cap_header->pid = getpid();
+ cap_header->version = _LINUX_CAPABILITY_VERSION;
+ if (capget(cap_header, cap_data) < 0) {
+ ERROR("turbostat plugin: capget failed");
return -1;
}
- DO_OR_GOTO_ERR(probe_cpu());
+ if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
+ WARNING("turbostat plugin: Collectd doesn't have the "
+ "CAP_SYS_RAWIO capability. If you don't want to run "
+ "collectd as root, try running \"setcap "
+ "cap_sys_rawio=ep\" on collectd binary");
+ ret = -1;
+ }
+
+ if (euidaccess("/dev/cpu/0/msr", R_OK)) {
+ WARNING("turbostat plugin: Collectd cannot open "
+ "/dev/cpu/0/msr. If you don't want to run collectd as "
+ "root, you need to change the ownership (chown) and "
+ "permissions on /dev/cpu/*/msr to allow such access");
+ ret = -1;
+ }
+
+ if (ret != 0)
+ ERROR("turbostat plugin: Initialization failed: this plugin "
+ "requires collectd to either to run as root or give "
+ "collectd a special capability (CAP_SYS_RAWIO) and read "
+ "access to /dev/cpu/*/msr (see previous warnings)");
+ return ret;
+#endif /* HAVE_SYS_CAPABILITY_H */
+}
+
+static int
+turbostat_init(void)
+{
+ struct stat sb;
+ int ret;
if (stat("/dev/cpu/0/msr", &sb)) {
- ERROR("Turbostat plugin: Initialization failed: /dev/cpu/0/msr"
- " does not exist while the CPU supports MSR. You may be "
+ ERROR("turbostat plugin: Initialization failed: /dev/cpu/0/msr "
+ "does not exist while the CPU supports MSR. You may be "
"missing the corresponding kernel module, please try '# "
"modprobe msr'");
return -1;
}
+ DO_OR_GOTO_ERR(check_permissions());
+
+ DO_OR_GOTO_ERR(probe_cpu());
+
DO_OR_GOTO_ERR(setup_all_buffers());
plugin_register_read(PLUGIN_NAME, turbostat_read);
long unsigned int tmp_val;
char *end;
- if (strcasecmp("TCCActivationTemp", key) == 0) {
+ if (strcasecmp("CoreCstates", key) == 0) {
+ tmp_val = strtoul(value, &end, 0);
+ if (*end != '\0' || tmp_val > UINT_MAX) {
+ ERROR("turbostat plugin: Invalid CoreCstates '%s'",
+ value);
+ return -1;
+ }
+ config_core_cstate = (unsigned int) tmp_val;
+ apply_config_core_cstate = 1;
+ } else if (strcasecmp("PackageCstates", key) == 0) {
+ tmp_val = strtoul(value, &end, 0);
+ if (*end != '\0' || tmp_val > UINT_MAX) {
+ ERROR("turbostat plugin: Invalid PackageCstates '%s'",
+ value);
+ return -1;
+ }
+ config_pkg_cstate = (unsigned int) tmp_val;
+ apply_config_pkg_cstate = 1;
+ } else if (strcasecmp("SystemManagementInterrupt", key) == 0) {
+ config_smi = IS_TRUE(value);
+ apply_config_smi = 1;
+ } else if (strcasecmp("DigitalTemperatureSensor", key) == 0) {
+ config_dts = IS_TRUE(value);
+ apply_config_dts = 1;
+ } else if (strcasecmp("PackageThermalManagement", key) == 0) {
+ config_ptm = IS_TRUE(value);
+ apply_config_ptm = 1;
+ } else if (strcasecmp("RunningAveragePowerLimit", key) == 0) {
+ tmp_val = strtoul(value, &end, 0);
+ if (*end != '\0' || tmp_val > UINT_MAX) {
+ ERROR("turbostat plugin: Invalid RunningAveragePowerLimit '%s'",
+ value);
+ return -1;
+ }
+ config_rapl = (unsigned int) tmp_val;
+ apply_config_rapl = 1;
+ } else if (strcasecmp("TCCActivationTemp", key) == 0) {
tmp_val = strtoul(value, &end, 0);
if (*end != '\0' || tmp_val > UINT_MAX) {
- ERROR("Turbostat plugin: Invalid TCCActivationTemp '%s'",
+ ERROR("turbostat plugin: Invalid TCCActivationTemp '%s'",
value);
return -1;
}
tcc_activation_temp = (unsigned int) tmp_val;
} else {
- ERROR("Turbostat plugin: Invalid configuration option '%s'",
+ ERROR("turbostat plugin: Invalid configuration option '%s'",
key);
return -1;
}