cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cpupower-monitor.c (10491B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
      4 *
      5 *  Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool.
      6 */
      7
      8
      9#include <stdio.h>
     10#include <unistd.h>
     11#include <stdlib.h>
     12#include <string.h>
     13#include <time.h>
     14#include <signal.h>
     15#include <sys/types.h>
     16#include <sys/wait.h>
     17#include <libgen.h>
     18
     19#include "idle_monitor/cpupower-monitor.h"
     20#include "idle_monitor/idle_monitors.h"
     21#include "helpers/helpers.h"
     22
     23/* Define pointers to all monitors.  */
     24#define DEF(x) & x ## _monitor ,
     25struct cpuidle_monitor *all_monitors[] = {
     26#include "idle_monitors.def"
     270
     28};
     29
     30int cpu_count;
     31
     32static struct cpuidle_monitor *monitors[MONITORS_MAX];
     33static unsigned int avail_monitors;
     34
     35static char *progname;
     36
     37enum operation_mode_e { list = 1, show, show_all };
     38static int mode;
     39static int interval = 1;
     40static char *show_monitors_param;
     41static struct cpupower_topology cpu_top;
     42static unsigned int wake_cpus;
     43
     44/* ToDo: Document this in the manpage */
     45static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
     46
     47static void print_wrong_arg_exit(void)
     48{
     49	printf(_("invalid or unknown argument\n"));
     50	exit(EXIT_FAILURE);
     51}
     52
     53long long timespec_diff_us(struct timespec start, struct timespec end)
     54{
     55	struct timespec temp;
     56	if ((end.tv_nsec - start.tv_nsec) < 0) {
     57		temp.tv_sec = end.tv_sec - start.tv_sec - 1;
     58		temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
     59	} else {
     60		temp.tv_sec = end.tv_sec - start.tv_sec;
     61		temp.tv_nsec = end.tv_nsec - start.tv_nsec;
     62	}
     63	return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
     64}
     65
     66void print_n_spaces(int n)
     67{
     68	int x;
     69	for (x = 0; x < n; x++)
     70		printf(" ");
     71}
     72
     73/*s is filled with left and right spaces
     74 *to make its length atleast n+1
     75 */
     76int fill_string_with_spaces(char *s, int n)
     77{
     78	char *temp;
     79	int len = strlen(s);
     80
     81	if (len >= n)
     82		return -1;
     83
     84	temp = malloc(sizeof(char) * (n+1));
     85	for (; len < n; len++)
     86		s[len] = ' ';
     87	s[len] = '\0';
     88	snprintf(temp, n+1, " %s", s);
     89	strcpy(s, temp);
     90	free(temp);
     91	return 0;
     92}
     93
     94#define MAX_COL_WIDTH 6
     95void print_header(int topology_depth)
     96{
     97	int unsigned mon;
     98	int state, need_len;
     99	cstate_t s;
    100	char buf[128] = "";
    101
    102	fill_string_with_spaces(buf, topology_depth * 5 - 1);
    103	printf("%s|", buf);
    104
    105	for (mon = 0; mon < avail_monitors; mon++) {
    106		need_len = monitors[mon]->hw_states_num * (MAX_COL_WIDTH + 1)
    107			- 1;
    108		if (mon != 0)
    109			printf("||");
    110		sprintf(buf, "%s", monitors[mon]->name);
    111		fill_string_with_spaces(buf, need_len);
    112		printf("%s", buf);
    113	}
    114	printf("\n");
    115
    116	if (topology_depth > 2)
    117		printf(" PKG|");
    118	if (topology_depth > 1)
    119		printf("CORE|");
    120	if (topology_depth > 0)
    121		printf(" CPU|");
    122
    123	for (mon = 0; mon < avail_monitors; mon++) {
    124		if (mon != 0)
    125			printf("||");
    126		for (state = 0; state < monitors[mon]->hw_states_num; state++) {
    127			if (state != 0)
    128				printf("|");
    129			s = monitors[mon]->hw_states[state];
    130			sprintf(buf, "%s", s.name);
    131			fill_string_with_spaces(buf, MAX_COL_WIDTH);
    132			printf("%s", buf);
    133		}
    134		printf(" ");
    135	}
    136	printf("\n");
    137}
    138
    139
    140void print_results(int topology_depth, int cpu)
    141{
    142	unsigned int mon;
    143	int state, ret;
    144	double percent;
    145	unsigned long long result;
    146	cstate_t s;
    147
    148	/* Be careful CPUs may got resorted for pkg value do not just use cpu */
    149	if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
    150		return;
    151	if (!cpu_top.core_info[cpu].is_online &&
    152	    cpu_top.core_info[cpu].pkg == -1)
    153		return;
    154
    155	if (topology_depth > 2)
    156		printf("%4d|", cpu_top.core_info[cpu].pkg);
    157	if (topology_depth > 1)
    158		printf("%4d|", cpu_top.core_info[cpu].core);
    159	if (topology_depth > 0)
    160		printf("%4d|", cpu_top.core_info[cpu].cpu);
    161
    162	for (mon = 0; mon < avail_monitors; mon++) {
    163		if (mon != 0)
    164			printf("||");
    165
    166		for (state = 0; state < monitors[mon]->hw_states_num; state++) {
    167			if (state != 0)
    168				printf("|");
    169
    170			s = monitors[mon]->hw_states[state];
    171
    172			if (s.get_count_percent) {
    173				ret = s.get_count_percent(s.id, &percent,
    174						  cpu_top.core_info[cpu].cpu);
    175				if (ret)
    176					printf("******");
    177				else if (percent >= 100.0)
    178					printf("%6.1f", percent);
    179				else
    180					printf("%6.2f", percent);
    181			} else if (s.get_count) {
    182				ret = s.get_count(s.id, &result,
    183						  cpu_top.core_info[cpu].cpu);
    184				if (ret)
    185					printf("******");
    186				else
    187					printf("%6llu", result);
    188			} else {
    189				printf(_("Monitor %s, Counter %s has no count "
    190					 "function. Implementation error\n"),
    191				       monitors[mon]->name, s.name);
    192				exit(EXIT_FAILURE);
    193			}
    194		}
    195	}
    196	/*
    197	 * The monitor could still provide useful data, for example
    198	 * AMD HW counters partly sit in PCI config space.
    199	 * It's up to the monitor plug-in to check .is_online, this one
    200	 * is just for additional info.
    201	 */
    202	if (!cpu_top.core_info[cpu].is_online &&
    203	    cpu_top.core_info[cpu].pkg != -1) {
    204		printf(_(" *is offline\n"));
    205		return;
    206	} else
    207		printf("\n");
    208}
    209
    210
    211/* param: string passed by -m param (The list of monitors to show)
    212 *
    213 * Monitors must have been registered already, matching monitors
    214 * are picked out and available monitors array is overridden
    215 * with matching ones
    216 *
    217 * Monitors get sorted in the same order the user passes them
    218*/
    219
    220static void parse_monitor_param(char *param)
    221{
    222	unsigned int num;
    223	int mon, hits = 0;
    224	char *tmp = param, *token;
    225	struct cpuidle_monitor *tmp_mons[MONITORS_MAX];
    226
    227
    228	for (mon = 0; mon < MONITORS_MAX; mon++, tmp = NULL) {
    229		token = strtok(tmp, ",");
    230		if (token == NULL)
    231			break;
    232		if (strlen(token) >= MONITOR_NAME_LEN) {
    233			printf(_("%s: max monitor name length"
    234				 " (%d) exceeded\n"), token, MONITOR_NAME_LEN);
    235			continue;
    236		}
    237
    238		for (num = 0; num < avail_monitors; num++) {
    239			if (!strcmp(monitors[num]->name, token)) {
    240				dprint("Found requested monitor: %s\n", token);
    241				tmp_mons[hits] = monitors[num];
    242				hits++;
    243			}
    244		}
    245	}
    246	if (hits == 0) {
    247		printf(_("No matching monitor found in %s, "
    248			 "try -l option\n"), param);
    249		exit(EXIT_FAILURE);
    250	}
    251	/* Override detected/registerd monitors array with requested one */
    252	memcpy(monitors, tmp_mons,
    253		sizeof(struct cpuidle_monitor *) * MONITORS_MAX);
    254	avail_monitors = hits;
    255}
    256
    257void list_monitors(void)
    258{
    259	unsigned int mon;
    260	int state;
    261	cstate_t s;
    262
    263	for (mon = 0; mon < avail_monitors; mon++) {
    264		printf(_("Monitor \"%s\" (%d states) - Might overflow after %u "
    265			 "s\n"),
    266			monitors[mon]->name, monitors[mon]->hw_states_num,
    267			monitors[mon]->overflow_s);
    268
    269		for (state = 0; state < monitors[mon]->hw_states_num; state++) {
    270			s = monitors[mon]->hw_states[state];
    271			/*
    272			 * ToDo show more state capabilities:
    273			 * percent, time (granlarity)
    274			 */
    275			printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range],
    276			       gettext(s.desc));
    277		}
    278	}
    279}
    280
    281int fork_it(char **argv)
    282{
    283	int status;
    284	unsigned int num;
    285	unsigned long long timediff;
    286	pid_t child_pid;
    287	struct timespec start, end;
    288
    289	child_pid = fork();
    290	clock_gettime(CLOCK_REALTIME, &start);
    291
    292	for (num = 0; num < avail_monitors; num++)
    293		monitors[num]->start();
    294
    295	if (!child_pid) {
    296		/* child */
    297		execvp(argv[0], argv);
    298	} else {
    299		/* parent */
    300		if (child_pid == -1) {
    301			perror("fork");
    302			exit(1);
    303		}
    304
    305		signal(SIGINT, SIG_IGN);
    306		signal(SIGQUIT, SIG_IGN);
    307		if (waitpid(child_pid, &status, 0) == -1) {
    308			perror("wait");
    309			exit(1);
    310		}
    311	}
    312	clock_gettime(CLOCK_REALTIME, &end);
    313	for (num = 0; num < avail_monitors; num++)
    314		monitors[num]->stop();
    315
    316	timediff = timespec_diff_us(start, end);
    317	if (WIFEXITED(status))
    318		printf(_("%s took %.5f seconds and exited with status %d\n"),
    319			argv[0], timediff / (1000.0 * 1000),
    320			WEXITSTATUS(status));
    321	return 0;
    322}
    323
    324int do_interval_measure(int i)
    325{
    326	unsigned int num;
    327	int cpu;
    328
    329	if (wake_cpus)
    330		for (cpu = 0; cpu < cpu_count; cpu++)
    331			bind_cpu(cpu);
    332
    333	for (num = 0; num < avail_monitors; num++) {
    334		dprint("HW C-state residency monitor: %s - States: %d\n",
    335		       monitors[num]->name, monitors[num]->hw_states_num);
    336		monitors[num]->start();
    337	}
    338
    339	sleep(i);
    340
    341	if (wake_cpus)
    342		for (cpu = 0; cpu < cpu_count; cpu++)
    343			bind_cpu(cpu);
    344
    345	for (num = 0; num < avail_monitors; num++)
    346		monitors[num]->stop();
    347
    348
    349	return 0;
    350}
    351
    352static void cmdline(int argc, char *argv[])
    353{
    354	int opt;
    355	progname = basename(argv[0]);
    356
    357	while ((opt = getopt(argc, argv, "+lci:m:")) != -1) {
    358		switch (opt) {
    359		case 'l':
    360			if (mode)
    361				print_wrong_arg_exit();
    362			mode = list;
    363			break;
    364		case 'i':
    365			/* only allow -i with -m or no option */
    366			if (mode && mode != show)
    367				print_wrong_arg_exit();
    368			interval = atoi(optarg);
    369			break;
    370		case 'm':
    371			if (mode)
    372				print_wrong_arg_exit();
    373			mode = show;
    374			show_monitors_param = optarg;
    375			break;
    376		case 'c':
    377			wake_cpus = 1;
    378			break;
    379		default:
    380			print_wrong_arg_exit();
    381		}
    382	}
    383	if (!mode)
    384		mode = show_all;
    385}
    386
    387int cmd_monitor(int argc, char **argv)
    388{
    389	unsigned int num;
    390	struct cpuidle_monitor *test_mon;
    391	int cpu;
    392
    393	cmdline(argc, argv);
    394	cpu_count = get_cpu_topology(&cpu_top);
    395	if (cpu_count < 0) {
    396		printf(_("Cannot read number of available processors\n"));
    397		return EXIT_FAILURE;
    398	}
    399
    400	if (!cpu_top.core_info[0].is_online)
    401		printf("WARNING: at least one cpu is offline\n");
    402
    403	/* Default is: monitor all CPUs */
    404	if (bitmask_isallclear(cpus_chosen))
    405		bitmask_setall(cpus_chosen);
    406
    407	dprint("System has up to %d CPU cores\n", cpu_count);
    408
    409	for (num = 0; all_monitors[num]; num++) {
    410		dprint("Try to register: %s\n", all_monitors[num]->name);
    411		test_mon = all_monitors[num]->do_register();
    412		if (test_mon) {
    413			if (test_mon->flags.needs_root && !run_as_root) {
    414				fprintf(stderr, _("Available monitor %s needs "
    415					  "root access\n"), test_mon->name);
    416				continue;
    417			}
    418			monitors[avail_monitors] = test_mon;
    419			dprint("%s registered\n", all_monitors[num]->name);
    420			avail_monitors++;
    421		}
    422	}
    423
    424	if (avail_monitors == 0) {
    425		printf(_("No HW Cstate monitors found\n"));
    426		return 1;
    427	}
    428
    429	if (mode == list) {
    430		list_monitors();
    431		exit(EXIT_SUCCESS);
    432	}
    433
    434	if (mode == show)
    435		parse_monitor_param(show_monitors_param);
    436
    437	dprint("Packages: %d - Cores: %d - CPUs: %d\n",
    438	       cpu_top.pkgs, cpu_top.cores, cpu_count);
    439
    440	/*
    441	 * if any params left, it must be a command to fork
    442	 */
    443	if (argc - optind)
    444		fork_it(argv + optind);
    445	else
    446		do_interval_measure(interval);
    447
    448	/* ToDo: Topology parsing needs fixing first to do
    449	   this more generically */
    450	if (cpu_top.pkgs > 1)
    451		print_header(3);
    452	else
    453		print_header(1);
    454
    455	for (cpu = 0; cpu < cpu_count; cpu++) {
    456		if (cpu_top.pkgs > 1)
    457			print_results(3, cpu);
    458		else
    459			print_results(1, cpu);
    460	}
    461
    462	for (num = 0; num < avail_monitors; num++)
    463		monitors[num]->unregister();
    464
    465	cpu_topology_release(cpu_top);
    466	return 0;
    467}