Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / tools / power / cpupower / utils / idle_monitor / cpuidle_sysfs.c
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
17 static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
18 struct cpuidle_monitor cpuidle_sysfs_monitor;
19
20 static unsigned long long **previous_count;
21 static unsigned long long **current_count;
22 struct timespec start_time;
23 static unsigned long long timediff;
24
25 static 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
44 static 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
60 static 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
79 void 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__
128 void 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
138 void map_power_idle_state_name(char *tmp) { }
139 #endif
140
141 static 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
191 void 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
203 struct 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         .needs_root             = 0,
211         .overflow_s             = UINT_MAX,
212 };