2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc
4 * Licensed under the terms of the GNU GPL License version 2.
14 #include "helpers/sysfs.h"
15 #include "helpers/helpers.h"
16 #include "idle_monitor/cpupower-monitor.h"
18 #define CPUIDLE_STATES_MAX 10
19 static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
20 struct cpuidle_monitor cpuidle_sysfs_monitor;
22 static unsigned long long **previous_count;
23 static unsigned long long **current_count;
24 struct timespec start_time;
25 static unsigned long long timediff;
27 static int cpuidle_get_count_percent(unsigned int id, double *percent,
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);
38 *percent = ((100.0 * statediff) / timediff);
40 dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
41 cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
46 static int cpuidle_start(void)
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;
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]);
63 static int cpuidle_stop(void)
66 struct timespec end_time;
67 clock_gettime(CLOCK_REALTIME, &end_time);
68 timediff = timespec_diff_us(start_time, end_time);
70 for (cpu = 0; cpu < cpu_count; cpu++) {
71 for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
73 current_count[cpu][state] =
74 sysfs_get_idlestate_time(cpu, state);
75 dprint("CPU %d - State: %d - Val: %llu\n",
76 cpu, state, previous_count[cpu][state]);
82 void fix_up_intel_idle_driver_name(char *tmp, int num)
84 /* fix up cpuidle name for intel idle driver */
85 if (!strncmp(tmp, "NHM-", 4)) {
87 case 1: strcpy(tmp, "C1");
89 case 2: strcpy(tmp, "C3");
91 case 3: strcpy(tmp, "C6");
94 } else if (!strncmp(tmp, "SNB-", 4)) {
96 case 1: strcpy(tmp, "C1");
98 case 2: strcpy(tmp, "C3");
100 case 3: strcpy(tmp, "C6");
102 case 4: strcpy(tmp, "C7");
105 } else if (!strncmp(tmp, "ATM-", 4)) {
107 case 1: strcpy(tmp, "C1");
109 case 2: strcpy(tmp, "C2");
111 case 3: strcpy(tmp, "C4");
113 case 4: strcpy(tmp, "C6");
119 static struct cpuidle_monitor* cpuidle_register(void)
124 /* Assume idle state count is the same for all CPUs */
125 cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
127 if (cpuidle_sysfs_monitor.hw_states_num == 0)
130 for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num ++) {
131 tmp = sysfs_get_idlestate_name(0, num);
135 fix_up_intel_idle_driver_name(tmp, num);
136 strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
139 tmp = sysfs_get_idlestate_desc(0, num);
142 strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
145 cpuidle_cstates[num].range = RANGE_THREAD;
146 cpuidle_cstates[num].id = num;
147 cpuidle_cstates[num].get_count_percent = cpuidle_get_count_percent;
150 /* Free this at program termination */
151 previous_count = malloc(sizeof (long long*) * cpu_count);
152 current_count = malloc(sizeof (long long*) * cpu_count);
153 for (num = 0; num < cpu_count; num++) {
154 previous_count[num] = malloc (sizeof(long long) *
155 cpuidle_sysfs_monitor.hw_states_num);
156 current_count[num] = malloc (sizeof(long long) *
157 cpuidle_sysfs_monitor.hw_states_num);
160 cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
161 return &cpuidle_sysfs_monitor;
164 void cpuidle_unregister(void)
168 for (num = 0; num < cpu_count; num++) {
169 free(previous_count[num]);
170 free(current_count[num]);
172 free(previous_count);
176 struct cpuidle_monitor cpuidle_sysfs_monitor = {
177 .name = "Idle_Stats",
178 .hw_states = cpuidle_cstates,
179 .start = cpuidle_start,
180 .stop = cpuidle_stop,
181 .do_register = cpuidle_register,
182 .unregister = cpuidle_unregister,
184 .overflow_s = UINT_MAX,