Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Jul 2018 19:17:22 +0000 (UTC)
From:      Kurt Jaeger <pi@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r475329 - in head/sysutils: . turbostat turbostat/files
Message-ID:  <201807251917.w6PJHM0m061709@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pi
Date: Wed Jul 25 19:17:22 2018
New Revision: 475329
URL: https://svnweb.freebsd.org/changeset/ports/475329

Log:
  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>

Added:
  head/sysutils/turbostat/
  head/sysutils/turbostat/Makefile   (contents, props changed)
  head/sysutils/turbostat/distinfo   (contents, props changed)
  head/sysutils/turbostat/files/
  head/sysutils/turbostat/files/patch-turbostat.c   (contents, props changed)
  head/sysutils/turbostat/pkg-descr   (contents, props changed)
Modified:
  head/sysutils/Makefile

Modified: head/sysutils/Makefile
==============================================================================
--- head/sysutils/Makefile	Wed Jul 25 19:14:54 2018	(r475328)
+++ head/sysutils/Makefile	Wed Jul 25 19:17:22 2018	(r475329)
@@ -1290,6 +1290,7 @@
     SUBDIR += ttyd
     SUBDIR += ttyload
     SUBDIR += tuptime
+    SUBDIR += turbostat
     SUBDIR += tw_cli
     SUBDIR += twmn
     SUBDIR += tzdialog

Added: head/sysutils/turbostat/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/turbostat/Makefile	Wed Jul 25 19:17:22 2018	(r475329)
@@ -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>

Added: head/sysutils/turbostat/distinfo
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/turbostat/distinfo	Wed Jul 25 19:17:22 2018	(r475329)
@@ -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

Added: head/sysutils/turbostat/files/patch-turbostat.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/turbostat/files/patch-turbostat.c	Wed Jul 25 19:17:22 2018	(r475329)
@@ -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()
+ {

Added: head/sysutils/turbostat/pkg-descr
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/turbostat/pkg-descr	Wed Jul 25 19:17:22 2018	(r475329)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201807251917.w6PJHM0m061709>