diff options
author | pi <pi@FreeBSD.org> | 2018-07-26 03:17:22 +0800 |
---|---|---|
committer | pi <pi@FreeBSD.org> | 2018-07-26 03:17:22 +0800 |
commit | 986e1dab06acc05e14e87e7081ec195f878338c1 (patch) | |
tree | 22dc956ace79cb04417bff53166e885a3a9b535c | |
parent | 260960536bbf28b5bfedaf5500b8d01d1ef65f4a (diff) | |
download | freebsd-ports-gnome-986e1dab06acc05e14e87e7081ec195f878338c1.tar.gz freebsd-ports-gnome-986e1dab06acc05e14e87e7081ec195f878338c1.tar.zst freebsd-ports-gnome-986e1dab06acc05e14e87e7081ec195f878338c1.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>
-rw-r--r-- | sysutils/Makefile | 1 | ||||
-rw-r--r-- | sysutils/turbostat/Makefile | 37 | ||||
-rw-r--r-- | sysutils/turbostat/distinfo | 9 | ||||
-rw-r--r-- | sysutils/turbostat/files/patch-turbostat.c | 446 | ||||
-rw-r--r-- | sysutils/turbostat/pkg-descr | 4 |
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 |