This source file includes following definitions.
- teo_update
- teo_find_shallower_state
- teo_select
- teo_reflect
- teo_enable_device
- teo_governor_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #include <linux/cpuidle.h>
49 #include <linux/jiffies.h>
50 #include <linux/kernel.h>
51 #include <linux/sched/clock.h>
52 #include <linux/tick.h>
53
54
55
56
57
58 #define PULSE 1024
59 #define DECAY_SHIFT 3
60
61
62
63
64
65 #define INTERVALS 8
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 struct teo_idle_state {
89 unsigned int early_hits;
90 unsigned int hits;
91 unsigned int misses;
92 };
93
94
95
96
97
98
99
100
101
102 struct teo_cpu {
103 u64 time_span_ns;
104 u64 sleep_length_ns;
105 struct teo_idle_state states[CPUIDLE_STATE_MAX];
106 int interval_idx;
107 unsigned int intervals[INTERVALS];
108 };
109
110 static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
111
112
113
114
115
116
117 static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
118 {
119 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
120 unsigned int sleep_length_us = ktime_to_us(cpu_data->sleep_length_ns);
121 int i, idx_hit = -1, idx_timer = -1;
122 unsigned int measured_us;
123
124 if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) {
125
126
127
128
129
130 measured_us = UINT_MAX;
131 } else {
132 unsigned int lat;
133
134 lat = drv->states[dev->last_state_idx].exit_latency;
135
136 measured_us = ktime_to_us(cpu_data->time_span_ns);
137
138
139
140
141
142
143 if (measured_us >= lat)
144 measured_us -= lat / 2;
145 else
146 measured_us /= 2;
147 }
148
149
150
151
152
153 for (i = 0; i < drv->state_count; i++) {
154 unsigned int early_hits = cpu_data->states[i].early_hits;
155
156 cpu_data->states[i].early_hits -= early_hits >> DECAY_SHIFT;
157
158 if (drv->states[i].target_residency <= sleep_length_us) {
159 idx_timer = i;
160 if (drv->states[i].target_residency <= measured_us)
161 idx_hit = i;
162 }
163 }
164
165
166
167
168
169
170
171
172
173 if (idx_timer >= 0) {
174 unsigned int hits = cpu_data->states[idx_timer].hits;
175 unsigned int misses = cpu_data->states[idx_timer].misses;
176
177 hits -= hits >> DECAY_SHIFT;
178 misses -= misses >> DECAY_SHIFT;
179
180 if (idx_timer > idx_hit) {
181 misses += PULSE;
182 if (idx_hit >= 0)
183 cpu_data->states[idx_hit].early_hits += PULSE;
184 } else {
185 hits += PULSE;
186 }
187
188 cpu_data->states[idx_timer].misses = misses;
189 cpu_data->states[idx_timer].hits = hits;
190 }
191
192
193
194
195
196 cpu_data->intervals[cpu_data->interval_idx++] = measured_us;
197 if (cpu_data->interval_idx >= INTERVALS)
198 cpu_data->interval_idx = 0;
199 }
200
201
202
203
204
205
206
207
208 static int teo_find_shallower_state(struct cpuidle_driver *drv,
209 struct cpuidle_device *dev, int state_idx,
210 unsigned int duration_us)
211 {
212 int i;
213
214 for (i = state_idx - 1; i >= 0; i--) {
215 if (drv->states[i].disabled || dev->states_usage[i].disable)
216 continue;
217
218 state_idx = i;
219 if (drv->states[i].target_residency <= duration_us)
220 break;
221 }
222 return state_idx;
223 }
224
225
226
227
228
229
230
231 static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
232 bool *stop_tick)
233 {
234 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
235 int latency_req = cpuidle_governor_latency_req(dev->cpu);
236 unsigned int duration_us, hits, misses, early_hits;
237 int max_early_idx, prev_max_early_idx, constraint_idx, idx, i;
238 ktime_t delta_tick;
239
240 if (dev->last_state_idx >= 0) {
241 teo_update(drv, dev);
242 dev->last_state_idx = -1;
243 }
244
245 cpu_data->time_span_ns = local_clock();
246
247 cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick);
248 duration_us = ktime_to_us(cpu_data->sleep_length_ns);
249
250 hits = 0;
251 misses = 0;
252 early_hits = 0;
253 max_early_idx = -1;
254 prev_max_early_idx = -1;
255 constraint_idx = drv->state_count;
256 idx = -1;
257
258 for (i = 0; i < drv->state_count; i++) {
259 struct cpuidle_state *s = &drv->states[i];
260 struct cpuidle_state_usage *su = &dev->states_usage[i];
261
262 if (s->disabled || su->disable) {
263
264
265
266
267 if (s->target_residency > duration_us)
268 continue;
269
270
271
272
273
274
275
276
277
278 hits = cpu_data->states[i].hits;
279 misses = cpu_data->states[i].misses;
280
281 if (early_hits >= cpu_data->states[i].early_hits ||
282 idx < 0)
283 continue;
284
285
286
287
288
289
290
291
292 if (max_early_idx == idx) {
293 early_hits = cpu_data->states[i].early_hits;
294 continue;
295 }
296
297
298
299
300
301
302
303
304
305 if (!(tick_nohz_tick_stopped() &&
306 drv->states[idx].target_residency < TICK_USEC)) {
307 prev_max_early_idx = max_early_idx;
308 early_hits = cpu_data->states[i].early_hits;
309 max_early_idx = idx;
310 }
311
312 continue;
313 }
314
315 if (idx < 0) {
316 idx = i;
317 hits = cpu_data->states[i].hits;
318 misses = cpu_data->states[i].misses;
319 }
320
321 if (s->target_residency > duration_us)
322 break;
323
324 if (s->exit_latency > latency_req && constraint_idx > i)
325 constraint_idx = i;
326
327 idx = i;
328 hits = cpu_data->states[i].hits;
329 misses = cpu_data->states[i].misses;
330
331 if (early_hits < cpu_data->states[i].early_hits &&
332 !(tick_nohz_tick_stopped() &&
333 drv->states[i].target_residency < TICK_USEC)) {
334 prev_max_early_idx = max_early_idx;
335 early_hits = cpu_data->states[i].early_hits;
336 max_early_idx = i;
337 }
338 }
339
340
341
342
343
344
345
346
347
348 if (hits <= misses) {
349
350
351
352
353
354 if (idx == max_early_idx)
355 max_early_idx = prev_max_early_idx;
356
357 if (max_early_idx >= 0) {
358 idx = max_early_idx;
359 duration_us = drv->states[idx].target_residency;
360 }
361 }
362
363
364
365
366
367 if (constraint_idx < idx)
368 idx = constraint_idx;
369
370 if (idx < 0) {
371 idx = 0;
372 } else if (idx > 0) {
373 unsigned int count = 0;
374 u64 sum = 0;
375
376
377
378
379
380 for (i = 0; i < INTERVALS; i++) {
381 unsigned int val = cpu_data->intervals[i];
382
383 if (val >= duration_us)
384 continue;
385
386 count++;
387 sum += val;
388 }
389
390
391
392
393
394 if (count > INTERVALS / 2) {
395 unsigned int avg_us = div64_u64(sum, count);
396
397
398
399
400
401 if (!(tick_nohz_tick_stopped() && avg_us < TICK_USEC)) {
402 duration_us = avg_us;
403 if (drv->states[idx].target_residency > avg_us)
404 idx = teo_find_shallower_state(drv, dev,
405 idx, avg_us);
406 }
407 }
408 }
409
410
411
412
413
414 if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
415 duration_us < TICK_USEC) && !tick_nohz_tick_stopped()) {
416 unsigned int delta_tick_us = ktime_to_us(delta_tick);
417
418 *stop_tick = false;
419
420
421
422
423
424
425
426 if (idx > 0 && drv->states[idx].target_residency > delta_tick_us)
427 idx = teo_find_shallower_state(drv, dev, idx, delta_tick_us);
428 }
429
430 return idx;
431 }
432
433
434
435
436
437
438 static void teo_reflect(struct cpuidle_device *dev, int state)
439 {
440 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
441
442 dev->last_state_idx = state;
443
444
445
446
447
448 if (dev->poll_time_limit ||
449 (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) {
450 dev->poll_time_limit = false;
451 cpu_data->time_span_ns = cpu_data->sleep_length_ns;
452 } else {
453 cpu_data->time_span_ns = local_clock() - cpu_data->time_span_ns;
454 }
455 }
456
457
458
459
460
461
462 static int teo_enable_device(struct cpuidle_driver *drv,
463 struct cpuidle_device *dev)
464 {
465 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
466 int i;
467
468 memset(cpu_data, 0, sizeof(*cpu_data));
469
470 for (i = 0; i < INTERVALS; i++)
471 cpu_data->intervals[i] = UINT_MAX;
472
473 return 0;
474 }
475
476 static struct cpuidle_governor teo_governor = {
477 .name = "teo",
478 .rating = 19,
479 .enable = teo_enable_device,
480 .select = teo_select,
481 .reflect = teo_reflect,
482 };
483
484 static int __init teo_governor_init(void)
485 {
486 return cpuidle_register_governor(&teo_governor);
487 }
488
489 postcore_initcall(teo_governor_init);