2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc
4 * Licensed under the terms of the GNU GPL License version 2.
15 #include "helpers/helpers.h"
16 #include "idle_monitor/cpupower-monitor.h"
18 #define CPUIDLE_STATES_MAX 10
19 static cstate_t cpuidle_cstates
[CPUIDLE_STATES_MAX
];
20 struct cpuidle_monitor cpuidle_sysfs_monitor
;
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
;
27 static int cpuidle_get_count_percent(unsigned int id
, double *percent
,
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
);
38 *percent
= ((100.0 * statediff
) / timediff
);
40 dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
41 cpuidle_cstates
[id
].name
, timediff
, statediff
, *percent
, cpu
);
46 static int cpuidle_start(void)
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
;
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
]);
62 static int cpuidle_stop(void)
65 struct timespec end_time
;
66 clock_gettime(CLOCK_REALTIME
, &end_time
);
67 timediff
= timespec_diff_us(start_time
, end_time
);
69 for (cpu
= 0; cpu
< cpu_count
; cpu
++) {
70 for (state
= 0; state
< cpuidle_sysfs_monitor
.hw_states_num
;
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
]);
81 void fix_up_intel_idle_driver_name(char *tmp
, int num
)
83 /* fix up cpuidle name for intel idle driver */
84 if (!strncmp(tmp
, "NHM-", 4)) {
96 } else if (!strncmp(tmp
, "SNB-", 4)) {
111 } else if (!strncmp(tmp
, "ATM-", 4)) {
129 static struct cpuidle_monitor
*cpuidle_register(void)
135 this_cpu
= sched_getcpu();
137 /* Assume idle state count is the same for all CPUs */
138 cpuidle_sysfs_monitor
.hw_states_num
= cpuidle_state_count(this_cpu
);
140 if (cpuidle_sysfs_monitor
.hw_states_num
<= 0)
143 for (num
= 0; num
< cpuidle_sysfs_monitor
.hw_states_num
; num
++) {
144 tmp
= cpuidle_state_name(this_cpu
, num
);
148 fix_up_intel_idle_driver_name(tmp
, num
);
149 strncpy(cpuidle_cstates
[num
].name
, tmp
, CSTATE_NAME_LEN
- 1);
152 tmp
= cpuidle_state_desc(this_cpu
, num
);
155 strncpy(cpuidle_cstates
[num
].desc
, tmp
, CSTATE_DESC_LEN
- 1);
158 cpuidle_cstates
[num
].range
= RANGE_THREAD
;
159 cpuidle_cstates
[num
].id
= num
;
160 cpuidle_cstates
[num
].get_count_percent
=
161 cpuidle_get_count_percent
;
164 /* Free this at program termination */
165 previous_count
= malloc(sizeof(long long *) * cpu_count
);
166 current_count
= malloc(sizeof(long long *) * cpu_count
);
167 for (num
= 0; num
< cpu_count
; num
++) {
168 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
);
174 cpuidle_sysfs_monitor
.name_len
= strlen(cpuidle_sysfs_monitor
.name
);
175 return &cpuidle_sysfs_monitor
;
178 void cpuidle_unregister(void)
182 for (num
= 0; num
< cpu_count
; num
++) {
183 free(previous_count
[num
]);
184 free(current_count
[num
]);
186 free(previous_count
);
190 struct 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
,
198 .overflow_s
= UINT_MAX
,