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)
134 /* Assume idle state count is the same for all CPUs */
135 cpuidle_sysfs_monitor
.hw_states_num
= cpuidle_state_count(0);
137 if (cpuidle_sysfs_monitor
.hw_states_num
<= 0)
140 for (num
= 0; num
< cpuidle_sysfs_monitor
.hw_states_num
; num
++) {
141 tmp
= cpuidle_state_name(0, num
);
145 fix_up_intel_idle_driver_name(tmp
, num
);
146 strncpy(cpuidle_cstates
[num
].name
, tmp
, CSTATE_NAME_LEN
- 1);
149 tmp
= cpuidle_state_desc(0, num
);
152 strncpy(cpuidle_cstates
[num
].desc
, tmp
, CSTATE_DESC_LEN
- 1);
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
;
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
);
171 cpuidle_sysfs_monitor
.name_len
= strlen(cpuidle_sysfs_monitor
.name
);
172 return &cpuidle_sysfs_monitor
;
175 void cpuidle_unregister(void)
179 for (num
= 0; num
< cpu_count
; num
++) {
180 free(previous_count
[num
]);
181 free(current_count
[num
]);
183 free(previous_count
);
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
,
195 .overflow_s
= UINT_MAX
,