blob: 5b3205f1621749bb6ebc340413ae16d957064cb9 [file] [log] [blame]
Dominik Brodowski7fe2f632011-03-30 16:30:11 +02001/*
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>
Thomas Renningerac5a1812016-04-28 15:24:40 +020013#include <cpuidle.h>
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020014
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020015#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);
Dominik Brodowskib510b542011-04-19 19:58:59 +020039
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020040 dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
41 cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
Dominik Brodowskib510b542011-04-19 19:58:59 +020042
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020043 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] =
Thomas Renningerac5a1812016-04-28 15:24:40 +020054 cpuidle_state_time(cpu, state);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020055 dprint("CPU %d - State: %d - Val: %llu\n",
56 cpu, state, previous_count[cpu][state]);
57 }
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020058 };
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] =
Thomas Renningerac5a1812016-04-28 15:24:40 +020073 cpuidle_state_time(cpu, state);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020074 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)) {
Dominik Brodowskib510b542011-04-19 19:58:59 +020085 switch (num) {
86 case 1:
87 strcpy(tmp, "C1");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020088 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +020089 case 2:
90 strcpy(tmp, "C3");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020091 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +020092 case 3:
93 strcpy(tmp, "C6");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +020094 break;
95 }
96 } else if (!strncmp(tmp, "SNB-", 4)) {
Dominik Brodowskib510b542011-04-19 19:58:59 +020097 switch (num) {
98 case 1:
99 strcpy(tmp, "C1");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200100 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200101 case 2:
102 strcpy(tmp, "C3");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200103 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200104 case 3:
105 strcpy(tmp, "C6");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200106 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200107 case 4:
108 strcpy(tmp, "C7");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200109 break;
110 }
111 } else if (!strncmp(tmp, "ATM-", 4)) {
Dominik Brodowskib510b542011-04-19 19:58:59 +0200112 switch (num) {
113 case 1:
114 strcpy(tmp, "C1");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200115 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200116 case 2:
117 strcpy(tmp, "C2");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200118 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200119 case 3:
120 strcpy(tmp, "C4");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200121 break;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200122 case 4:
123 strcpy(tmp, "C6");
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200124 break;
125 }
126 }
127}
128
Dominik Brodowskib510b542011-04-19 19:58:59 +0200129static struct cpuidle_monitor *cpuidle_register(void)
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200130{
131 int num;
132 char *tmp;
Abhishek Goeld8f75b42017-11-15 14:10:02 +0530133 int this_cpu;
134
135 this_cpu = sched_getcpu();
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200136
137 /* Assume idle state count is the same for all CPUs */
Abhishek Goeld8f75b42017-11-15 14:10:02 +0530138 cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200139
Thomas Renninger88f984e2011-08-12 01:11:36 +0200140 if (cpuidle_sysfs_monitor.hw_states_num <= 0)
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200141 return NULL;
142
Dominik Brodowskib510b542011-04-19 19:58:59 +0200143 for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
Abhishek Goeld8f75b42017-11-15 14:10:02 +0530144 tmp = cpuidle_state_name(this_cpu, num);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200145 if (tmp == NULL)
146 continue;
147
148 fix_up_intel_idle_driver_name(tmp, num);
149 strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
150 free(tmp);
151
Abhishek Goeld8f75b42017-11-15 14:10:02 +0530152 tmp = cpuidle_state_desc(this_cpu, num);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200153 if (tmp == NULL)
154 continue;
155 strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
156 free(tmp);
157
158 cpuidle_cstates[num].range = RANGE_THREAD;
159 cpuidle_cstates[num].id = num;
Dominik Brodowskib510b542011-04-19 19:58:59 +0200160 cpuidle_cstates[num].get_count_percent =
161 cpuidle_get_count_percent;
162 };
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200163
164 /* Free this at program termination */
Dominik Brodowskib510b542011-04-19 19:58:59 +0200165 previous_count = malloc(sizeof(long long *) * cpu_count);
166 current_count = malloc(sizeof(long long *) * cpu_count);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200167 for (num = 0; num < cpu_count; num++) {
Dominik Brodowskib510b542011-04-19 19:58:59 +0200168 previous_count[num] = malloc(sizeof(long long) *
169 cpuidle_sysfs_monitor.hw_states_num);
170 current_count[num] = malloc(sizeof(long long) *
171 cpuidle_sysfs_monitor.hw_states_num);
Dominik Brodowski7fe2f632011-03-30 16:30:11 +0200172 }
173
174 cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
175 return &cpuidle_sysfs_monitor;
176}
177
178void cpuidle_unregister(void)
179{
180 int num;
181
182 for (num = 0; num < cpu_count; num++) {
183 free(previous_count[num]);
184 free(current_count[num]);
185 }
186 free(previous_count);
187 free(current_count);
188}
189
190struct cpuidle_monitor cpuidle_sysfs_monitor = {
191 .name = "Idle_Stats",
192 .hw_states = cpuidle_cstates,
193 .start = cpuidle_start,
194 .stop = cpuidle_stop,
195 .do_register = cpuidle_register,
196 .unregister = cpuidle_unregister,
197 .needs_root = 0,
198 .overflow_s = UINT_MAX,
199};