Merge tag 'pm-fixes-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[sfrench/cifs-2.6.git] / tools / power / cpupower / utils / idle_monitor / cpuidle_sysfs.c
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 #include <cpuidle.h>
14
15 #include "helpers/helpers.h"
16 #include "idle_monitor/cpupower-monitor.h"
17
18 #define CPUIDLE_STATES_MAX 10
19 static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
20 struct cpuidle_monitor cpuidle_sysfs_monitor;
21
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;
26
27 static 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
46 static 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                                 cpuidle_state_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
62 static 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                                 cpuidle_state_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
81 void 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
129 static 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 = cpuidle_state_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 = cpuidle_state_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 = cpuidle_state_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
175 void 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
187 struct 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 };