brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 55e55b6 Raw
195 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 SandyBridge monitor. Implements the new package C-states6 *  (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.7 */8 9#if defined(__i386__) || defined(__x86_64__)10 11#include <stdio.h>12#include <stdint.h>13#include <stdlib.h>14#include <string.h>15 16#include "helpers/helpers.h"17#include "idle_monitor/cpupower-monitor.h"18 19#define MSR_PKG_C8_RESIDENCY           0x0000063020#define MSR_PKG_C9_RESIDENCY           0x0000063121#define MSR_PKG_C10_RESIDENCY          0x0000063222 23#define MSR_TSC	0x1024 25enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,26			TSC = 0xFFFF };27 28static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,29				 unsigned int cpu);30 31static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {32	{33		.name			= "PC8",34		.desc			= N_("Processor Package C8"),35		.id			= PC8,36		.range			= RANGE_PACKAGE,37		.get_count_percent	= hsw_ext_get_count_percent,38	},39	{40		.name			= "PC9",41		.desc			= N_("Processor Package C9"),42		.id			= PC9,43		.range			= RANGE_PACKAGE,44		.get_count_percent	= hsw_ext_get_count_percent,45	},46	{47		.name			= "PC10",48		.desc			= N_("Processor Package C10"),49		.id			= PC10,50		.range			= RANGE_PACKAGE,51		.get_count_percent	= hsw_ext_get_count_percent,52	},53};54 55static unsigned long long tsc_at_measure_start;56static unsigned long long tsc_at_measure_end;57static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];58static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];59/* valid flag for all CPUs. If a MSR read failed it will be zero */60static int *is_valid;61 62static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,63			unsigned int cpu)64{65	int msr;66 67	switch (id) {68	case PC8:69		msr = MSR_PKG_C8_RESIDENCY;70		break;71	case PC9:72		msr = MSR_PKG_C9_RESIDENCY;73		break;74	case PC10:75		msr = MSR_PKG_C10_RESIDENCY;76		break;77	case TSC:78		msr = MSR_TSC;79		break;80	default:81		return -1;82	}83	if (read_msr(cpu, msr, val))84		return -1;85	return 0;86}87 88static int hsw_ext_get_count_percent(unsigned int id, double *percent,89				 unsigned int cpu)90{91	*percent = 0.0;92 93	if (!is_valid[cpu])94		return -1;95 96	*percent = (100.0 *97		(current_count[id][cpu] - previous_count[id][cpu])) /98		(tsc_at_measure_end - tsc_at_measure_start);99 100	dprint("%s: previous: %llu - current: %llu - (%u)\n",101		hsw_ext_cstates[id].name, previous_count[id][cpu],102		current_count[id][cpu], cpu);103 104	dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",105	       hsw_ext_cstates[id].name,106	       (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,107	       current_count[id][cpu] - previous_count[id][cpu],108	       *percent, cpu);109 110	return 0;111}112 113static int hsw_ext_start(void)114{115	int num, cpu;116	unsigned long long val;117 118	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {119		for (cpu = 0; cpu < cpu_count; cpu++) {120			hsw_ext_get_count(num, &val, cpu);121			previous_count[num][cpu] = val;122		}123	}124	hsw_ext_get_count(TSC, &tsc_at_measure_start, base_cpu);125	return 0;126}127 128static int hsw_ext_stop(void)129{130	unsigned long long val;131	int num, cpu;132 133	hsw_ext_get_count(TSC, &tsc_at_measure_end, base_cpu);134 135	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {136		for (cpu = 0; cpu < cpu_count; cpu++) {137			is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);138			current_count[num][cpu] = val;139		}140	}141	return 0;142}143 144struct cpuidle_monitor intel_hsw_ext_monitor;145 146static struct cpuidle_monitor *hsw_ext_register(void)147{148	int num;149 150	if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL151	    || cpupower_cpu_info.family != 6)152		return NULL;153 154	switch (cpupower_cpu_info.model) {155	case 0x45: /* HSW */156		break;157	default:158		return NULL;159	}160 161	is_valid = calloc(cpu_count, sizeof(int));162	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {163		previous_count[num] = calloc(cpu_count,164					sizeof(unsigned long long));165		current_count[num]  = calloc(cpu_count,166					sizeof(unsigned long long));167	}168	intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);169	return &intel_hsw_ext_monitor;170}171 172void hsw_ext_unregister(void)173{174	int num;175	free(is_valid);176	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {177		free(previous_count[num]);178		free(current_count[num]);179	}180}181 182struct cpuidle_monitor intel_hsw_ext_monitor = {183	.name			= "HaswellExtended",184	.hw_states		= hsw_ext_cstates,185	.hw_states_num		= HSW_EXT_CSTATE_COUNT,186	.start			= hsw_ext_start,187	.stop			= hsw_ext_stop,188	.do_register		= hsw_ext_register,189	.unregister		= hsw_ext_unregister,190	.flags.needs_root	= 1,191	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow192					       at 20GHz */193};194#endif /* defined(__i386__) || defined(__x86_64__) */195