brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 811d63a Raw
200 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.4 *5 *  Based on Len Brown's <lenb@kernel.org> turbostat tool.6 */7 8#if defined(__i386__) || defined(__x86_64__)9 10#include <stdio.h>11#include <stdint.h>12#include <stdlib.h>13#include <string.h>14 15#include "helpers/helpers.h"16#include "idle_monitor/cpupower-monitor.h"17 18#define MSR_PKG_C2_RESIDENCY	0x60D19#define MSR_PKG_C7_RESIDENCY	0x3FA20#define MSR_CORE_C7_RESIDENCY	0x3FE21 22#define MSR_TSC	0x1023 24enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF };25 26static int snb_get_count_percent(unsigned int self_id, double *percent,27				 unsigned int cpu);28 29static cstate_t snb_cstates[SNB_CSTATE_COUNT] = {30	{31		.name			= "C7",32		.desc			= N_("Processor Core C7"),33		.id			= C7,34		.range			= RANGE_CORE,35		.get_count_percent	= snb_get_count_percent,36	},37	{38		.name			= "PC2",39		.desc			= N_("Processor Package C2"),40		.id			= PC2,41		.range			= RANGE_PACKAGE,42		.get_count_percent	= snb_get_count_percent,43	},44	{45		.name			= "PC7",46		.desc			= N_("Processor Package C7"),47		.id			= PC7,48		.range			= RANGE_PACKAGE,49		.get_count_percent	= snb_get_count_percent,50	},51};52 53static unsigned long long tsc_at_measure_start;54static unsigned long long tsc_at_measure_end;55static unsigned long long *previous_count[SNB_CSTATE_COUNT];56static unsigned long long *current_count[SNB_CSTATE_COUNT];57/* valid flag for all CPUs. If a MSR read failed it will be zero */58static int *is_valid;59 60static int snb_get_count(enum intel_snb_id id, unsigned long long *val,61			unsigned int cpu)62{63	int msr;64 65	switch (id) {66	case C7:67		msr = MSR_CORE_C7_RESIDENCY;68		break;69	case PC2:70		msr = MSR_PKG_C2_RESIDENCY;71		break;72	case PC7:73		msr = MSR_PKG_C7_RESIDENCY;74		break;75	case TSC:76		msr = MSR_TSC;77		break;78	default:79		return -1;80	}81	if (read_msr(cpu, msr, val))82		return -1;83	return 0;84}85 86static int snb_get_count_percent(unsigned int id, double *percent,87				 unsigned int cpu)88{89	*percent = 0.0;90 91	if (!is_valid[cpu])92		return -1;93 94	*percent = (100.0 *95		(current_count[id][cpu] - previous_count[id][cpu])) /96		(tsc_at_measure_end - tsc_at_measure_start);97 98	dprint("%s: previous: %llu - current: %llu - (%u)\n",99		snb_cstates[id].name, previous_count[id][cpu],100		current_count[id][cpu], cpu);101 102	dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",103	       snb_cstates[id].name,104	       (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,105	       current_count[id][cpu] - previous_count[id][cpu],106	       *percent, cpu);107 108	return 0;109}110 111static int snb_start(void)112{113	int num, cpu;114	unsigned long long val;115 116	for (num = 0; num < SNB_CSTATE_COUNT; num++) {117		for (cpu = 0; cpu < cpu_count; cpu++) {118			snb_get_count(num, &val, cpu);119			previous_count[num][cpu] = val;120		}121	}122	snb_get_count(TSC, &tsc_at_measure_start, base_cpu);123	return 0;124}125 126static int snb_stop(void)127{128	unsigned long long val;129	int num, cpu;130 131	snb_get_count(TSC, &tsc_at_measure_end, base_cpu);132 133	for (num = 0; num < SNB_CSTATE_COUNT; num++) {134		for (cpu = 0; cpu < cpu_count; cpu++) {135			is_valid[cpu] = !snb_get_count(num, &val, cpu);136			current_count[num][cpu] = val;137		}138	}139	return 0;140}141 142struct cpuidle_monitor intel_snb_monitor;143 144static struct cpuidle_monitor *snb_register(void)145{146	int num;147 148	if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL149	    || cpupower_cpu_info.family != 6)150		return NULL;151 152	switch (cpupower_cpu_info.model) {153	case 0x2A: /* SNB */154	case 0x2D: /* SNB Xeon */155	case 0x3A: /* IVB */156	case 0x3E: /* IVB Xeon */157	case 0x3C: /* HSW */158	case 0x3F: /* HSW */159	case 0x45: /* HSW */160	case 0x46: /* HSW */161		break;162	default:163		return NULL;164	}165 166	is_valid = calloc(cpu_count, sizeof(int));167	for (num = 0; num < SNB_CSTATE_COUNT; num++) {168		previous_count[num] = calloc(cpu_count,169					sizeof(unsigned long long));170		current_count[num]  = calloc(cpu_count,171					sizeof(unsigned long long));172	}173	intel_snb_monitor.name_len = strlen(intel_snb_monitor.name);174	return &intel_snb_monitor;175}176 177void snb_unregister(void)178{179	int num;180	free(is_valid);181	for (num = 0; num < SNB_CSTATE_COUNT; num++) {182		free(previous_count[num]);183		free(current_count[num]);184	}185}186 187struct cpuidle_monitor intel_snb_monitor = {188	.name			= "SandyBridge",189	.hw_states		= snb_cstates,190	.hw_states_num		= SNB_CSTATE_COUNT,191	.start			= snb_start,192	.stop			= snb_stop,193	.do_register		= snb_register,194	.unregister		= snb_unregister,195	.flags.needs_root	= 1,196	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow197					       at 20GHz */198};199#endif /* defined(__i386__) || defined(__x86_64__) */200