summaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-12-10 06:30:23 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-12-12 17:22:18 -0500
commit04dab58a39d402162a7effe7278df8cd41557252 (patch)
tree72ef8dca1e3a3d56bf68ce729678c638dd247e8b /drivers/cpuidle
parent9456823c842f346c74265fcd98d008d87a7eb6f5 (diff)
cpuidle: Add 'above' and 'below' idle state metrics
Add two new metrics for CPU idle states, "above" and "below", to count the number of times the given state had been asked for (or entered from the kernel's perspective), but the observed idle duration turned out to be too short or too long for it (respectively). These metrics help to estimate the quality of the CPU idle governor in use. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle.c31
-rw-r--r--drivers/cpuidle/sysfs.c6
2 files changed, 36 insertions, 1 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index f7c58043e50f..7f108309e871 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -202,7 +202,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
202 struct cpuidle_state *target_state = &drv->states[index]; 202 struct cpuidle_state *target_state = &drv->states[index];
203 bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP); 203 bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
204 ktime_t time_start, time_end; 204 ktime_t time_start, time_end;
205 s64 diff;
206 205
207 /* 206 /*
208 * Tell the time framework to switch to a broadcast timer because our 207 * Tell the time framework to switch to a broadcast timer because our
@@ -248,6 +247,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
248 local_irq_enable(); 247 local_irq_enable();
249 248
250 if (entered_state >= 0) { 249 if (entered_state >= 0) {
250 s64 diff, delay = drv->states[entered_state].exit_latency;
251 int i;
252
251 /* 253 /*
252 * Update cpuidle counters 254 * Update cpuidle counters
253 * This can be moved to within driver enter routine, 255 * This can be moved to within driver enter routine,
@@ -260,6 +262,33 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
260 dev->last_residency = (int)diff; 262 dev->last_residency = (int)diff;
261 dev->states_usage[entered_state].time += dev->last_residency; 263 dev->states_usage[entered_state].time += dev->last_residency;
262 dev->states_usage[entered_state].usage++; 264 dev->states_usage[entered_state].usage++;
265
266 if (diff < drv->states[entered_state].target_residency) {
267 for (i = entered_state - 1; i >= 0; i--) {
268 if (drv->states[i].disabled ||
269 dev->states_usage[i].disable)
270 continue;
271
272 /* Shallower states are enabled, so update. */
273 dev->states_usage[entered_state].above++;
274 break;
275 }
276 } else if (diff > delay) {
277 for (i = entered_state + 1; i < drv->state_count; i++) {
278 if (drv->states[i].disabled ||
279 dev->states_usage[i].disable)
280 continue;
281
282 /*
283 * Update if a deeper state would have been a
284 * better match for the observed idle duration.
285 */
286 if (diff - delay >= drv->states[i].target_residency)
287 dev->states_usage[entered_state].below++;
288
289 break;
290 }
291 }
263 } else { 292 } else {
264 dev->last_residency = 0; 293 dev->last_residency = 0;
265 } 294 }
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index e754c7aae7f7..eb20adb5de23 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -301,6 +301,8 @@ define_show_state_str_function(name)
301define_show_state_str_function(desc) 301define_show_state_str_function(desc)
302define_show_state_ull_function(disable) 302define_show_state_ull_function(disable)
303define_store_state_ull_function(disable) 303define_store_state_ull_function(disable)
304define_show_state_ull_function(above)
305define_show_state_ull_function(below)
304 306
305define_one_state_ro(name, show_state_name); 307define_one_state_ro(name, show_state_name);
306define_one_state_ro(desc, show_state_desc); 308define_one_state_ro(desc, show_state_desc);
@@ -310,6 +312,8 @@ define_one_state_ro(power, show_state_power_usage);
310define_one_state_ro(usage, show_state_usage); 312define_one_state_ro(usage, show_state_usage);
311define_one_state_ro(time, show_state_time); 313define_one_state_ro(time, show_state_time);
312define_one_state_rw(disable, show_state_disable, store_state_disable); 314define_one_state_rw(disable, show_state_disable, store_state_disable);
315define_one_state_ro(above, show_state_above);
316define_one_state_ro(below, show_state_below);
313 317
314static struct attribute *cpuidle_state_default_attrs[] = { 318static struct attribute *cpuidle_state_default_attrs[] = {
315 &attr_name.attr, 319 &attr_name.attr,
@@ -320,6 +324,8 @@ static struct attribute *cpuidle_state_default_attrs[] = {
320 &attr_usage.attr, 324 &attr_usage.attr,
321 &attr_time.attr, 325 &attr_time.attr,
322 &attr_disable.attr, 326 &attr_disable.attr,
327 &attr_above.attr,
328 &attr_below.attr,
323 NULL 329 NULL
324}; 330};
325 331