sched/tune: add support to compute normalized energy
[firefly-linux-kernel-4.4.55.git] / kernel / sched / tune.c
1 #include <linux/cgroup.h>
2 #include <linux/err.h>
3 #include <linux/kernel.h>
4 #include <linux/percpu.h>
5 #include <linux/printk.h>
6 #include <linux/reciprocal_div.h>
7 #include <linux/rcupdate.h>
8 #include <linux/slab.h>
9
10 #include "sched.h"
11
12 unsigned int sysctl_sched_cfs_boost __read_mostly;
13
14 /*
15  * System energy normalization constants
16  */
17 static struct target_nrg {
18         unsigned long min_power;
19         unsigned long max_power;
20         struct reciprocal_value rdiv;
21 } schedtune_target_nrg;
22
23 /* Performance Boost region (B) threshold params */
24 static int perf_boost_idx;
25
26 /* Performance Constraint region (C) threshold params */
27 static int perf_constrain_idx;
28
29 /**
30  * Performance-Energy (P-E) Space thresholds constants
31  */
32 struct threshold_params {
33         int nrg_gain;
34         int cap_gain;
35 };
36
37 /*
38  * System specific P-E space thresholds constants
39  */
40 static struct threshold_params
41 threshold_gains[] = {
42         { 0, 4 }, /* >=  0% */
43         { 0, 4 }, /* >= 10% */
44         { 1, 4 }, /* >= 20% */
45         { 2, 4 }, /* >= 30% */
46         { 3, 4 }, /* >= 40% */
47         { 4, 3 }, /* >= 50% */
48         { 4, 2 }, /* >= 60% */
49         { 4, 1 }, /* >= 70% */
50         { 4, 0 }, /* >= 80% */
51         { 4, 0 }  /* >= 90% */
52 };
53
54 static int
55 __schedtune_accept_deltas(int nrg_delta, int cap_delta,
56                           int perf_boost_idx, int perf_constrain_idx)
57 {
58         int payoff = -INT_MAX;
59
60         /* Performance Boost (B) region */
61         if (nrg_delta > 0 && cap_delta > 0) {
62                 /*
63                  * Evaluate "Performance Boost" vs "Energy Increase"
64                  * payoff criteria:
65                  *    cap_delta / nrg_delta < cap_gain / nrg_gain
66                  * which is:
67                  *    nrg_delta * cap_gain > cap_delta * nrg_gain
68                  */
69                 payoff  = nrg_delta * threshold_gains[perf_boost_idx].cap_gain;
70                 payoff -= cap_delta * threshold_gains[perf_boost_idx].nrg_gain;
71                 return payoff;
72         }
73
74         /* Performance Constraint (C) region */
75         if (nrg_delta < 0 && cap_delta < 0) {
76                 /*
77                  * Evaluate "Performance Boost" vs "Energy Increase"
78                  * payoff criteria:
79                  *    cap_delta / nrg_delta > cap_gain / nrg_gain
80                  * which is:
81                  *    cap_delta * nrg_gain > nrg_delta * cap_gain
82                  */
83                 payoff  = cap_delta * threshold_gains[perf_constrain_idx].nrg_gain;
84                 payoff -= nrg_delta * threshold_gains[perf_constrain_idx].cap_gain;
85                 return payoff;
86         }
87
88         /* Default: reject schedule candidate */
89         return payoff;
90 }
91
92 #ifdef CONFIG_CGROUP_SCHEDTUNE
93
94 /*
95  * EAS scheduler tunables for task groups.
96  */
97
98 /* SchdTune tunables for a group of tasks */
99 struct schedtune {
100         /* SchedTune CGroup subsystem */
101         struct cgroup_subsys_state css;
102
103         /* Boost group allocated ID */
104         int idx;
105
106         /* Boost value for tasks on that SchedTune CGroup */
107         int boost;
108
109         /* Performance Boost (B) region threshold params */
110         int perf_boost_idx;
111
112         /* Performance Constraint (C) region threshold params */
113         int perf_constrain_idx;
114 };
115
116 static inline struct schedtune *css_st(struct cgroup_subsys_state *css)
117 {
118         return css ? container_of(css, struct schedtune, css) : NULL;
119 }
120
121 static inline struct schedtune *task_schedtune(struct task_struct *tsk)
122 {
123         return css_st(task_css(tsk, schedtune_cgrp_id));
124 }
125
126 static inline struct schedtune *parent_st(struct schedtune *st)
127 {
128         return css_st(st->css.parent);
129 }
130
131 /*
132  * SchedTune root control group
133  * The root control group is used to defined a system-wide boosting tuning,
134  * which is applied to all tasks in the system.
135  * Task specific boost tuning could be specified by creating and
136  * configuring a child control group under the root one.
137  * By default, system-wide boosting is disabled, i.e. no boosting is applied
138  * to tasks which are not into a child control group.
139  */
140 static struct schedtune
141 root_schedtune = {
142         .boost  = 0,
143         .perf_boost_idx = 0,
144         .perf_constrain_idx = 0,
145 };
146
147 int
148 schedtune_accept_deltas(int nrg_delta, int cap_delta,
149                         struct task_struct *task)
150 {
151         struct schedtune *ct;
152         int perf_boost_idx;
153         int perf_constrain_idx;
154
155         /* Optimal (O) region */
156         if (nrg_delta < 0 && cap_delta > 0)
157                 return INT_MAX;
158
159         /* Suboptimal (S) region */
160         if (nrg_delta > 0 && cap_delta < 0)
161                 return -INT_MAX;
162
163         /* Get task specific perf Boost/Constraints indexes */
164         rcu_read_lock();
165         ct = task_schedtune(task);
166         perf_boost_idx = ct->perf_boost_idx;
167         perf_constrain_idx = ct->perf_constrain_idx;
168         rcu_read_unlock();
169
170         return __schedtune_accept_deltas(nrg_delta, cap_delta,
171                         perf_boost_idx, perf_constrain_idx);
172 }
173
174 /*
175  * Maximum number of boost groups to support
176  * When per-task boosting is used we still allow only limited number of
177  * boost groups for two main reasons:
178  * 1. on a real system we usually have only few classes of workloads which
179  *    make sense to boost with different values (e.g. background vs foreground
180  *    tasks, interactive vs low-priority tasks)
181  * 2. a limited number allows for a simpler and more memory/time efficient
182  *    implementation especially for the computation of the per-CPU boost
183  *    value
184  */
185 #define BOOSTGROUPS_COUNT 4
186
187 /* Array of configured boostgroups */
188 static struct schedtune *allocated_group[BOOSTGROUPS_COUNT] = {
189         &root_schedtune,
190         NULL,
191 };
192
193 /* SchedTune boost groups
194  * Keep track of all the boost groups which impact on CPU, for example when a
195  * CPU has two RUNNABLE tasks belonging to two different boost groups and thus
196  * likely with different boost values.
197  * Since on each system we expect only a limited number of boost groups, here
198  * we use a simple array to keep track of the metrics required to compute the
199  * maximum per-CPU boosting value.
200  */
201 struct boost_groups {
202         /* Maximum boost value for all RUNNABLE tasks on a CPU */
203         unsigned boost_max;
204         struct {
205                 /* The boost for tasks on that boost group */
206                 unsigned boost;
207                 /* Count of RUNNABLE tasks on that boost group */
208                 unsigned tasks;
209         } group[BOOSTGROUPS_COUNT];
210 };
211
212 /* Boost groups affecting each CPU in the system */
213 DEFINE_PER_CPU(struct boost_groups, cpu_boost_groups);
214
215 static void
216 schedtune_cpu_update(int cpu)
217 {
218         struct boost_groups *bg;
219         unsigned boost_max;
220         int idx;
221
222         bg = &per_cpu(cpu_boost_groups, cpu);
223
224         /* The root boost group is always active */
225         boost_max = bg->group[0].boost;
226         for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) {
227                 /*
228                  * A boost group affects a CPU only if it has
229                  * RUNNABLE tasks on that CPU
230                  */
231                 if (bg->group[idx].tasks == 0)
232                         continue;
233                 boost_max = max(boost_max, bg->group[idx].boost);
234         }
235
236         bg->boost_max = boost_max;
237 }
238
239 static int
240 schedtune_boostgroup_update(int idx, int boost)
241 {
242         struct boost_groups *bg;
243         int cur_boost_max;
244         int old_boost;
245         int cpu;
246
247         /* Update per CPU boost groups */
248         for_each_possible_cpu(cpu) {
249                 bg = &per_cpu(cpu_boost_groups, cpu);
250
251                 /*
252                  * Keep track of current boost values to compute the per CPU
253                  * maximum only when it has been affected by the new value of
254                  * the updated boost group
255                  */
256                 cur_boost_max = bg->boost_max;
257                 old_boost = bg->group[idx].boost;
258
259                 /* Update the boost value of this boost group */
260                 bg->group[idx].boost = boost;
261
262                 /* Check if this update increase current max */
263                 if (boost > cur_boost_max && bg->group[idx].tasks) {
264                         bg->boost_max = boost;
265                         continue;
266                 }
267
268                 /* Check if this update has decreased current max */
269                 if (cur_boost_max == old_boost && old_boost > boost)
270                         schedtune_cpu_update(cpu);
271         }
272
273         return 0;
274 }
275
276 static inline void
277 schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count)
278 {
279         struct boost_groups *bg;
280         int tasks;
281
282         bg = &per_cpu(cpu_boost_groups, cpu);
283
284         /* Update boosted tasks count while avoiding to make it negative */
285         if (task_count < 0 && bg->group[idx].tasks <= -task_count)
286                 bg->group[idx].tasks = 0;
287         else
288                 bg->group[idx].tasks += task_count;
289
290         /* Boost group activation or deactivation on that RQ */
291         tasks = bg->group[idx].tasks;
292         if (tasks == 1 || tasks == 0)
293                 schedtune_cpu_update(cpu);
294 }
295
296 /*
297  * NOTE: This function must be called while holding the lock on the CPU RQ
298  */
299 void schedtune_enqueue_task(struct task_struct *p, int cpu)
300 {
301         struct schedtune *st;
302         int idx;
303
304         /*
305          * When a task is marked PF_EXITING by do_exit() it's going to be
306          * dequeued and enqueued multiple times in the exit path.
307          * Thus we avoid any further update, since we do not want to change
308          * CPU boosting while the task is exiting.
309          */
310         if (p->flags & PF_EXITING)
311                 return;
312
313         /* Get task boost group */
314         rcu_read_lock();
315         st = task_schedtune(p);
316         idx = st->idx;
317         rcu_read_unlock();
318
319         schedtune_tasks_update(p, cpu, idx, 1);
320 }
321
322 /*
323  * NOTE: This function must be called while holding the lock on the CPU RQ
324  */
325 void schedtune_dequeue_task(struct task_struct *p, int cpu)
326 {
327         struct schedtune *st;
328         int idx;
329
330         /*
331          * When a task is marked PF_EXITING by do_exit() it's going to be
332          * dequeued and enqueued multiple times in the exit path.
333          * Thus we avoid any further update, since we do not want to change
334          * CPU boosting while the task is exiting.
335          * The last dequeue will be done by cgroup exit() callback.
336          */
337         if (p->flags & PF_EXITING)
338                 return;
339
340         /* Get task boost group */
341         rcu_read_lock();
342         st = task_schedtune(p);
343         idx = st->idx;
344         rcu_read_unlock();
345
346         schedtune_tasks_update(p, cpu, idx, -1);
347 }
348
349 int schedtune_cpu_boost(int cpu)
350 {
351         struct boost_groups *bg;
352
353         bg = &per_cpu(cpu_boost_groups, cpu);
354         return bg->boost_max;
355 }
356
357 int schedtune_task_boost(struct task_struct *p)
358 {
359         struct schedtune *st;
360         int task_boost;
361
362         /* Get task boost value */
363         rcu_read_lock();
364         st = task_schedtune(p);
365         task_boost = st->boost;
366         rcu_read_unlock();
367
368         return task_boost;
369 }
370
371 static u64
372 boost_read(struct cgroup_subsys_state *css, struct cftype *cft)
373 {
374         struct schedtune *st = css_st(css);
375
376         return st->boost;
377 }
378
379 static int
380 boost_write(struct cgroup_subsys_state *css, struct cftype *cft,
381             u64 boost)
382 {
383         struct schedtune *st = css_st(css);
384
385         if (boost < 0 || boost > 100)
386                 return -EINVAL;
387
388         st->boost = boost;
389         if (css == &root_schedtune.css)
390                 sysctl_sched_cfs_boost = boost;
391
392         /* Update CPU boost */
393         schedtune_boostgroup_update(st->idx, st->boost);
394
395         return 0;
396 }
397
398 static struct cftype files[] = {
399         {
400                 .name = "boost",
401                 .read_u64 = boost_read,
402                 .write_u64 = boost_write,
403         },
404         { }     /* terminate */
405 };
406
407 static int
408 schedtune_boostgroup_init(struct schedtune *st)
409 {
410         struct boost_groups *bg;
411         int cpu;
412
413         /* Keep track of allocated boost groups */
414         allocated_group[st->idx] = st;
415
416         /* Initialize the per CPU boost groups */
417         for_each_possible_cpu(cpu) {
418                 bg = &per_cpu(cpu_boost_groups, cpu);
419                 bg->group[st->idx].boost = 0;
420                 bg->group[st->idx].tasks = 0;
421         }
422
423         return 0;
424 }
425
426 static int
427 schedtune_init(void)
428 {
429         struct boost_groups *bg;
430         int cpu;
431
432         /* Initialize the per CPU boost groups */
433         for_each_possible_cpu(cpu) {
434                 bg = &per_cpu(cpu_boost_groups, cpu);
435                 memset(bg, 0, sizeof(struct boost_groups));
436         }
437
438         pr_info("  schedtune configured to support %d boost groups\n",
439                 BOOSTGROUPS_COUNT);
440         return 0;
441 }
442
443 static struct cgroup_subsys_state *
444 schedtune_css_alloc(struct cgroup_subsys_state *parent_css)
445 {
446         struct schedtune *st;
447         int idx;
448
449         if (!parent_css) {
450                 schedtune_init();
451                 return &root_schedtune.css;
452         }
453
454         /* Allow only single level hierachies */
455         if (parent_css != &root_schedtune.css) {
456                 pr_err("Nested SchedTune boosting groups not allowed\n");
457                 return ERR_PTR(-ENOMEM);
458         }
459
460         /* Allow only a limited number of boosting groups */
461         for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx)
462                 if (!allocated_group[idx])
463                         break;
464         if (idx == BOOSTGROUPS_COUNT) {
465                 pr_err("Trying to create more than %d SchedTune boosting groups\n",
466                        BOOSTGROUPS_COUNT);
467                 return ERR_PTR(-ENOSPC);
468         }
469
470         st = kzalloc(sizeof(*st), GFP_KERNEL);
471         if (!st)
472                 goto out;
473
474         /* Initialize per CPUs boost group support */
475         st->idx = idx;
476         if (schedtune_boostgroup_init(st))
477                 goto release;
478
479         return &st->css;
480
481 release:
482         kfree(st);
483 out:
484         return ERR_PTR(-ENOMEM);
485 }
486
487 static void
488 schedtune_boostgroup_release(struct schedtune *st)
489 {
490         /* Reset this boost group */
491         schedtune_boostgroup_update(st->idx, 0);
492
493         /* Keep track of allocated boost groups */
494         allocated_group[st->idx] = NULL;
495 }
496
497 static void
498 schedtune_css_free(struct cgroup_subsys_state *css)
499 {
500         struct schedtune *st = css_st(css);
501
502         schedtune_boostgroup_release(st);
503         kfree(st);
504 }
505
506 struct cgroup_subsys schedtune_cgrp_subsys = {
507         .css_alloc      = schedtune_css_alloc,
508         .css_free       = schedtune_css_free,
509         .legacy_cftypes = files,
510         .early_init     = 1,
511 };
512
513 #else /* CONFIG_CGROUP_SCHEDTUNE */
514
515 int
516 schedtune_accept_deltas(int nrg_delta, int cap_delta,
517                         struct task_struct *task)
518 {
519         /* Optimal (O) region */
520         if (nrg_delta < 0 && cap_delta > 0)
521                 return INT_MAX;
522
523         /* Suboptimal (S) region */
524         if (nrg_delta > 0 && cap_delta < 0)
525                 return -INT_MAX;
526
527         return __schedtune_accept_deltas(nrg_delta, cap_delta,
528                         perf_boost_idx, perf_constrain_idx);
529 }
530
531 #endif /* CONFIG_CGROUP_SCHEDTUNE */
532
533 int
534 sysctl_sched_cfs_boost_handler(struct ctl_table *table, int write,
535                                void __user *buffer, size_t *lenp,
536                                loff_t *ppos)
537 {
538         int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
539
540         if (ret || !write)
541                 return ret;
542
543         /* Performance Boost (B) region threshold params */
544         perf_boost_idx  = sysctl_sched_cfs_boost;
545         perf_boost_idx /= 10;
546
547         /* Performance Constraint (C) region threshold params */
548         perf_constrain_idx  = 100 - sysctl_sched_cfs_boost;
549         perf_constrain_idx /= 10;
550
551         return 0;
552 }
553
554 /*
555  * System energy normalization
556  * Returns the normalized value, in the range [0..SCHED_LOAD_SCALE],
557  * corresponding to the specified energy variation.
558  */
559 int
560 schedtune_normalize_energy(int energy_diff)
561 {
562         u32 normalized_nrg;
563         int max_delta;
564
565 #ifdef CONFIG_SCHED_DEBUG
566         /* Check for boundaries */
567         max_delta  = schedtune_target_nrg.max_power;
568         max_delta -= schedtune_target_nrg.min_power;
569         WARN_ON(abs(energy_diff) >= max_delta);
570 #endif
571
572         /* Do scaling using positive numbers to increase the range */
573         normalized_nrg = (energy_diff < 0) ? -energy_diff : energy_diff;
574
575         /* Scale by energy magnitude */
576         normalized_nrg <<= SCHED_LOAD_SHIFT;
577
578         /* Normalize on max energy for target platform */
579         normalized_nrg = reciprocal_divide(
580                         normalized_nrg, schedtune_target_nrg.rdiv);
581
582         return (energy_diff < 0) ? -normalized_nrg : normalized_nrg;
583 }
584
585 #ifdef CONFIG_SCHED_DEBUG
586 static void
587 schedtune_test_nrg(unsigned long delta_pwr)
588 {
589         unsigned long test_delta_pwr;
590         unsigned long test_norm_pwr;
591         int idx;
592
593         /*
594          * Check normalization constants using some constant system
595          * energy values
596          */
597         pr_info("schedtune: verify normalization constants...\n");
598         for (idx = 0; idx < 6; ++idx) {
599                 test_delta_pwr = delta_pwr >> idx;
600
601                 /* Normalize on max energy for target platform */
602                 test_norm_pwr = reciprocal_divide(
603                                         test_delta_pwr << SCHED_LOAD_SHIFT,
604                                         schedtune_target_nrg.rdiv);
605
606                 pr_info("schedtune: max_pwr/2^%d: %4lu => norm_pwr: %5lu\n",
607                         idx, test_delta_pwr, test_norm_pwr);
608         }
609 }
610 #else
611 #define schedtune_test_nrg(delta_pwr)
612 #endif
613
614 /*
615  * Compute the min/max power consumption of a cluster and all its CPUs
616  */
617 static void
618 schedtune_add_cluster_nrg(
619                 struct sched_domain *sd,
620                 struct sched_group *sg,
621                 struct target_nrg *ste)
622 {
623         struct sched_domain *sd2;
624         struct sched_group *sg2;
625
626         struct cpumask *cluster_cpus;
627         char str[32];
628
629         unsigned long min_pwr;
630         unsigned long max_pwr;
631         int cpu;
632
633         /* Get Cluster energy using EM data for the first CPU */
634         cluster_cpus = sched_group_cpus(sg);
635         snprintf(str, 32, "CLUSTER[%*pbl]",
636                  cpumask_pr_args(cluster_cpus));
637
638         min_pwr = sg->sge->idle_states[sg->sge->nr_idle_states - 1].power;
639         max_pwr = sg->sge->cap_states[sg->sge->nr_cap_states - 1].power;
640         pr_info("schedtune: %-17s min_pwr: %5lu max_pwr: %5lu\n",
641                 str, min_pwr, max_pwr);
642
643         /*
644          * Keep track of this cluster's energy in the computation of the
645          * overall system energy
646          */
647         ste->min_power += min_pwr;
648         ste->max_power += max_pwr;
649
650         /* Get CPU energy using EM data for each CPU in the group */
651         for_each_cpu(cpu, cluster_cpus) {
652                 /* Get a SD view for the specific CPU */
653                 for_each_domain(cpu, sd2) {
654                         /* Get the CPU group */
655                         sg2 = sd2->groups;
656                         min_pwr = sg2->sge->idle_states[sg2->sge->nr_idle_states - 1].power;
657                         max_pwr = sg2->sge->cap_states[sg2->sge->nr_cap_states - 1].power;
658
659                         ste->min_power += min_pwr;
660                         ste->max_power += max_pwr;
661
662                         snprintf(str, 32, "CPU[%d]", cpu);
663                         pr_info("schedtune: %-17s min_pwr: %5lu max_pwr: %5lu\n",
664                                 str, min_pwr, max_pwr);
665
666                         /*
667                          * Assume we have EM data only at the CPU and
668                          * the upper CLUSTER level
669                          */
670                         BUG_ON(!cpumask_equal(
671                                 sched_group_cpus(sg),
672                                 sched_group_cpus(sd2->parent->groups)
673                                 ));
674                         break;
675                 }
676         }
677 }
678
679 /*
680  * Initialize the constants required to compute normalized energy.
681  * The values of these constants depends on the EM data for the specific
682  * target system and topology.
683  * Thus, this function is expected to be called by the code
684  * that bind the EM to the topology information.
685  */
686 static int
687 schedtune_init_late(void)
688 {
689         struct target_nrg *ste = &schedtune_target_nrg;
690         unsigned long delta_pwr = 0;
691         struct sched_domain *sd;
692         struct sched_group *sg;
693
694         pr_info("schedtune: init normalization constants...\n");
695         ste->max_power = 0;
696         ste->min_power = 0;
697
698         rcu_read_lock();
699
700         /*
701          * When EAS is in use, we always have a pointer to the highest SD
702          * which provides EM data.
703          */
704         sd = rcu_dereference(per_cpu(sd_ea, cpumask_first(cpu_online_mask)));
705         if (!sd) {
706                 pr_info("schedtune: no energy model data\n");
707                 goto nodata;
708         }
709
710         sg = sd->groups;
711         do {
712                 schedtune_add_cluster_nrg(sd, sg, ste);
713         } while (sg = sg->next, sg != sd->groups);
714
715         rcu_read_unlock();
716
717         pr_info("schedtune: %-17s min_pwr: %5lu max_pwr: %5lu\n",
718                 "SYSTEM", ste->min_power, ste->max_power);
719
720         /* Compute normalization constants */
721         delta_pwr = ste->max_power - ste->min_power;
722         ste->rdiv = reciprocal_value(delta_pwr);
723         pr_info("schedtune: using normalization constants mul: %u sh1: %u sh2: %u\n",
724                 ste->rdiv.m, ste->rdiv.sh1, ste->rdiv.sh2);
725
726         schedtune_test_nrg(delta_pwr);
727         return 0;
728
729 nodata:
730         rcu_read_unlock();
731         return -EINVAL;
732 }
733 late_initcall(schedtune_init_late);
734