@@ -306,15 +306,10 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
306306 cpu_data -> total += PULSE ;
307307}
308308
309- static bool teo_time_ok ( u64 interval_ns )
309+ static bool teo_state_ok ( int i , struct cpuidle_driver * drv )
310310{
311- return !tick_nohz_tick_stopped () || interval_ns >= TICK_NSEC ;
312- }
313-
314- static s64 teo_middle_of_bin (int idx , struct cpuidle_driver * drv )
315- {
316- return (drv -> states [idx ].target_residency_ns +
317- drv -> states [idx + 1 ].target_residency_ns ) / 2 ;
311+ return !tick_nohz_tick_stopped () ||
312+ drv -> states [i ].target_residency_ns >= TICK_NSEC ;
318313}
319314
320315/**
@@ -354,6 +349,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
354349{
355350 struct teo_cpu * cpu_data = per_cpu_ptr (& teo_cpus , dev -> cpu );
356351 s64 latency_req = cpuidle_governor_latency_req (dev -> cpu );
352+ ktime_t delta_tick = TICK_NSEC / 2 ;
357353 unsigned int idx_intercept_sum = 0 ;
358354 unsigned int intercept_sum = 0 ;
359355 unsigned int idx_recent_sum = 0 ;
@@ -363,7 +359,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
363359 int constraint_idx = 0 ;
364360 int idx0 = 0 , idx = -1 ;
365361 bool alt_intercepts , alt_recent ;
366- ktime_t delta_tick ;
367362 bool cpu_utilized ;
368363 s64 duration_ns ;
369364 int i ;
@@ -374,21 +369,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
374369 }
375370
376371 cpu_data -> time_span_ns = local_clock ();
377-
378- duration_ns = tick_nohz_get_sleep_length (& delta_tick );
379- cpu_data -> sleep_length_ns = duration_ns ;
372+ /*
373+ * Set the expected sleep length to infinity in case of an early
374+ * return.
375+ */
376+ cpu_data -> sleep_length_ns = KTIME_MAX ;
380377
381378 /* Check if there is any choice in the first place. */
382379 if (drv -> state_count < 2 ) {
383380 idx = 0 ;
384381 goto out_tick ;
385382 }
386383
387- if (!dev -> states_usage [0 ].disable ) {
384+ if (!dev -> states_usage [0 ].disable )
388385 idx = 0 ;
389- if (drv -> states [1 ].target_residency_ns > duration_ns )
390- goto out_tick ;
391- }
392386
393387 cpu_utilized = teo_cpu_is_utilized (dev -> cpu , cpu_data );
394388 /*
@@ -397,8 +391,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
397391 * the shallowest non-polling state and exit.
398392 */
399393 if (drv -> state_count < 3 && cpu_utilized ) {
400- /* The CPU is utilized, so assume a short idle duration. */
401- duration_ns = teo_middle_of_bin (0 , drv );
402394 /*
403395 * If state 0 is enabled and it is not a polling one, select it
404396 * right away unless the scheduler tick has been stopped, in
@@ -408,22 +400,17 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
408400 * anyway.
409401 */
410402 if ((!idx && !(drv -> states [0 ].flags & CPUIDLE_FLAG_POLLING ) &&
411- teo_time_ok ( duration_ns )) || dev -> states_usage [1 ].disable ) {
403+ teo_state_ok ( 0 , drv )) || dev -> states_usage [1 ].disable ) {
412404 idx = 0 ;
413405 goto out_tick ;
414406 }
415407 /* Assume that state 1 is not a polling one and use it. */
416408 idx = 1 ;
409+ duration_ns = drv -> states [1 ].target_residency_ns ;
417410 goto end ;
418411 }
419412
420- /*
421- * Find the deepest idle state whose target residency does not exceed
422- * the current sleep length and the deepest idle state not deeper than
423- * the former whose exit latency does not exceed the current latency
424- * constraint. Compute the sums of metrics for early wakeup pattern
425- * detection.
426- */
413+ /* Compute the sums of metrics for early wakeup pattern detection. */
427414 for (i = 1 ; i < drv -> state_count ; i ++ ) {
428415 struct teo_bin * prev_bin = & cpu_data -> state_bins [i - 1 ];
429416 struct cpuidle_state * s = & drv -> states [i ];
@@ -439,19 +426,15 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
439426 if (dev -> states_usage [i ].disable )
440427 continue ;
441428
442- if (idx < 0 ) {
443- idx = i ; /* first enabled state */
444- idx0 = i ;
445- }
446-
447- if (s -> target_residency_ns > duration_ns )
448- break ;
429+ if (idx < 0 )
430+ idx0 = i ; /* first enabled state */
449431
450432 idx = i ;
451433
452434 if (s -> exit_latency_ns <= latency_req )
453435 constraint_idx = i ;
454436
437+ /* Save the sums for the current state. */
455438 idx_intercept_sum = intercept_sum ;
456439 idx_hit_sum = hit_sum ;
457440 idx_recent_sum = recent_sum ;
@@ -465,7 +448,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
465448
466449 if (idx == idx0 ) {
467450 /*
468- * This is the first enabled idle state, so use it, but do not
451+ * Only one idle state is enabled , so use it, but do not
469452 * allow the tick to be stopped it is shallow enough.
470453 */
471454 duration_ns = drv -> states [idx ].target_residency_ns ;
@@ -479,13 +462,11 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
479462 * all of the deeper states, or the sum of the numbers of recent
480463 * intercepts over all of the states shallower than the candidate one
481464 * is greater than a half of the number of recent events taken into
482- * account, the CPU is likely to wake up early, so find an alternative
483- * idle state to select.
465+ * account, a shallower idle state is likely to be a better choice.
484466 */
485467 alt_intercepts = 2 * idx_intercept_sum > cpu_data -> total - idx_hit_sum ;
486468 alt_recent = idx_recent_sum > NR_RECENT / 2 ;
487469 if (alt_recent || alt_intercepts ) {
488- s64 first_suitable_span_ns = duration_ns ;
489470 int first_suitable_idx = idx ;
490471
491472 /*
@@ -494,44 +475,39 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
494475 * cases (both with respect to intercepts overall and with
495476 * respect to the recent intercepts only) in the past.
496477 *
497- * Take the possible latency constraint and duration limitation
498- * present if the tick has been stopped already into account.
478+ * Take the possible duration limitation present if the tick
479+ * has been stopped already into account.
499480 */
500481 intercept_sum = 0 ;
501482 recent_sum = 0 ;
502483
503484 for (i = idx - 1 ; i >= 0 ; i -- ) {
504485 struct teo_bin * bin = & cpu_data -> state_bins [i ];
505- s64 span_ns ;
506486
507487 intercept_sum += bin -> intercepts ;
508488 recent_sum += bin -> recent ;
509489
510- span_ns = teo_middle_of_bin (i , drv );
511-
512490 if ((!alt_recent || 2 * recent_sum > idx_recent_sum ) &&
513491 (!alt_intercepts ||
514492 2 * intercept_sum > idx_intercept_sum )) {
515- if (teo_time_ok (span_ns ) &&
516- !dev -> states_usage [i ].disable ) {
493+ /*
494+ * Use the current state unless it is too
495+ * shallow or disabled, in which case take the
496+ * first enabled state that is deep enough.
497+ */
498+ if (teo_state_ok (i , drv ) &&
499+ !dev -> states_usage [i ].disable )
517500 idx = i ;
518- duration_ns = span_ns ;
519- } else {
520- /*
521- * The current state is too shallow or
522- * disabled, so take the first enabled
523- * deeper state with suitable time span.
524- */
501+ else
525502 idx = first_suitable_idx ;
526- duration_ns = first_suitable_span_ns ;
527- }
503+
528504 break ;
529505 }
530506
531507 if (dev -> states_usage [i ].disable )
532508 continue ;
533509
534- if (!teo_time_ok ( span_ns )) {
510+ if (!teo_state_ok ( i , drv )) {
535511 /*
536512 * The current state is too shallow, but if an
537513 * alternative candidate state has been found,
@@ -543,7 +519,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
543519 break ;
544520 }
545521
546- first_suitable_span_ns = span_ns ;
547522 first_suitable_idx = i ;
548523 }
549524 }
@@ -562,14 +537,22 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
562537 * not sufficiently large.
563538 */
564539 if (cpu_utilized ) {
565- s64 span_ns ;
540+ i = teo_find_shallower_state (drv , dev , idx , KTIME_MAX , true);
541+ if (teo_state_ok (i , drv ))
542+ idx = i ;
543+ }
566544
567- i = teo_find_shallower_state (drv , dev , idx , duration_ns , true);
568- span_ns = teo_middle_of_bin (i , drv );
569- if (teo_time_ok (span_ns )) {
545+ duration_ns = tick_nohz_get_sleep_length (& delta_tick );
546+ cpu_data -> sleep_length_ns = duration_ns ;
547+
548+ /*
549+ * If the closest expected timer is before the terget residency of the
550+ * candidate state, a shallower one needs to be found.
551+ */
552+ if (drv -> states [idx ].target_residency_ns > duration_ns ) {
553+ i = teo_find_shallower_state (drv , dev , idx , duration_ns , false);
554+ if (teo_state_ok (i , drv ))
570555 idx = i ;
571- duration_ns = span_ns ;
572- }
573556 }
574557
575558end :
0 commit comments