Skip to content

Commit c1d51f6

Browse files
committed
cpuidle: Use nanoseconds as the unit of time
Currently, the cpuidle subsystem uses microseconds as the unit of time which (among other things) causes the idle loop to incur some integer division overhead for no clear benefit. In order to allow cpuidle to measure time in nanoseconds, add two new fields, exit_latency_ns and target_residency_ns, to represent the exit latency and target residency of an idle state in nanoseconds, respectively, to struct cpuidle_state and initialize them with the help of the corresponding values in microseconds provided by drivers. Additionally, change cpuidle_governor_latency_req() to return the idle state exit latency constraint in nanoseconds. Also meeasure idle state residency (last_residency_ns in struct cpuidle_device and time_ns in struct cpuidle_driver) in nanoseconds and update the cpuidle core and governors accordingly. However, the menu governor still computes typical intervals in microseconds to avoid integer overflows. Signed-off-by: Rafael J. Wysocki <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Doug Smythies <[email protected]> Tested-by: Doug Smythies <[email protected]>
1 parent 99e98d3 commit c1d51f6

File tree

11 files changed

+174
-161
lines changed

11 files changed

+174
-161
lines changed

drivers/cpuidle/cpuidle.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,24 @@ int cpuidle_play_dead(void)
7575

7676
static int find_deepest_state(struct cpuidle_driver *drv,
7777
struct cpuidle_device *dev,
78-
unsigned int max_latency,
78+
u64 max_latency_ns,
7979
unsigned int forbidden_flags,
8080
bool s2idle)
8181
{
82-
unsigned int latency_req = 0;
82+
u64 latency_req = 0;
8383
int i, ret = 0;
8484

8585
for (i = 1; i < drv->state_count; i++) {
8686
struct cpuidle_state *s = &drv->states[i];
8787

8888
if (dev->states_usage[i].disable ||
89-
s->exit_latency <= latency_req ||
90-
s->exit_latency > max_latency ||
89+
s->exit_latency_ns <= latency_req ||
90+
s->exit_latency_ns > max_latency_ns ||
9191
(s->flags & forbidden_flags) ||
9292
(s2idle && !s->enter_s2idle))
9393
continue;
9494

95-
latency_req = s->exit_latency;
95+
latency_req = s->exit_latency_ns;
9696
ret = i;
9797
}
9898
return ret;
@@ -124,7 +124,7 @@ void cpuidle_use_deepest_state(bool enable)
124124
int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
125125
struct cpuidle_device *dev)
126126
{
127-
return find_deepest_state(drv, dev, UINT_MAX, 0, false);
127+
return find_deepest_state(drv, dev, U64_MAX, 0, false);
128128
}
129129

130130
#ifdef CONFIG_SUSPEND
@@ -180,7 +180,7 @@ int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev)
180180
* that interrupts won't be enabled when it exits and allows the tick to
181181
* be frozen safely.
182182
*/
183-
index = find_deepest_state(drv, dev, UINT_MAX, 0, true);
183+
index = find_deepest_state(drv, dev, U64_MAX, 0, true);
184184
if (index > 0)
185185
enter_s2idle_proper(drv, dev, index);
186186

@@ -209,7 +209,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
209209
* CPU as a broadcast timer, this call may fail if it is not available.
210210
*/
211211
if (broadcast && tick_broadcast_enter()) {
212-
index = find_deepest_state(drv, dev, target_state->exit_latency,
212+
index = find_deepest_state(drv, dev, target_state->exit_latency_ns,
213213
CPUIDLE_FLAG_TIMER_STOP, false);
214214
if (index < 0) {
215215
default_idle_call();
@@ -247,23 +247,21 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
247247
local_irq_enable();
248248

249249
if (entered_state >= 0) {
250-
s64 diff, delay = drv->states[entered_state].exit_latency;
250+
s64 diff, delay = drv->states[entered_state].exit_latency_ns;
251251
int i;
252252

253253
/*
254254
* Update cpuidle counters
255255
* This can be moved to within driver enter routine,
256256
* but that results in multiple copies of same code.
257257
*/
258-
diff = ktime_us_delta(time_end, time_start);
259-
if (diff > INT_MAX)
260-
diff = INT_MAX;
258+
diff = ktime_sub(time_end, time_start);
261259

262-
dev->last_residency = (int)diff;
263-
dev->states_usage[entered_state].time += dev->last_residency;
260+
dev->last_residency_ns = diff;
261+
dev->states_usage[entered_state].time_ns += diff;
264262
dev->states_usage[entered_state].usage++;
265263

266-
if (diff < drv->states[entered_state].target_residency) {
264+
if (diff < drv->states[entered_state].target_residency_ns) {
267265
for (i = entered_state - 1; i >= 0; i--) {
268266
if (dev->states_usage[i].disable)
269267
continue;
@@ -281,14 +279,14 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
281279
* Update if a deeper state would have been a
282280
* better match for the observed idle duration.
283281
*/
284-
if (diff - delay >= drv->states[i].target_residency)
282+
if (diff - delay >= drv->states[i].target_residency_ns)
285283
dev->states_usage[entered_state].below++;
286284

287285
break;
288286
}
289287
}
290288
} else {
291-
dev->last_residency = 0;
289+
dev->last_residency_ns = 0;
292290
}
293291

294292
return entered_state;
@@ -381,7 +379,7 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv,
381379
if (dev->states_usage[i].disable)
382380
continue;
383381

384-
limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
382+
limit_ns = (u64)drv->states[i].target_residency_ns;
385383
}
386384

387385
dev->poll_limit_ns = limit_ns;
@@ -552,7 +550,7 @@ static void __cpuidle_unregister_device(struct cpuidle_device *dev)
552550
static void __cpuidle_device_init(struct cpuidle_device *dev)
553551
{
554552
memset(dev->states_usage, 0, sizeof(dev->states_usage));
555-
dev->last_residency = 0;
553+
dev->last_residency_ns = 0;
556554
dev->next_hrtimer = 0;
557555
}
558556

drivers/cpuidle/driver.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,27 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
165165
if (!drv->cpumask)
166166
drv->cpumask = (struct cpumask *)cpu_possible_mask;
167167

168-
/*
169-
* Look for the timer stop flag in the different states, so that we know
170-
* if the broadcast timer has to be set up. The loop is in the reverse
171-
* order, because usually one of the deeper states have this flag set.
172-
*/
173-
for (i = drv->state_count - 1; i >= 0 ; i--) {
174-
if (drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP) {
168+
for (i = 0; i < drv->state_count; i++) {
169+
struct cpuidle_state *s = &drv->states[i];
170+
171+
/*
172+
* Look for the timer stop flag in the different states and if
173+
* it is found, indicate that the broadcast timer has to be set
174+
* up.
175+
*/
176+
if (s->flags & CPUIDLE_FLAG_TIMER_STOP)
175177
drv->bctimer = 1;
176-
break;
177-
}
178+
179+
/*
180+
* The core will use the target residency and exit latency
181+
* values in nanoseconds, but allow drivers to provide them in
182+
* microseconds too.
183+
*/
184+
if (s->target_residency > 0)
185+
s->target_residency_ns = s->target_residency * NSEC_PER_USEC;
186+
187+
if (s->exit_latency > 0)
188+
s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC;
178189
}
179190
}
180191

drivers/cpuidle/governor.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,14 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
107107
* cpuidle_governor_latency_req - Compute a latency constraint for CPU
108108
* @cpu: Target CPU
109109
*/
110-
int cpuidle_governor_latency_req(unsigned int cpu)
110+
s64 cpuidle_governor_latency_req(unsigned int cpu)
111111
{
112112
int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
113113
struct device *device = get_cpu_device(cpu);
114114
int device_req = dev_pm_qos_raw_resume_latency(device);
115115

116-
return device_req < global_req ? device_req : global_req;
116+
if (device_req > global_req)
117+
device_req = global_req;
118+
119+
return (s64)device_req * NSEC_PER_USEC;
117120
}

drivers/cpuidle/governors/haltpoll.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static int haltpoll_select(struct cpuidle_driver *drv,
4949
struct cpuidle_device *dev,
5050
bool *stop_tick)
5151
{
52-
int latency_req = cpuidle_governor_latency_req(dev->cpu);
52+
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
5353

5454
if (!drv->state_count || latency_req == 0) {
5555
*stop_tick = false;
@@ -75,10 +75,9 @@ static int haltpoll_select(struct cpuidle_driver *drv,
7575
return 0;
7676
}
7777

78-
static void adjust_poll_limit(struct cpuidle_device *dev, unsigned int block_us)
78+
static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
7979
{
8080
unsigned int val;
81-
u64 block_ns = block_us*NSEC_PER_USEC;
8281

8382
/* Grow cpu_halt_poll_us if
8483
* cpu_halt_poll_us < block_ns < guest_halt_poll_us
@@ -115,7 +114,7 @@ static void haltpoll_reflect(struct cpuidle_device *dev, int index)
115114
dev->last_state_idx = index;
116115

117116
if (index != 0)
118-
adjust_poll_limit(dev, dev->last_residency);
117+
adjust_poll_limit(dev, dev->last_residency_ns);
119118
}
120119

121120
/**

drivers/cpuidle/governors/ladder.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ struct ladder_device_state {
2727
struct {
2828
u32 promotion_count;
2929
u32 demotion_count;
30-
u32 promotion_time;
31-
u32 demotion_time;
30+
u64 promotion_time_ns;
31+
u64 demotion_time_ns;
3232
} threshold;
3333
struct {
3434
int promotion_count;
@@ -68,9 +68,10 @@ static int ladder_select_state(struct cpuidle_driver *drv,
6868
{
6969
struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
7070
struct ladder_device_state *last_state;
71-
int last_residency, last_idx = dev->last_state_idx;
71+
int last_idx = dev->last_state_idx;
7272
int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
73-
int latency_req = cpuidle_governor_latency_req(dev->cpu);
73+
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
74+
s64 last_residency;
7475

7576
/* Special case when user has set very strict latency requirement */
7677
if (unlikely(latency_req == 0)) {
@@ -80,13 +81,13 @@ static int ladder_select_state(struct cpuidle_driver *drv,
8081

8182
last_state = &ldev->states[last_idx];
8283

83-
last_residency = dev->last_residency - drv->states[last_idx].exit_latency;
84+
last_residency = dev->last_residency_ns - drv->states[last_idx].exit_latency_ns;
8485

8586
/* consider promotion */
8687
if (last_idx < drv->state_count - 1 &&
8788
!dev->states_usage[last_idx + 1].disable &&
88-
last_residency > last_state->threshold.promotion_time &&
89-
drv->states[last_idx + 1].exit_latency <= latency_req) {
89+
last_residency > last_state->threshold.promotion_time_ns &&
90+
drv->states[last_idx + 1].exit_latency_ns <= latency_req) {
9091
last_state->stats.promotion_count++;
9192
last_state->stats.demotion_count = 0;
9293
if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
@@ -98,19 +99,19 @@ static int ladder_select_state(struct cpuidle_driver *drv,
9899
/* consider demotion */
99100
if (last_idx > first_idx &&
100101
(dev->states_usage[last_idx].disable ||
101-
drv->states[last_idx].exit_latency > latency_req)) {
102+
drv->states[last_idx].exit_latency_ns > latency_req)) {
102103
int i;
103104

104105
for (i = last_idx - 1; i > first_idx; i--) {
105-
if (drv->states[i].exit_latency <= latency_req)
106+
if (drv->states[i].exit_latency_ns <= latency_req)
106107
break;
107108
}
108109
ladder_do_selection(dev, ldev, last_idx, i);
109110
return i;
110111
}
111112

112113
if (last_idx > first_idx &&
113-
last_residency < last_state->threshold.demotion_time) {
114+
last_residency < last_state->threshold.demotion_time_ns) {
114115
last_state->stats.demotion_count++;
115116
last_state->stats.promotion_count = 0;
116117
if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
@@ -150,9 +151,9 @@ static int ladder_enable_device(struct cpuidle_driver *drv,
150151
lstate->threshold.demotion_count = DEMOTION_COUNT;
151152

152153
if (i < drv->state_count - 1)
153-
lstate->threshold.promotion_time = state->exit_latency;
154+
lstate->threshold.promotion_time_ns = state->exit_latency_ns;
154155
if (i > first_idx)
155-
lstate->threshold.demotion_time = state->exit_latency;
156+
lstate->threshold.demotion_time_ns = state->exit_latency_ns;
156157
}
157158

158159
return 0;

0 commit comments

Comments
 (0)