aboutsummaryrefslogtreecommitdiff
path: root/sysutils
diff options
context:
space:
mode:
authorKurt Jaeger <pi@FreeBSD.org>2018-07-25 19:17:22 +0000
committerKurt Jaeger <pi@FreeBSD.org>2018-07-25 19:17:22 +0000
commit75036c1703e29bd2f359b30a4ecf789d26ccb952 (patch)
tree22dc956ace79cb04417bff53166e885a3a9b535c /sysutils
parent0b032b9ee64c11d6f6cc7d9ac4faaba6a1da91aa (diff)
downloadports-75036c1703e29bd2f359b30a4ecf789d26ccb952.tar.gz
ports-75036c1703e29bd2f359b30a4ecf789d26ccb952.zip
New port: sysutils/turbostat
Report processor topology, frequency, idle power-state statistics, temperature and power on X86 processors. WWW: https://github.com/torvalds/linux/tree/master/tools/power/x86/turbostat PR: 229988 Submitted by: D Scott Phillips <d.scott.phillips@intel.com>
Notes
Notes: svn path=/head/; revision=475329
Diffstat (limited to 'sysutils')
-rw-r--r--sysutils/Makefile1
-rw-r--r--sysutils/turbostat/Makefile37
-rw-r--r--sysutils/turbostat/distinfo9
-rw-r--r--sysutils/turbostat/files/patch-turbostat.c446
-rw-r--r--sysutils/turbostat/pkg-descr4
5 files changed, 497 insertions, 0 deletions
diff --git a/sysutils/Makefile b/sysutils/Makefile
index 1f3b69921b39..2eb7647a5bdc 100644
--- a/sysutils/Makefile
+++ b/sysutils/Makefile
@@ -1290,6 +1290,7 @@
SUBDIR += ttyd
SUBDIR += ttyload
SUBDIR += tuptime
+ SUBDIR += turbostat
SUBDIR += tw_cli
SUBDIR += twmn
SUBDIR += tzdialog
diff --git a/sysutils/turbostat/Makefile b/sysutils/turbostat/Makefile
new file mode 100644
index 000000000000..65373d9383e1
--- /dev/null
+++ b/sysutils/turbostat/Makefile
@@ -0,0 +1,37 @@
+# $FreeBSD$
+
+PORTNAME= turbostat
+PORTVERSION= 4.17 # Turbostat itself has a version, but we don't bother
+CATEGORIES= sysutils
+MASTER_SITES= https://raw.githubusercontent.com/torvalds/linux/v${PORTVERSION}/tools/power/x86/turbostat/ \
+ https://raw.githubusercontent.com/torvalds/linux/v${PORTVERSION}/arch/x86/include/asm/
+DISTFILES= ${PORTNAME}.c ${PORTNAME}.8 msr-index.h intel-family.h
+DIST_SUBDIR= ${PORTNAME}-${PORTVERSION}
+
+MAINTAINER= d.scott.phillips@intel.com
+COMMENT= Report power statistics for Intel CPUs
+
+LICENSE= GPLv2
+
+ONLY_FOR_ARCHS= amd64
+
+NO_WRKSUBDIR=yes
+PLIST_FILES= sbin/turbostat man/man8/turbostat.8.gz
+
+post-extract:
+
+do-extract:
+ @${MKDIR} ${WRKSRC}
+ ${CP} ${_DISTDIR}/${PORTNAME}.c ${WRKSRC}
+ ${CP} ${_DISTDIR}/${PORTNAME}.8 ${WRKSRC}
+ ${CP} ${_DISTDIR}/msr-index.h ${WRKSRC}
+ ${CP} ${_DISTDIR}/intel-family.h ${WRKSRC}
+
+do-build:
+ cd ${WRKSRC} && ${CC} ${CFLAGS} -DMSRHEADER='"msr-index.h"' -DINTEL_FAMILY_HEADER='"intel-family.h"' -o ${PORTNAME} ${PORTNAME}.c -lutil
+
+do-install:
+ ${INSTALL_PROGRAM} ${WRKSRC}/${PORTNAME} ${STAGEDIR}${PREFIX}/sbin
+ ${INSTALL_MAN} ${WRKSRC}/${PORTNAME}.8 ${STAGEDIR}${MANPREFIX}/man/man8
+
+.include <bsd.port.mk>
diff --git a/sysutils/turbostat/distinfo b/sysutils/turbostat/distinfo
new file mode 100644
index 000000000000..7efda87eb84e
--- /dev/null
+++ b/sysutils/turbostat/distinfo
@@ -0,0 +1,9 @@
+TIMESTAMP = 1531331060
+SHA256 (turbostat-4.17/turbostat.c) = 23bc86ba086b0b18bfb92619eb66e0c482f7d6c20f5a00d9c333ac2a1c212660
+SIZE (turbostat-4.17/turbostat.c) = 135407
+SHA256 (turbostat-4.17/turbostat.8) = b58eddff29a33ada502627a457021dd70191a4e4bb96b17ff44b1623158b3ed4
+SIZE (turbostat-4.17/turbostat.8) = 18201
+SHA256 (turbostat-4.17/msr-index.h) = f984e5737423ed1e5beea2d543f2f263321f43b74abc31d728f306489279e4cf
+SIZE (turbostat-4.17/msr-index.h) = 29422
+SHA256 (turbostat-4.17/intel-family.h) = c3b888feb0e1a73c0aa6817908c2e71313b1dc2d6c834700d1f983746cc49258
+SIZE (turbostat-4.17/intel-family.h) = 2629
diff --git a/sysutils/turbostat/files/patch-turbostat.c b/sysutils/turbostat/files/patch-turbostat.c
new file mode 100644
index 000000000000..047d679c339e
--- /dev/null
+++ b/sysutils/turbostat/files/patch-turbostat.c
@@ -0,0 +1,446 @@
+--- turbostat.c.orig 2018-07-23 18:26:58 UTC
++++ turbostat.c
+@@ -41,7 +41,30 @@
+ #include <sched.h>
+ #include <time.h>
+ #include <cpuid.h>
++#ifdef __FreeBSD__
++#include <sys/types.h>
++#include <sys/cpuctl.h>
++#include <sys/cpuset.h>
++#include <sys/ioctl.h>
++#include <sys/sysctl.h>
++#include <sys/user.h>
++#include <elf.h>
++#include <libutil.h>
++#include <limits.h>
++
++#define cpu_set_t cpuset_t
++
++#define CPU_ALLOC(_ign) ({(cpuset_t*)malloc(sizeof(cpuset_t));})
++#define CPU_ALLOC_SIZE(_ign) sizeof(cpuset_t)
++#define CPU_FREE free
++#define CPU_ISSET_S(cpu, _ign, set) (set && CPU_ISSET(cpu, set))
++#define CPU_SET_S(cpu, _ign, set) CPU_SET(cpu, set)
++#define CPU_ZERO_S(_ign, set) CPU_ZERO(set)
++#define sched_setaffinity(_x, _y, set) cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset_t), set)
++
++#else
+ #include <linux/capability.h>
++#endif
+ #include <errno.h>
+
+ char *proc_stat = "/proc/stat";
+@@ -132,7 +155,9 @@ unsigned int has_misc_feature_control;
+ #define RAPL_CORES (RAPL_CORES_ENERGY_STATUS | RAPL_CORES_POWER_LIMIT)
+ #define TJMAX_DEFAULT 100
+
++#ifndef __FreeBSD__
+ #define MAX(a, b) ((a) > (b) ? (a) : (b))
++#endif
+
+ /*
+ * buffer size used by sscanf() for added column names
+@@ -309,6 +334,7 @@ int cpu_migrate(int cpu)
+ else
+ return 0;
+ }
++
+ int get_msr_fd(int cpu)
+ {
+ char pathname[32];
+@@ -319,18 +345,39 @@ int get_msr_fd(int cpu)
+ if (fd)
+ return fd;
+
++#ifdef __FreeBSD__
++ sprintf(pathname, "/dev/cpuctl%d", cpu);
++#else
+ sprintf(pathname, "/dev/cpu/%d/msr", cpu);
++#endif
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+- err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
++ err(-1, "%s open failed, try chown or chmod +r "
++#ifdef __FreeBSD__
++ "/dev/cpuctl*"
++#else
++ "/dev/cpu/*/msr"
++#endif
++ ", or run as root", pathname);
+
+ fd_percpu[cpu] = fd;
+
+ return fd;
+ }
+
++#ifdef __FreeBSD__
+ int get_msr(int cpu, off_t offset, unsigned long long *msr)
+ {
++ cpuctl_msr_args_t args;
++ args.msr = offset;
++ if (ioctl(get_msr_fd(cpu), CPUCTL_RDMSR, &args))
++ err(1, "cpu%d: msr offset 0x%llx read failed", cpu, (unsigned long long)offset);
++ *msr = args.data;
++ return 0;
++}
++#else
++int get_msr(int cpu, off_t offset, unsigned long long *msr)
++{
+ ssize_t retval;
+
+ retval = pread(get_msr_fd(cpu), msr, sizeof(*msr), offset);
+@@ -340,6 +387,7 @@ int get_msr(int cpu, off_t offset, unsigned long long
+
+ return 0;
+ }
++#endif
+
+ /*
+ * Each string in this array is compared in --show and --hide cmdline.
+@@ -2239,6 +2287,158 @@ int parse_int_file(const char *fmt, ...)
+ return value;
+ }
+
++#ifdef __FreeBSD__
++static int ncpus;
++struct cpuset_list {
++ cpuset_t *sets;
++ size_t len;
++ size_t cap;
++};
++static struct cpuset_list packages = {0};
++static struct cpuset_list cores = {0};
++
++static void cpuset_list_ensure_space(struct cpuset_list *list) {
++ if (list->cap > list->len)
++ return;
++
++ if (list->cap)
++ list->cap *= 2;
++ else
++ list->cap = 2;
++
++ list->sets = reallocarray(list->sets, list->cap, sizeof(cpuset_t));
++}
++
++static cpuset_t parse_cpu_mask(const char *i) {
++ int count, mask_offset;
++ i = strstr(i, "mask=\"");
++ if (!i)
++ errx(1, "failed to parse topology_spec");
++ i += sizeof("mask=\"") - 1;
++
++ char sep;
++ cpuset_t out;
++ uint64_t *_out = (uint64_t *)&out;
++ CPU_ZERO(&out);
++
++ do {
++ int len;
++ if (sscanf(i, "%lx%c%n", _out, &sep, &len) != 2)
++ errx(1, "failed to parse topology_spec");
++ _out++;
++ i += len;
++ } while (sep == ',');
++
++ return out;
++}
++
++static void read_topology_spec(void)
++{
++ char spec[16384];
++ size_t sz = sizeof(spec) - 1;
++ char *i;
++
++ if (sysctlbyname("kern.sched.topology_spec", spec, &sz, NULL, 0))
++ err(1, "sysctl: kern.sched.topology_spec: failed");
++ spec[sizeof(spec) - 1] = '\0';
++
++ /* Skip the entire system entry. */
++ i = strstr(spec, "<cpu");
++ if (!i)
++ errx(1, "read_topology_spec: parse failed");
++
++ cpuset_t last;
++ CPU_ZERO(&last);
++
++ while ((i = strstr(i + 1, "<cpu")) != NULL) {
++ cpuset_t set = parse_cpu_mask(i);
++
++ if (CPU_OVERLAP(&last, &set)) {
++ cpuset_list_ensure_space(&packages);
++ cores.len--;
++ CPU_COPY(cores.sets + cores.len, packages.sets + packages.len);
++ packages.len++;
++ }
++
++ cpuset_list_ensure_space(&cores);
++ CPU_COPY(&set, cores.sets + cores.len);
++ cores.len++;
++ CPU_COPY(&set, &last);
++ }
++
++ if (!packages.len) {
++ cpuset_list_ensure_space(&packages);
++ CPU_ZERO(packages.sets);
++
++ for (int i = 0; i < cores.len; i++)
++ CPU_OR(packages.sets, cores.sets + i);
++ packages.len++;
++ }
++
++ ncpus = 0;
++ for (int i = 0; i < packages.len; i++)
++ ncpus += CPU_COUNT(packages.sets + i);
++}
++
++static int get_core_id(int cpu)
++{
++ for (int i = 0; i < cores.len; i++) {
++ if (!CPU_ISSET(cpu, cores.sets + i))
++ continue;
++
++ return i;
++ }
++ return -1;
++}
++
++static int get_cpu_position_in_core(int cpu)
++{
++ int core = get_core_id(cpu);
++ if (core < 0)
++ return -1;
++
++ cpuset_t s;
++ CPU_COPY(cores.sets + core, &s);
++ for (int i = 0; !CPU_EMPTY(&s); i++) {
++ int ffs = CPU_FFS(&s) - 1;
++ if (ffs == cpu)
++ return i;
++ CPU_CLR(ffs, &s);
++ }
++
++ return -1;
++}
++
++static int get_num_ht_siblings(int cpu)
++{
++ int core = get_core_id(cpu);
++ if (core < 0)
++ return 1;
++
++ return CPU_COUNT(cores.sets + core);
++}
++
++static int get_physical_package_id(int cpu)
++{
++ for (int i = 0; i < packages.len; i++) {
++ if (!CPU_ISSET(cpu, packages.sets + i))
++ continue;
++
++ return i;
++ }
++ return -1;
++}
++
++static int cpu_is_first_core_in_package(int cpu)
++{
++ int package = get_physical_package_id(cpu);
++ if (package < 0)
++ return -1;
++
++ return CPU_FFS(packages.sets + package) - 1 == cpu;
++}
++
++#else
+ /*
+ * get_cpu_position_in_core(cpu)
+ * return the position of the CPU among its HT siblings in the core
+@@ -2326,6 +2526,7 @@ int get_num_ht_siblings(int cpu)
+ fclose(filep);
+ return matches+1;
+ }
++#endif
+
+ /*
+ * run func(thread, core, package) in topology order
+@@ -2371,6 +2572,22 @@ int for_all_cpus_2(int (func)(struct thread_data *, st
+ return 0;
+ }
+
++#ifdef __FreeBSD__
++int for_all_proc_cpus(int (func)(int))
++{
++ int retval;
++
++ if (!ncpus)
++ read_topology_spec();
++
++ for (long i = 0; i < ncpus; i++) {
++ retval = func(i);
++ if (retval)
++ return retval;
++ }
++ return 0;
++}
++#else
+ /*
+ * run func(cpu) on every cpu in /proc/stat
+ * return max_cpu number
+@@ -2401,6 +2618,7 @@ int for_all_proc_cpus(int (func)(int))
+ fclose(fp);
+ return 0;
+ }
++#endif
+
+ void re_initialize(void)
+ {
+@@ -2428,6 +2646,81 @@ int mark_cpu_present(int cpu)
+ return 0;
+ }
+
++#ifdef __FreeBSD__
++static struct {
++ uint64_t intr_num;
++ uint64_t cpu_num;
++} *intr_map = NULL;
++static size_t intr_map_len = 0;
++static size_t intr_map_cap = 0;
++
++static void ensure_intr_map(void)
++{
++ if (intr_map_cap > intr_map_len)
++ return;
++
++ if (intr_map_cap)
++ intr_map_cap *= 2;
++ else
++ intr_map_cap = 2;
++
++ intr_map = reallocarray(intr_map, intr_map_cap, sizeof(*intr_map));
++}
++
++static void init_intr_map(void)
++{
++ size_t sz = 0;
++ if (sysctlbyname("hw.intrs", NULL, &sz, NULL, 0))
++ err(1, "sysctl: hw.intrs: failed");
++ char *intrs = alloca(sz);
++ if (sysctlbyname("hw.intrs", intrs, &sz, NULL, 0))
++ err(1, "sysctl: hw.intrs: failed");
++
++ char *i = intrs;
++ char *j;
++ while ((j = strstr(i, "@cpu")) != NULL) {
++ char *k;
++ for (k = j; k > i && *k != ':'; k--)
++ ;
++ if (*k != ':')
++ errx(1, "init_intr_map: parse failed");
++ k++;
++ uint64_t intr_num;
++ if (sscanf(k, "%ld", &intr_num) != 1)
++ errx(1, "init_intr_map: parse failed");
++ j += 4;
++ uint64_t cpu_num;
++ if (sscanf(j, "%ld", &cpu_num) != 1)
++ errx(1, "init_intr_map: parse failed");
++ ensure_intr_map();
++ intr_map[intr_map_len].intr_num = intr_num;
++ intr_map[intr_map_len].cpu_num = cpu_num;
++ intr_map_len++;
++
++ i = j;
++ }
++}
++
++static int snapshot_proc_interrupts(void)
++{
++ if (!intr_map)
++ init_intr_map();
++
++ size_t sz = 0;
++ if (sysctlbyname("hw.intrcnt", NULL, &sz, NULL, 0))
++ err(1, "sysctl: hw.intrcnt: failed");
++ uint64_t *intrcnt = alloca(sz);
++ if (sysctlbyname("hw.intrcnt", intrcnt, &sz, NULL, 0))
++ err(1, "sysctl: hw.intrcnt: failed");
++
++ for (int i = 0; i < topo.num_cpus; i++)
++ irqs_per_cpu[i] = 0;
++ for (int i = 0; i < intr_map_len; i++)
++ irqs_per_cpu[intr_map[i].cpu_num] += intrcnt[intr_map[i].intr_num];
++
++ return 0;
++}
++#else
+ /*
+ * snapshot_proc_interrupts()
+ *
+@@ -2491,6 +2784,8 @@ int snapshot_proc_interrupts(void)
+ }
+ return 0;
+ }
++#endif
++
+ /*
+ * snapshot_gfx_rc6_ms()
+ *
+@@ -2629,6 +2924,18 @@ restart:
+ }
+ }
+
++#ifdef __FreeBSD__
++#define check_dev_msr()
++
++void check_permissions()
++{
++ if (eaccess("/dev/cpuctl0", F_OK))
++ err(errno, "/dev/cpuctl0 missing, kldload cpuctl");
++ if (eaccess("/dev/cpuctl0", R_OK))
++ err(errno, "cannot read /dev/cpuctl0, (run as root?)");
++}
++
++#else
+ void check_dev_msr()
+ {
+ struct stat sb;
+@@ -2677,6 +2984,7 @@ void check_permissions()
+ if (do_exit)
+ exit(-6);
+ }
++#endif
+
+ /*
+ * NHM adds support for additional MSRs:
+@@ -4520,8 +4828,21 @@ void setup_all_buffers(void)
+ for_all_proc_cpus(initialize_counters);
+ }
+
++#ifdef __FreeBSD__
+ void set_base_cpu(void)
+ {
++ struct kinfo_proc *proc = kinfo_getproc(getpid());
++ if (!proc || proc->ki_oncpu == NOCPU)
++ err(-ENODEV, "Failed to lookup curcpu");
++ base_cpu = proc->ki_oncpu;
++ free(proc);
++
++ if (debug > 1)
++ fprintf(outf, "base_cpu = %d\n", base_cpu);
++}
++#else
++void set_base_cpu(void)
++{
+ base_cpu = sched_getcpu();
+ if (base_cpu < 0)
+ err(-ENODEV, "No valid cpus found");
+@@ -4529,6 +4850,7 @@ void set_base_cpu(void)
+ if (debug > 1)
+ fprintf(outf, "base_cpu = %d\n", base_cpu);
+ }
++#endif
+
+ void turbostat_init()
+ {
diff --git a/sysutils/turbostat/pkg-descr b/sysutils/turbostat/pkg-descr
new file mode 100644
index 000000000000..77c8074c8729
--- /dev/null
+++ b/sysutils/turbostat/pkg-descr
@@ -0,0 +1,4 @@
+Report processor topology, frequency, idle power-state
+statistics, temperature and power on X86 processors.
+
+WWW: https://github.com/torvalds/linux/tree/master/tools/power/x86/turbostat