* turbostat -- Log CPU frequency and C-state residency
* on modern Intel turbo-capable processors for collectd.
*
- * Based on the kernel tools by:
+ * Based on the 'turbostat' tool of the Linux kernel, found at
+ * linux/tools/power/x86/turbostat/turbostat.c:
+ * ----
* Copyright (c) 2013 Intel Corporation.
* Len Brown <len.brown@intel.com>
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
+ * ----
* Ported to collectd by Vincent Brillault <git@lerya.net>
*/
+/*
+ * _GNU_SOURCE is required because of the following functions:
+ * - CPU_ISSET_S
+ * - CPU_ZERO_S
+ * - CPU_SET_S
+ * - CPU_FREE
+ * - CPU_ALLOC
+ * - CPU_ALLOC_SIZE
+ */
#define _GNU_SOURCE
-#include "msr-index.h"
+
+#include <asm/msr-index.h>
#include <stdarg.h>
#include <stdio.h>
-#include <stdbool.h>
#include <err.h>
#include <unistd.h>
#include <sys/types.h>
#define PLUGIN_NAME "turbostat"
static const char *proc_stat = "/proc/stat";
-static unsigned int interval_sec = 5; /* set with -i interval_sec */
static unsigned int skip_c0;
static unsigned int skip_c1;
static unsigned int do_nhm_cstates;
static unsigned int do_snb_cstates;
static unsigned int do_c8_c9_c10;
static unsigned int do_slm_cstates;
-static unsigned int has_aperf;
static unsigned int has_epb;
-static unsigned int units = 1000000000; /* Ghz etc */
static unsigned int genuine_intel;
-static unsigned int has_invariant_tsc;
static unsigned int do_nehalem_platform_info;
static int do_smi;
-static unsigned int show_pkg;
-static unsigned int show_core;
-static unsigned int show_cpu;
static unsigned int do_rapl;
static unsigned int do_dts;
static unsigned int do_ptm;
#define ODD_COUNTERS thread_odd, core_odd, package_odd
#define EVEN_COUNTERS thread_even, core_even, package_even
-static bool is_even = true;
+static _Bool is_even = 1;
-static bool allocated = false;
-static bool initialized = false;
+static _Bool allocated = 0;
+static _Bool initialized = 0;
#define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
(thread_base + (pkg_no) * topo.num_cores_per_pkg * \
ERR_NOT_ROOT,
};
-#define STATIC_MUST_CHECK(function) \
-function \
- __attribute__((warn_unused_result)); \
-function
-
static int setup_all_buffers(void);
-static int cpu_is_not_present(int cpu)
+static int
+cpu_is_not_present(int cpu)
{
return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
}
* skip non-present cpus
*/
-STATIC_MUST_CHECK(static int 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))
+static int __attribute__((warn_unused_result))
+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;
return 0;
}
-STATIC_MUST_CHECK(static int cpu_migrate(int cpu))
+static int __attribute__((warn_unused_result))
+cpu_migrate(int cpu)
{
CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
return 0;
}
-STATIC_MUST_CHECK(static int get_msr(int cpu, off_t offset, unsigned long long *msr))
+static int __attribute__((warn_unused_result))
+get_msr(int cpu, off_t offset, unsigned long long *msr)
{
ssize_t retval;
char pathname[32];
int fd;
- sprintf(pathname, "/dev/cpu/%d/msr", cpu);
+ ssnprintf(pathname, 32, "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY);
if (fd < 0)
return -1;
/*
* old = new - old
*/
-STATIC_MUST_CHECK(static int
+static int __attribute__((warn_unused_result))
delta_thread(struct thread_data *new, struct thread_data *old,
- struct core_data *core_delta))
+ struct core_data *core_delta)
{
old->tsc = new->tsc - old->tsc;
return 0;
}
-STATIC_MUST_CHECK(static int delta_cpu(struct thread_data *t, struct core_data *c,
+static int __attribute__((warn_unused_result))
+delta_cpu(struct thread_data *t, struct core_data *c,
struct pkg_data *p, struct thread_data *t2,
- struct core_data *c2, struct pkg_data *p2))
+ struct core_data *c2, struct pkg_data *p2)
{
int ret;
return 0;
}
-static unsigned long long rdtsc(void)
+static unsigned long long
+rdtsc(void)
{
unsigned int low, high;
* migrate to cpu
* acquire and record local counters for that cpu
*/
-STATIC_MUST_CHECK(static int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p))
+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 long long msr;
t->tsc = rdtsc(); /* we are running on local CPU of interest */
- if (has_aperf) {
- if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
- return -ERR_MSR_IA32_APERF;
- if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
- return -ERR_MSR_IA32_MPERF;
- }
+ if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
+ return -ERR_MSR_IA32_APERF;
+ if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
+ return -ERR_MSR_IA32_MPERF;
if (do_smi) {
if (get_msr(cpu, MSR_SMI_COUNT, &msr))
return 0;
}
-static void free_all_buffers(void)
+static void
+free_all_buffers(void)
{
- allocated = false;
- initialized = false;
+ allocated = 0;
+ initialized = 0;
CPU_FREE(cpu_present_set);
cpu_present_set = NULL;
/*
* Parse a file containing a single int.
*/
-static int parse_int_file(const char *fmt, ...)
+static int __attribute__ ((format(printf,1,2)))
+parse_int_file(const char *fmt, ...)
{
va_list args;
char path[PATH_MAX];
* cpu_is_first_sibling_in_core(cpu)
* return 1 if given CPU is 1st HT sibling in the core
*/
-static int cpu_is_first_sibling_in_core(int cpu)
+static int
+cpu_is_first_sibling_in_core(int cpu)
{
return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
}
* cpu_is_first_core_in_package(cpu)
* return 1 if given CPU is 1st core in package
*/
-static int cpu_is_first_core_in_package(int cpu)
+static int
+cpu_is_first_core_in_package(int cpu)
{
return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);
}
-static int get_physical_package_id(int cpu)
+static int
+get_physical_package_id(int cpu)
{
return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
}
-static int get_core_id(int cpu)
+static int
+get_core_id(int cpu)
{
return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
}
-static int get_num_ht_siblings(int cpu)
+static int
+get_num_ht_siblings(int cpu)
{
char path[80];
FILE *filep;
int matches;
char character;
- sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
+ ssnprintf(path, 80, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
filep = fopen(path, "r");
if (!filep) {
ERROR("%s: open failed", path);
* skip non-present cpus
*/
-STATIC_MUST_CHECK(
-static int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
+
+static int __attribute__((warn_unused_result))
+for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
struct pkg_data *, struct thread_data *, struct core_data *,
struct pkg_data *), struct thread_data *thread_base,
struct core_data *core_base, struct pkg_data *pkg_base,
struct thread_data *thread_base2, struct core_data *core_base2,
- struct pkg_data *pkg_base2))
+ struct pkg_data *pkg_base2)
{
int retval, pkg_no, core_no, thread_no;
* run func(cpu) on every cpu in /proc/stat
* return max_cpu number
*/
-STATIC_MUST_CHECK(static int for_all_proc_cpus(int (func)(int)))
+static int __attribute__((warn_unused_result))
+for_all_proc_cpus(int (func)(int))
{
FILE *fp;
int cpu_num;
* count_cpus()
* remember the last one seen, it will be the max
*/
-static int count_cpus(int cpu)
+static int
+count_cpus(int cpu)
{
if (topo.max_cpu_num < cpu)
topo.max_cpu_num = cpu;
topo.num_cpus += 1;
return 0;
}
-static int mark_cpu_present(int cpu)
+static int
+mark_cpu_present(int cpu)
{
CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
return 0;
}
-static void turbostat_submit (const char *plugin_instance,
+static void
+turbostat_submit (const char *plugin_instance,
const char *type, const char *type_instance,
gauge_t value)
{
* "CTMP" 4 columns %4d
*/
#define NAME_LEN 12
-static int submit_counters(struct thread_data *t, struct core_data *c,
+static int
+submit_counters(struct thread_data *t, struct core_data *c,
struct pkg_data *p)
{
char name[NAME_LEN];
}
/* GHz */
- if (has_aperf && ((!aperf_mperf_unstable) || (!(t->aperf > t->tsc || t->mperf > t->tsc))))
- turbostat_submit(NULL, "frequency", name, 1.0 * t->tsc / units * t->aperf / t->mperf / 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);
/* SMI */
if (do_smi)
if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
goto done;
- snprintf(name, NAME_LEN, "pc%02d", p->package_id);
+ snprintf(name, NAME_LEN, "pkg%02d", p->package_id);
if (do_ptm)
turbostat_submit(NULL, "temperature", name, p->pkg_temp_c);
return 0;
}
-static int turbostat_read (user_data_t * not_used)
+static int
+turbostat_read(user_data_t * not_used)
{
int ret;
if ((ret = for_all_cpus(get_counters, EVEN_COUNTERS)) < 0)
return ret;
gettimeofday(&tv_even, (struct timezone *)NULL);
- is_even = true;
- initialized = true;
+ is_even = 1;
+ initialized = 1;
return 0;
}
if ((ret = for_all_cpus(get_counters, ODD_COUNTERS)) < 0)
return ret;
gettimeofday(&tv_odd, (struct timezone *)NULL);
- is_even = false;
+ is_even = 0;
timersub(&tv_odd, &tv_even, &tv_delta);
if ((ret = for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS)) < 0)
return ret;
if ((ret = for_all_cpus(get_counters, EVEN_COUNTERS)) < 0)
return ret;
gettimeofday(&tv_even, (struct timezone *)NULL);
- is_even = true;
+ is_even = 1;
timersub(&tv_even, &tv_odd, &tv_delta);
if ((ret = for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS)) < 0)
return ret;
return 0;
}
-STATIC_MUST_CHECK(static int check_dev_msr())
+static int __attribute__((warn_unused_result))
+check_dev_msr()
{
struct stat sb;
return 0;
}
-STATIC_MUST_CHECK(static int check_super_user())
+static int __attribute__((warn_unused_result))
+check_super_user()
{
if (getuid() != 0) {
ERROR("must be root");
#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
-static double get_tdp(unsigned int model)
+static double
+get_tdp(unsigned int model)
{
unsigned long long msr;
*
* sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
*/
-static void rapl_probe(unsigned int family, unsigned int model)
+static void
+rapl_probe(unsigned int family, unsigned int model)
{
unsigned long long msr;
unsigned int time_unit;
return;
}
-static int is_snb(unsigned int family, unsigned int model)
+static int
+is_snb(unsigned int family, unsigned int model)
{
if (!genuine_intel)
return 0;
return 0;
}
-static int has_c8_c9_c10(unsigned int family, unsigned int model)
+static int
+has_c8_c9_c10(unsigned int family, unsigned int model)
{
if (!genuine_intel)
return 0;
}
-static int is_slm(unsigned int family, unsigned int model)
+static int
+is_slm(unsigned int family, unsigned int model)
{
if (!genuine_intel)
return 0;
* below this value, including the Digital Thermal Sensor (DTS),
* Package Thermal Management Sensor (PTM), and thermal event thresholds.
*/
-STATIC_MUST_CHECK(static int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p))
+static int __attribute__((warn_unused_result))
+set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
{
unsigned long long msr;
unsigned int target_c_local;
return 0;
}
-STATIC_MUST_CHECK(static int check_cpuid())
+static int __attribute__((warn_unused_result))
+check_cpuid()
{
unsigned int eax, ebx, ecx, edx, max_level;
unsigned int fms, family, model;
* this check is valid for both Intel and AMD
*/
__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
- has_invariant_tsc = edx & (1 << 8);
-
- if (!has_invariant_tsc) {
+ if (!(edx & (1 << 8))) {
ERROR("No invariant TSC");
return -ERR_NO_INVARIANT_TSC;
}
*/
__get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
- has_aperf = ecx & (1 << 0);
do_dts = eax & (1 << 0);
do_ptm = eax & (1 << 6);
has_epb = ecx & (1 << 3);
- if (!has_aperf) {
+ if (!(ecx & (1 << 0))) {
ERROR("No APERF");
return -ERR_NO_APERF;
}
- do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
+ do_nehalem_platform_info = genuine_intel;
do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
do_smi = do_nhm_cstates;
do_snb_cstates = is_snb(family, model);
-STATIC_MUST_CHECK(static int topology_probe())
+static int __attribute__((warn_unused_result))
+topology_probe()
{
int i;
int ret;
ret = for_all_proc_cpus(count_cpus);
if (ret < 0)
return ret;
- if (topo.num_cpus > 1)
- show_cpu = 1;
DEBUG("num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
topo.num_cores_per_pkg = max_core_id + 1;
DEBUG("max_core_id %d, sizing for %d cores per package\n",
max_core_id, topo.num_cores_per_pkg);
- if (topo.num_cores_per_pkg > 1)
- show_core = 1;
topo.num_packages = max_package_id + 1;
DEBUG("max_package_id %d, sizing for %d packages\n",
max_package_id, topo.num_packages);
- if (topo.num_packages > 1)
- show_pkg = 1;
topo.num_threads_per_core = max_siblings;
DEBUG("max_siblings %d\n", max_siblings);
*
* increment topo.num_cores when 1st core in pkg seen
*/
-static int init_counter(struct thread_data *thread_base, struct core_data *core_base,
+static int
+init_counter(struct thread_data *thread_base, struct core_data *core_base,
struct pkg_data *pkg_base, int thread_num, int core_num,
int pkg_num, int cpu_id)
{
}
-static int initialize_counters(int cpu_id)
+static int
+initialize_counters(int cpu_id)
{
int my_thread_id, my_core_id, my_package_id;
int ret;
#define DO_OR_GOTO_ERR(something) \
do { \
- ret = something; \
+ ret = (something); \
if (ret < 0) \
goto err; \
-} while (0);
+} while (0)
static int setup_all_buffers(void)
{
int ret;
- DO_OR_GOTO_ERR(topology_probe())
- DO_OR_GOTO_ERR(allocate_counters(&thread_even, &core_even, &package_even))
- DO_OR_GOTO_ERR(allocate_counters(&thread_odd, &core_odd, &package_odd))
- DO_OR_GOTO_ERR(for_all_proc_cpus(initialize_counters))
+ DO_OR_GOTO_ERR(topology_probe());
+ DO_OR_GOTO_ERR(allocate_counters(&thread_even, &core_even, &package_even));
+ DO_OR_GOTO_ERR(allocate_counters(&thread_odd, &core_odd, &package_odd));
+ DO_OR_GOTO_ERR(for_all_proc_cpus(initialize_counters));
- allocated = true;
+ allocated = 1;
return 0;
err:
free_all_buffers();
return ret;
}
-static int turbostat_init(void)
+static int
+turbostat_init(void)
{
int ret;
- struct timespec ts;
-
- DO_OR_GOTO_ERR(check_cpuid())
- DO_OR_GOTO_ERR(check_dev_msr())
- DO_OR_GOTO_ERR(check_super_user())
- DO_OR_GOTO_ERR(setup_all_buffers())
- DO_OR_GOTO_ERR(for_all_cpus(set_temperature_target, EVEN_COUNTERS))
- ts.tv_sec = interval_sec;
- ts.tv_nsec = 0;
+ DO_OR_GOTO_ERR(check_cpuid());
+ DO_OR_GOTO_ERR(check_dev_msr());
+ DO_OR_GOTO_ERR(check_super_user());
+ DO_OR_GOTO_ERR(setup_all_buffers());
+ DO_OR_GOTO_ERR(for_all_cpus(set_temperature_target, EVEN_COUNTERS));
- plugin_register_complex_read(NULL, PLUGIN_NAME, turbostat_read, &ts, NULL);
+ plugin_register_complex_read(NULL, PLUGIN_NAME, turbostat_read, NULL, NULL);
return 0;
err:
return ret;
}
-static const char *config_keys[] =
-{
- "Interval",
-};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-
-static int turbostat_config (const char *key, const char *value)
-{
- if (strcasecmp("Interval", key) == 0)
- interval_sec = atoi(value);
- else
- return -1;
- return 0;
-}
-
-void module_register (void);
-void module_register (void)
+void module_register(void);
+void module_register(void)
{
plugin_register_init(PLUGIN_NAME, turbostat_init);
- plugin_register_config(PLUGIN_NAME, turbostat_config, config_keys, config_keys_num);
}