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};