Linux Audio

Check our new training course

Loading...
  1/*
  2 *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
  3 *
  4 *  Licensed under the terms of the GNU GPL License version 2.
  5 *
  6 */
  7
  8#include <stdio.h>
  9#include <stdlib.h>
 10#include <stdint.h>
 11#include <string.h>
 12#include <limits.h>
 13
 14#include "helpers/sysfs.h"
 15#include "helpers/helpers.h"
 16#include "idle_monitor/cpupower-monitor.h"
 17
 18#define CPUIDLE_STATES_MAX 10
 19static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
 20struct cpuidle_monitor cpuidle_sysfs_monitor;
 21
 22static unsigned long long **previous_count;
 23static unsigned long long **current_count;
 24struct timespec start_time;
 25static unsigned long long timediff;
 26
 27static int cpuidle_get_count_percent(unsigned int id, double *percent,
 28				     unsigned int cpu)
 29{
 30	unsigned long long statediff = current_count[cpu][id]
 31		- previous_count[cpu][id];
 32	dprint("%s: - diff: %llu - percent: %f (%u)\n",
 33	       cpuidle_cstates[id].name, timediff, *percent, cpu);
 34
 35	if (timediff == 0)
 36		*percent = 0.0;
 37	else
 38		*percent = ((100.0 * statediff) / timediff);
 39
 40	dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
 41	       cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
 42
 43	return 0;
 44}
 45
 46static int cpuidle_start(void)
 47{
 48	int cpu, state;
 49	clock_gettime(CLOCK_REALTIME, &start_time);
 50	for (cpu = 0; cpu < cpu_count; cpu++) {
 51		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
 52		     state++) {
 53			previous_count[cpu][state] =
 54				sysfs_get_idlestate_time(cpu, state);
 55			dprint("CPU %d - State: %d - Val: %llu\n",
 56			       cpu, state, previous_count[cpu][state]);
 57		}
 58	};
 59	return 0;
 60}
 61
 62static int cpuidle_stop(void)
 63{
 64	int cpu, state;
 65	struct timespec end_time;
 66	clock_gettime(CLOCK_REALTIME, &end_time);
 67	timediff = timespec_diff_us(start_time, end_time);
 68
 69	for (cpu = 0; cpu < cpu_count; cpu++) {
 70		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
 71		     state++) {
 72			current_count[cpu][state] =
 73				sysfs_get_idlestate_time(cpu, state);
 74			dprint("CPU %d - State: %d - Val: %llu\n",
 75			       cpu, state, previous_count[cpu][state]);
 76		}
 77	};
 78	return 0;
 79}
 80
 81void fix_up_intel_idle_driver_name(char *tmp, int num)
 82{
 83	/* fix up cpuidle name for intel idle driver */
 84	if (!strncmp(tmp, "NHM-", 4)) {
 85		switch (num) {
 86		case 1:
 87			strcpy(tmp, "C1");
 88			break;
 89		case 2:
 90			strcpy(tmp, "C3");
 91			break;
 92		case 3:
 93			strcpy(tmp, "C6");
 94			break;
 95		}
 96	} else if (!strncmp(tmp, "SNB-", 4)) {
 97		switch (num) {
 98		case 1:
 99			strcpy(tmp, "C1");
100			break;
101		case 2:
102			strcpy(tmp, "C3");
103			break;
104		case 3:
105			strcpy(tmp, "C6");
106			break;
107		case 4:
108			strcpy(tmp, "C7");
109			break;
110		}
111	} else if (!strncmp(tmp, "ATM-", 4)) {
112		switch (num) {
113		case 1:
114			strcpy(tmp, "C1");
115			break;
116		case 2:
117			strcpy(tmp, "C2");
118			break;
119		case 3:
120			strcpy(tmp, "C4");
121			break;
122		case 4:
123			strcpy(tmp, "C6");
124			break;
125		}
126	}
127}
128
129static struct cpuidle_monitor *cpuidle_register(void)
130{
131	int num;
132	char *tmp;
133
134	/* Assume idle state count is the same for all CPUs */
135	cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
136
137	if (cpuidle_sysfs_monitor.hw_states_num <= 0)
138		return NULL;
139
140	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
141		tmp = sysfs_get_idlestate_name(0, num);
142		if (tmp == NULL)
143			continue;
144
145		fix_up_intel_idle_driver_name(tmp, num);
146		strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
147		free(tmp);
148
149		tmp = sysfs_get_idlestate_desc(0, num);
150		if (tmp == NULL)
151			continue;
152		strncpy(cpuidle_cstates[num].desc, tmp,	CSTATE_DESC_LEN - 1);
153		free(tmp);
154
155		cpuidle_cstates[num].range = RANGE_THREAD;
156		cpuidle_cstates[num].id = num;
157		cpuidle_cstates[num].get_count_percent =
158			cpuidle_get_count_percent;
159	};
160
161	/* Free this at program termination */
162	previous_count = malloc(sizeof(long long *) * cpu_count);
163	current_count = malloc(sizeof(long long *) * cpu_count);
164	for (num = 0; num < cpu_count; num++) {
165		previous_count[num] = malloc(sizeof(long long) *
166					cpuidle_sysfs_monitor.hw_states_num);
167		current_count[num] = malloc(sizeof(long long) *
168					cpuidle_sysfs_monitor.hw_states_num);
169	}
170
171	cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
172	return &cpuidle_sysfs_monitor;
173}
174
175void cpuidle_unregister(void)
176{
177	int num;
178
179	for (num = 0; num < cpu_count; num++) {
180		free(previous_count[num]);
181		free(current_count[num]);
182	}
183	free(previous_count);
184	free(current_count);
185}
186
187struct cpuidle_monitor cpuidle_sysfs_monitor = {
188	.name			= "Idle_Stats",
189	.hw_states		= cpuidle_cstates,
190	.start			= cpuidle_start,
191	.stop			= cpuidle_stop,
192	.do_register		= cpuidle_register,
193	.unregister		= cpuidle_unregister,
194	.needs_root		= 0,
195	.overflow_s		= UINT_MAX,
196};
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
  4 */
  5
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <stdint.h>
  9#include <string.h>
 10#include <limits.h>
 11#include <cpuidle.h>
 12
 13#include "helpers/helpers.h"
 14#include "idle_monitor/cpupower-monitor.h"
 15
 16#define CPUIDLE_STATES_MAX 10
 17static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
 18struct cpuidle_monitor cpuidle_sysfs_monitor;
 19
 20static unsigned long long **previous_count;
 21static unsigned long long **current_count;
 22static struct timespec start_time;
 23static unsigned long long timediff;
 24
 25static int cpuidle_get_count_percent(unsigned int id, double *percent,
 26				     unsigned int cpu)
 27{
 28	unsigned long long statediff = current_count[cpu][id]
 29		- previous_count[cpu][id];
 30	dprint("%s: - diff: %llu - percent: %f (%u)\n",
 31	       cpuidle_cstates[id].name, timediff, *percent, cpu);
 32
 33	if (timediff == 0)
 34		*percent = 0.0;
 35	else
 36		*percent = ((100.0 * statediff) / timediff);
 37
 38	dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
 39	       cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
 40
 41	return 0;
 42}
 43
 44static int cpuidle_start(void)
 45{
 46	int cpu, state;
 47	clock_gettime(CLOCK_REALTIME, &start_time);
 48	for (cpu = 0; cpu < cpu_count; cpu++) {
 49		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
 50		     state++) {
 51			previous_count[cpu][state] =
 52				cpuidle_state_time(cpu, state);
 53			dprint("CPU %d - State: %d - Val: %llu\n",
 54			       cpu, state, previous_count[cpu][state]);
 55		}
 56	}
 57	return 0;
 58}
 59
 60static int cpuidle_stop(void)
 61{
 62	int cpu, state;
 63	struct timespec end_time;
 64	clock_gettime(CLOCK_REALTIME, &end_time);
 65	timediff = timespec_diff_us(start_time, end_time);
 66
 67	for (cpu = 0; cpu < cpu_count; cpu++) {
 68		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
 69		     state++) {
 70			current_count[cpu][state] =
 71				cpuidle_state_time(cpu, state);
 72			dprint("CPU %d - State: %d - Val: %llu\n",
 73			       cpu, state, previous_count[cpu][state]);
 74		}
 75	}
 76	return 0;
 77}
 78
 79void fix_up_intel_idle_driver_name(char *tmp, int num)
 80{
 81	/* fix up cpuidle name for intel idle driver */
 82	if (!strncmp(tmp, "NHM-", 4)) {
 83		switch (num) {
 84		case 1:
 85			strcpy(tmp, "C1");
 86			break;
 87		case 2:
 88			strcpy(tmp, "C3");
 89			break;
 90		case 3:
 91			strcpy(tmp, "C6");
 92			break;
 93		}
 94	} else if (!strncmp(tmp, "SNB-", 4)) {
 95		switch (num) {
 96		case 1:
 97			strcpy(tmp, "C1");
 98			break;
 99		case 2:
100			strcpy(tmp, "C3");
101			break;
102		case 3:
103			strcpy(tmp, "C6");
104			break;
105		case 4:
106			strcpy(tmp, "C7");
107			break;
108		}
109	} else if (!strncmp(tmp, "ATM-", 4)) {
110		switch (num) {
111		case 1:
112			strcpy(tmp, "C1");
113			break;
114		case 2:
115			strcpy(tmp, "C2");
116			break;
117		case 3:
118			strcpy(tmp, "C4");
119			break;
120		case 4:
121			strcpy(tmp, "C6");
122			break;
123		}
124	}
125}
126
127#ifdef __powerpc__
128void map_power_idle_state_name(char *tmp)
129{
130	if (!strncmp(tmp, "stop0_lite", CSTATE_NAME_LEN))
131		strcpy(tmp, "stop0L");
132	else if (!strncmp(tmp, "stop1_lite", CSTATE_NAME_LEN))
133		strcpy(tmp, "stop1L");
134	else if (!strncmp(tmp, "stop2_lite", CSTATE_NAME_LEN))
135		strcpy(tmp, "stop2L");
136}
137#else
138void map_power_idle_state_name(char *tmp) { }
139#endif
140
141static struct cpuidle_monitor *cpuidle_register(void)
142{
143	int num;
144	char *tmp;
145	int this_cpu;
146
147	this_cpu = sched_getcpu();
148
149	/* Assume idle state count is the same for all CPUs */
150	cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu);
151
152	if (cpuidle_sysfs_monitor.hw_states_num <= 0)
153		return NULL;
154
155	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
156		tmp = cpuidle_state_name(this_cpu, num);
157		if (tmp == NULL)
158			continue;
159
160		map_power_idle_state_name(tmp);
161		fix_up_intel_idle_driver_name(tmp, num);
162		strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
163		free(tmp);
164
165		tmp = cpuidle_state_desc(this_cpu, num);
166		if (tmp == NULL)
167			continue;
168		strncpy(cpuidle_cstates[num].desc, tmp,	CSTATE_DESC_LEN - 1);
169		free(tmp);
170
171		cpuidle_cstates[num].range = RANGE_THREAD;
172		cpuidle_cstates[num].id = num;
173		cpuidle_cstates[num].get_count_percent =
174			cpuidle_get_count_percent;
175	}
176
177	/* Free this at program termination */
178	previous_count = malloc(sizeof(long long *) * cpu_count);
179	current_count = malloc(sizeof(long long *) * cpu_count);
180	for (num = 0; num < cpu_count; num++) {
181		previous_count[num] = malloc(sizeof(long long) *
182					cpuidle_sysfs_monitor.hw_states_num);
183		current_count[num] = malloc(sizeof(long long) *
184					cpuidle_sysfs_monitor.hw_states_num);
185	}
186
187	cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
188	return &cpuidle_sysfs_monitor;
189}
190
191void cpuidle_unregister(void)
192{
193	int num;
194
195	for (num = 0; num < cpu_count; num++) {
196		free(previous_count[num]);
197		free(current_count[num]);
198	}
199	free(previous_count);
200	free(current_count);
201}
202
203struct cpuidle_monitor cpuidle_sysfs_monitor = {
204	.name			= "Idle_Stats",
205	.hw_states		= cpuidle_cstates,
206	.start			= cpuidle_start,
207	.stop			= cpuidle_stop,
208	.do_register		= cpuidle_register,
209	.unregister		= cpuidle_unregister,
210	.flags.needs_root	= 0,
211	.overflow_s		= UINT_MAX,
212};