1 // SPDX-License-Identifier: GPL-2.0-only
3 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc
13 #include "helpers/helpers.h"
14 #include "idle_monitor/cpupower-monitor.h"
16 #define CPUIDLE_STATES_MAX 10
17 static cstate_t cpuidle_cstates
[CPUIDLE_STATES_MAX
];
18 struct cpuidle_monitor cpuidle_sysfs_monitor
;
20 static unsigned long long **previous_count
;
21 static unsigned long long **current_count
;
22 static struct timespec start_time
;
23 static unsigned long long timediff
;
25 static int cpuidle_get_count_percent(unsigned int id
, double *percent
,
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
);
36 *percent
= ((100.0 * statediff
) / timediff
);
38 dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
39 cpuidle_cstates
[id
].name
, timediff
, statediff
, *percent
, cpu
);
44 static int cpuidle_start(void)
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
;
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
]);
60 static int cpuidle_stop(void)
63 struct timespec end_time
;
64 clock_gettime(CLOCK_REALTIME
, &end_time
);
65 timediff
= timespec_diff_us(start_time
, end_time
);
67 for (cpu
= 0; cpu
< cpu_count
; cpu
++) {
68 for (state
= 0; state
< cpuidle_sysfs_monitor
.hw_states_num
;
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
]);
79 void fix_up_intel_idle_driver_name(char *tmp
, int num
)
81 /* fix up cpuidle name for intel idle driver */
82 if (!strncmp(tmp
, "NHM-", 4)) {
94 } else if (!strncmp(tmp
, "SNB-", 4)) {
109 } else if (!strncmp(tmp
, "ATM-", 4)) {
128 void map_power_idle_state_name(char *tmp
)
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");
138 void map_power_idle_state_name(char *tmp
) { }
141 static struct cpuidle_monitor
*cpuidle_register(void)
147 this_cpu
= sched_getcpu();
149 /* Assume idle state count is the same for all CPUs */
150 cpuidle_sysfs_monitor
.hw_states_num
= cpuidle_state_count(this_cpu
);
152 if (cpuidle_sysfs_monitor
.hw_states_num
<= 0)
155 for (num
= 0; num
< cpuidle_sysfs_monitor
.hw_states_num
; num
++) {
156 tmp
= cpuidle_state_name(this_cpu
, num
);
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);
165 tmp
= cpuidle_state_desc(this_cpu
, num
);
168 strncpy(cpuidle_cstates
[num
].desc
, tmp
, CSTATE_DESC_LEN
- 1);
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
;
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
);
187 cpuidle_sysfs_monitor
.name_len
= strlen(cpuidle_sysfs_monitor
.name
);
188 return &cpuidle_sysfs_monitor
;
191 void cpuidle_unregister(void)
195 for (num
= 0; num
< cpu_count
; num
++) {
196 free(previous_count
[num
]);
197 free(current_count
[num
]);
199 free(previous_count
);
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 .flags
.needs_root
= 0,
211 .overflow_s
= UINT_MAX
,