Index: sysutils/turbostat/Makefile =================================================================== --- /dev/null +++ sysutils/turbostat/Makefile @@ -0,0 +1,38 @@ +# $FreeBSD$ + +PORTNAME= turbostat +PORTVERSION= 4.17 # Turbostat itself has a version, but we don't bother +PORTREVISION= 1 +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 Index: sysutils/turbostat/distinfo =================================================================== --- /dev/null +++ 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 Index: sysutils/turbostat/files/patch-turbostat.c =================================================================== --- /dev/null +++ sysutils/turbostat/files/patch-turbostat.c @@ -0,0 +1,466 @@ +--- turbostat.c.orig 2018-07-31 20:42:12 UTC ++++ turbostat.c +@@ -41,7 +41,31 @@ + #include + #include + #include ++#ifdef __FreeBSD__ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#endif + #include + + char *proc_stat = "/proc/stat"; +@@ -132,7 +156,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 +335,7 @@ int cpu_migrate(int cpu) + else + return 0; + } ++ + int get_msr_fd(int cpu) + { + char pathname[32]; +@@ -319,18 +346,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 +388,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 +2288,173 @@ 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 = realloc(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, " intr_map_len) ++ return; ++ ++ if (intr_map_cap) ++ intr_map_cap *= 2; ++ else ++ intr_map_cap = 2; ++ ++ intr_map = realloc(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)) { ++ warn("sysctl: hw.intrs: per-cpu interrupt data will be unavailable"); ++ return; ++ } ++ char *intrs = alloca(sz); ++ if (sysctlbyname("hw.intrs", intrs, &sz, NULL, 0)) { ++ warn("sysctl: hw.intrs: per-cpu interrupt data will be unavailable"); ++ return; ++ } ++ ++ 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 +2804,8 @@ int snapshot_proc_interrupts(void) + } + return 0; + } ++#endif ++ + /* + * snapshot_gfx_rc6_ms() + * +@@ -2629,6 +2944,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 +3004,7 @@ void check_permissions() + if (do_exit) + exit(-6); + } ++#endif + + /* + * NHM adds support for additional MSRs: +@@ -4520,8 +4848,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 +4870,7 @@ void set_base_cpu(void) + if (debug > 1) + fprintf(outf, "base_cpu = %d\n", base_cpu); + } ++#endif + + void turbostat_init() + { Index: sysutils/turbostat/pkg-descr =================================================================== --- /dev/null +++ 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