History

Merge tag 'sched-psi-2022-10-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull PSI updates from Ingo Molnar: - Various performance optimizations, resulting in a 4%-9% speedup in the mmtests/config-scheduler-perfpipe micro-benchmark. - New interface to turn PSI on/off on a per cgroup level. * tag 'sched-psi-2022-10-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: sched/psi: Per-cgroup PSI accounting disable/re-enable interface sched/psi: Cache parent psi_group to speed up group iteration sched/psi: Consolidate cgroup_psi() sched/psi: Add PSI_IRQ to track IRQ/SOFTIRQ pressure sched/psi: Remove NR_ONCPU task accounting sched/psi: Optimize task switch inside shared cgroups again sched/psi: Move private helpers to sched/stats.h sched/psi: Save percpu memory when !psi_cgroups_enabled sched/psi: Don't create cgroup PSI files when psi_disabled sched/psi: Fix periodic aggregation shut off

Linus Torvalds committed 4 years ago

Commit bd9a3db2 parents 1df046a 34f26a19 files · +362 −103Browse files

Unified · Split

9 files
  1. Documentation/admin-guide/cgroup-v2.rst +23 −0
  2. include/linux/cgroup-defs.h +3 −0
  3. include/linux/cgroup.h +0 −5
  4. include/linux/psi.h +8 −4
  5. include/linux/psi_types.h +20 −11
  6. kernel/cgroup/cgroup.c +95 −9
  7. kernel/sched/core.c +1 −0
  8. kernel/sched/psi.c +206 −74
  9. kernel/sched/stats.h +6 −0
Documentation/admin-guide/cgroup-v2.rst+23−0
@@ -976,6 +976,29 @@ All cgroup core files are prefixed with "cgroup." · 975 unmodified lines
976976 killing cgroups is a process directed operation, i.e. it affects
977977 the whole thread-group.
978978
979+ cgroup.pressure
980+ A read-write single value file that allowed values are "0" and "1".
981+ The default is "1".
982+
983+ Writing "0" to the file will disable the cgroup PSI accounting.
984+ Writing "1" to the file will re-enable the cgroup PSI accounting.
985+
986+ This control attribute is not hierarchical, so disable or enable PSI
987+ accounting in a cgroup does not affect PSI accounting in descendants
988+ and doesn't need pass enablement via ancestors from root.
989+
990+ The reason this control attribute exists is that PSI accounts stalls for
991+ each cgroup separately and aggregates it at each level of the hierarchy.
992+ This may cause non-negligible overhead for some workloads when under
993+ deep level of the hierarchy, in which case this control attribute can
994+ be used to disable PSI accounting in the non-leaf cgroups.
995+
996+ irq.pressure
997+ A read-write nested-keyed file.
998+
999+ Shows pressure stall information for IRQ/SOFTIRQ. See
1000+ :ref:`Documentation/accounting/psi.rst <psi>` for details.
1001+
9791002 Controllers
9801003 ===========
9811004
include/linux/cgroup-defs.h+3−0
@@ -428,6 +428,9 @@ struct cgroup { · 427 unmodified lines
428428 struct cgroup_file procs_file; /* handle for "cgroup.procs" */
429429 struct cgroup_file events_file; /* handle for "cgroup.events" */
430430
431+ /* handles for "{cpu,memory,io,irq}.pressure" */
432+ struct cgroup_file psi_files[NR_PSI_RESOURCES];
433+
431434 /*
432435 * The bitmask of subsystems enabled on the child cgroups.
433436 * ->subtree_control is the one configured through
include/linux/cgroup.h+0−5
@@ -682,11 +682,6 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp) · 681 unmodified lines
682682 pr_cont_kernfs_path(cgrp->kn);
683683 }
684684
685−static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
686−{
687− return cgrp->psi;
688−}
689−
690685 bool cgroup_psi_enabled(void);
691686
692687 static inline void cgroup_init_kthreadd(void)
include/linux/psi.h+8−4
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 #include <linux/sched.h>
88 #include <linux/poll.h>
99 #include <linux/cgroup-defs.h>
10+#include <linux/cgroup.h>
1011
1112 struct seq_file;
1213 struct css_set;
@@ -18,10 +19,6 @@ extern struct psi_group psi_system; · 5 unmodified lines
1819
1920 void psi_init(void);
2021
21−void psi_task_change(struct task_struct *task, int clear, int set);
22−void psi_task_switch(struct task_struct *prev, struct task_struct *next,
23− bool sleep);
24−
2522 void psi_memstall_enter(unsigned long *flags);
2623 void psi_memstall_leave(unsigned long *flags);
2724
@@ -34,9 +31,15 @@ __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file, · 6 unmodified lines
3431 poll_table *wait);
3532
3633 #ifdef CONFIG_CGROUPS
34+static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
35+{
36+ return cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
37+}
38+
3739 int psi_cgroup_alloc(struct cgroup *cgrp);
3840 void psi_cgroup_free(struct cgroup *cgrp);
3941 void cgroup_move_task(struct task_struct *p, struct css_set *to);
42+void psi_cgroup_restart(struct psi_group *group);
4043 #endif
4144
4245 #else /* CONFIG_PSI */
@@ -58,6 +61,7 @@ static inline void cgroup_move_task(struct task_struct *p, struct css_set *to) · 15 unmodified lines
5861 {
5962 rcu_assign_pointer(p->cgroups, to);
6063 }
64+static inline void psi_cgroup_restart(struct psi_group *group) {}
6165 #endif
6266
6367 #endif /* CONFIG_PSI */
include/linux/psi_types.h+20−11
@@ -15,13 +15,6 @@ enum psi_task_count { · 14 unmodified lines
1515 NR_IOWAIT,
1616 NR_MEMSTALL,
1717 NR_RUNNING,
18− /*
19− * This can't have values other than 0 or 1 and could be
20− * implemented as a bit flag. But for now we still have room
21− * in the first cacheline of psi_group_cpu, and this way we
22− * don't have to special case any state tracking for it.
23− */
24− NR_ONCPU,
2518 /*
2619 * For IO and CPU stalls the presence of running/oncpu tasks
2720 * in the domain means a partial rather than a full stall.
@@ -32,22 +25,27 @@ enum psi_task_count { · 4 unmodified lines
3225 * threads and memstall ones.
3326 */
3427 NR_MEMSTALL_RUNNING,
35− NR_PSI_TASK_COUNTS = 5,
28+ NR_PSI_TASK_COUNTS = 4,
3629 };
3730
3831 /* Task state bitmasks */
3932 #define TSK_IOWAIT (1 << NR_IOWAIT)
4033 #define TSK_MEMSTALL (1 << NR_MEMSTALL)
4134 #define TSK_RUNNING (1 << NR_RUNNING)
42−#define TSK_ONCPU (1 << NR_ONCPU)
4335 #define TSK_MEMSTALL_RUNNING (1 << NR_MEMSTALL_RUNNING)
4436
37+/* Only one task can be scheduled, no corresponding task count */
38+#define TSK_ONCPU (1 << NR_PSI_TASK_COUNTS)
39+
4540 /* Resources that workloads could be stalled on */
4641 enum psi_res {
4742 PSI_IO,
4843 PSI_MEM,
4944 PSI_CPU,
50− NR_PSI_RESOURCES = 3,
45+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
46+ PSI_IRQ,
47+#endif
48+ NR_PSI_RESOURCES,
5149 };
5250
5351 /*
@@ -63,11 +61,17 @@ enum psi_states { · 9 unmodified lines
6361 PSI_MEM_FULL,
6462 PSI_CPU_SOME,
6563 PSI_CPU_FULL,
64+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
65+ PSI_IRQ_FULL,
66+#endif
6667 /* Only per-CPU, to weigh the CPU in the global average: */
6768 PSI_NONIDLE,
68− NR_PSI_STATES = 7,
69+ NR_PSI_STATES,
6970 };
7071
72+/* Use one bit in the state mask to track TSK_ONCPU */
73+#define PSI_ONCPU (1 << NR_PSI_STATES)
74+
7175 enum psi_aggregators {
7276 PSI_AVGS = 0,
7377 PSI_POLL,
@@ -147,6 +151,9 @@ struct psi_trigger { · 73 unmodified lines
147151 };
148152
149153 struct psi_group {
154+ struct psi_group *parent;
155+ bool enabled;
156+
150157 /* Protects data used by the aggregator */
151158 struct mutex avgs_lock;
152159
@@ -188,6 +195,8 @@ struct psi_group { · 35 unmodified lines
188195
189196 #else /* CONFIG_PSI */
190197
198+#define NR_PSI_RESOURCES 0
199+
191200 struct psi_group { };
192201
193202 #endif /* CONFIG_PSI */
kernel/cgroup/cgroup.c+95−9
@@ -3698,27 +3698,27 @@ static int cpu_stat_show(struct seq_file *seq, void *v) · 3697 unmodified lines
36983698 static int cgroup_io_pressure_show(struct seq_file *seq, void *v)
36993699 {
37003700 struct cgroup *cgrp = seq_css(seq)->cgroup;
3701− struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
3701+ struct psi_group *psi = cgroup_psi(cgrp);
37023702
37033703 return psi_show(seq, psi, PSI_IO);
37043704 }
37053705 static int cgroup_memory_pressure_show(struct seq_file *seq, void *v)
37063706 {
37073707 struct cgroup *cgrp = seq_css(seq)->cgroup;
3708− struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
3708+ struct psi_group *psi = cgroup_psi(cgrp);
37093709
37103710 return psi_show(seq, psi, PSI_MEM);
37113711 }
37123712 static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
37133713 {
37143714 struct cgroup *cgrp = seq_css(seq)->cgroup;
3715− struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
3715+ struct psi_group *psi = cgroup_psi(cgrp);
37163716
37173717 return psi_show(seq, psi, PSI_CPU);
37183718 }
37193719
3720−static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
3721− size_t nbytes, enum psi_res res)
3720+static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
3721+ size_t nbytes, enum psi_res res)
37223722 {
37233723 struct cgroup_file_ctx *ctx = of->priv;
37243724 struct psi_trigger *new;
@@ -3738,7 +3738,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, · 13 unmodified lines
37383738 return -EBUSY;
37393739 }
37403740
3741− psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
3741+ psi = cgroup_psi(cgrp);
37423742 new = psi_trigger_create(psi, buf, res);
37433743 if (IS_ERR(new)) {
37443744 cgroup_put(cgrp);
@@ -3755,21 +3755,86 @@ static ssize_t cgroup_io_pressure_write(struct kernfs_open_file *of, · 10 unmodified lines
37553755 char *buf, size_t nbytes,
37563756 loff_t off)
37573757 {
3758− return cgroup_pressure_write(of, buf, nbytes, PSI_IO);
3758+ return pressure_write(of, buf, nbytes, PSI_IO);
37593759 }
37603760
37613761 static ssize_t cgroup_memory_pressure_write(struct kernfs_open_file *of,
37623762 char *buf, size_t nbytes,
37633763 loff_t off)
37643764 {
3765− return cgroup_pressure_write(of, buf, nbytes, PSI_MEM);
3765+ return pressure_write(of, buf, nbytes, PSI_MEM);
37663766 }
37673767
37683768 static ssize_t cgroup_cpu_pressure_write(struct kernfs_open_file *of,
37693769 char *buf, size_t nbytes,
37703770 loff_t off)
37713771 {
3772− return cgroup_pressure_write(of, buf, nbytes, PSI_CPU);
3772+ return pressure_write(of, buf, nbytes, PSI_CPU);
3773+}
3774+
3775+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
3776+static int cgroup_irq_pressure_show(struct seq_file *seq, void *v)
3777+{
3778+ struct cgroup *cgrp = seq_css(seq)->cgroup;
3779+ struct psi_group *psi = cgroup_psi(cgrp);
3780+
3781+ return psi_show(seq, psi, PSI_IRQ);
3782+}
3783+
3784+static ssize_t cgroup_irq_pressure_write(struct kernfs_open_file *of,
3785+ char *buf, size_t nbytes,
3786+ loff_t off)
3787+{
3788+ return pressure_write(of, buf, nbytes, PSI_IRQ);
3789+}
3790+#endif
3791+
3792+static int cgroup_pressure_show(struct seq_file *seq, void *v)
3793+{
3794+ struct cgroup *cgrp = seq_css(seq)->cgroup;
3795+ struct psi_group *psi = cgroup_psi(cgrp);
3796+
3797+ seq_printf(seq, "%d\n", psi->enabled);
3798+
3799+ return 0;
3800+}
3801+
3802+static ssize_t cgroup_pressure_write(struct kernfs_open_file *of,
3803+ char *buf, size_t nbytes,
3804+ loff_t off)
3805+{
3806+ ssize_t ret;
3807+ int enable;
3808+ struct cgroup *cgrp;
3809+ struct psi_group *psi;
3810+
3811+ ret = kstrtoint(strstrip(buf), 0, &enable);
3812+ if (ret)
3813+ return ret;
3814+
3815+ if (enable < 0 || enable > 1)
3816+ return -ERANGE;
3817+
3818+ cgrp = cgroup_kn_lock_live(of->kn, false);
3819+ if (!cgrp)
3820+ return -ENOENT;
3821+
3822+ psi = cgroup_psi(cgrp);
3823+ if (psi->enabled != enable) {
3824+ int i;
3825+
3826+ /* show or hide {cpu,memory,io,irq}.pressure files */
3827+ for (i = 0; i < NR_PSI_RESOURCES; i++)
3828+ cgroup_file_show(&cgrp->psi_files[i], enable);
3829+
3830+ psi->enabled = enable;
3831+ if (enable)
3832+ psi_cgroup_restart(psi);
3833+ }
3834+
3835+ cgroup_kn_unlock(of->kn);
3836+
3837+ return nbytes;
37733838 }
37743839
37753840 static __poll_t cgroup_pressure_poll(struct kernfs_open_file *of,
@@ -3789,6 +3854,9 @@ static void cgroup_pressure_release(struct kernfs_open_file *of) · 13 unmodified lines
37893854
37903855 bool cgroup_psi_enabled(void)
37913856 {
3857+ if (static_branch_likely(&psi_disabled))
3858+ return false;
3859+
37923860 return (cgroup_feature_disable_mask & (1 << OPT_FEATURE_PRESSURE)) == 0;
37933861 }
37943862
@@ -5175,6 +5243,7 @@ static struct cftype cgroup_psi_files[] = { · 1380 unmodified lines
51755243 #ifdef CONFIG_PSI
51765244 {
51775245 .name = "io.pressure",
5246+ .file_offset = offsetof(struct cgroup, psi_files[PSI_IO]),
51785247 .seq_show = cgroup_io_pressure_show,
51795248 .write = cgroup_io_pressure_write,
51805249 .poll = cgroup_pressure_poll,
@@ -5182,6 +5251,7 @@ static struct cftype cgroup_psi_files[] = { · 1 unmodified line
51825251 },
51835252 {
51845253 .name = "memory.pressure",
5254+ .file_offset = offsetof(struct cgroup, psi_files[PSI_MEM]),
51855255 .seq_show = cgroup_memory_pressure_show,
51865256 .write = cgroup_memory_pressure_write,
51875257 .poll = cgroup_pressure_poll,
@@ -5189,11 +5259,27 @@ static struct cftype cgroup_psi_files[] = { · 1 unmodified line
51895259 },
51905260 {
51915261 .name = "cpu.pressure",
5262+ .file_offset = offsetof(struct cgroup, psi_files[PSI_CPU]),
51925263 .seq_show = cgroup_cpu_pressure_show,
51935264 .write = cgroup_cpu_pressure_write,
51945265 .poll = cgroup_pressure_poll,
51955266 .release = cgroup_pressure_release,
51965267 },
5268+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
5269+ {
5270+ .name = "irq.pressure",
5271+ .file_offset = offsetof(struct cgroup, psi_files[PSI_IRQ]),
5272+ .seq_show = cgroup_irq_pressure_show,
5273+ .write = cgroup_irq_pressure_write,
5274+ .poll = cgroup_pressure_poll,
5275+ .release = cgroup_pressure_release,
5276+ },
5277+#endif
5278+ {
5279+ .name = "cgroup.pressure",
5280+ .seq_show = cgroup_pressure_show,
5281+ .write = cgroup_pressure_write,
5282+ },
51975283 #endif /* CONFIG_PSI */
51985284 { } /* terminate */
51995285 };
kernel/sched/core.c+1−0
@@ -701,6 +701,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta) · 700 unmodified lines
701701
702702 rq->prev_irq_time += irq_delta;
703703 delta -= irq_delta;
704+ psi_account_irqtime(rq->curr, irq_delta);
704705 #endif
705706 #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
706707 if (static_key_false((&paravirt_steal_rq_enabled))) {
kernel/sched/psi.c+206−74
@@ -181,6 +181,7 @@ static void group_init(struct psi_group *group) · 180 unmodified lines
181181 {
182182 int cpu;
183183
184+ group->enabled = true;
184185 for_each_possible_cpu(cpu)
185186 seqcount_init(&per_cpu_ptr(group->pcpu, cpu)->seq);
186187 group->avg_last_update = sched_clock();
@@ -201,6 +202,7 @@ void __init psi_init(void) · 14 unmodified lines
201202 {
202203 if (!psi_enable) {
203204 static_branch_enable(&psi_disabled);
205+ static_branch_disable(&psi_cgroups_enabled);
204206 return;
205207 }
206208
@@ -211,7 +213,7 @@ void __init psi_init(void) · 4 unmodified lines
211213 group_init(&psi_system);
212214 }
213215
214−static bool test_state(unsigned int *tasks, enum psi_states state)
216+static bool test_state(unsigned int *tasks, enum psi_states state, bool oncpu)
215217 {
216218 switch (state) {
217219 case PSI_IO_SOME:
@@ -224,9 +226,9 @@ static bool test_state(unsigned int *tasks, enum psi_states state) · 6 unmodified lines
224226 return unlikely(tasks[NR_MEMSTALL] &&
225227 tasks[NR_RUNNING] == tasks[NR_MEMSTALL_RUNNING]);
226228 case PSI_CPU_SOME:
227− return unlikely(tasks[NR_RUNNING] > tasks[NR_ONCPU]);
229+ return unlikely(tasks[NR_RUNNING] > oncpu);
228230 case PSI_CPU_FULL:
229− return unlikely(tasks[NR_RUNNING] && !tasks[NR_ONCPU]);
231+ return unlikely(tasks[NR_RUNNING] && !oncpu);
230232 case PSI_NONIDLE:
231233 return tasks[NR_IOWAIT] || tasks[NR_MEMSTALL] ||
232234 tasks[NR_RUNNING];
@@ -688,35 +690,53 @@ static void psi_group_change(struct psi_group *group, int cpu, · 455 unmodified lines
688690 bool wake_clock)
689691 {
690692 struct psi_group_cpu *groupc;
691− u32 state_mask = 0;
692693 unsigned int t, m;
693694 enum psi_states s;
695+ u32 state_mask;
694696
695697 groupc = per_cpu_ptr(group->pcpu, cpu);
696698
697699 /*
698− * First we assess the aggregate resource states this CPU's
699− * tasks have been in since the last change, and account any
700− * SOME and FULL time these may have resulted in.
701− *
702− * Then we update the task counts according to the state
700+ * First we update the task counts according to the state
703701 * change requested through the @clear and @set bits.
702+ *
703+ * Then if the cgroup PSI stats accounting enabled, we
704+ * assess the aggregate resource states this CPU's tasks
705+ * have been in since the last change, and account any
706+ * SOME and FULL time these may have resulted in.
704707 */
705708 write_seqcount_begin(&groupc->seq);
706709
707− record_times(groupc, now);
710+ /*
711+ * Start with TSK_ONCPU, which doesn't have a corresponding
712+ * task count - it's just a boolean flag directly encoded in
713+ * the state mask. Clear, set, or carry the current state if
714+ * no changes are requested.
715+ */
716+ if (unlikely(clear & TSK_ONCPU)) {
717+ state_mask = 0;
718+ clear &= ~TSK_ONCPU;
719+ } else if (unlikely(set & TSK_ONCPU)) {
720+ state_mask = PSI_ONCPU;
721+ set &= ~TSK_ONCPU;
722+ } else {
723+ state_mask = groupc->state_mask & PSI_ONCPU;
724+ }
708725
726+ /*
727+ * The rest of the state mask is calculated based on the task
728+ * counts. Update those first, then construct the mask.
729+ */
709730 for (t = 0, m = clear; m; m &= ~(1 << t), t++) {
710731 if (!(m & (1 << t)))
711732 continue;
712733 if (groupc->tasks[t]) {
713734 groupc->tasks[t]--;
714735 } else if (!psi_bug) {
715− printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u %u %u] clear=%x set=%x\n",
736+ printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u %u] clear=%x set=%x\n",
716737 cpu, t, groupc->tasks[0],
717738 groupc->tasks[1], groupc->tasks[2],
718− groupc->tasks[3], groupc->tasks[4],
719− clear, set);
739+ groupc->tasks[3], clear, set);
720740 psi_bug = 1;
721741 }
722742 }
@@ -725,9 +745,25 @@ static void psi_group_change(struct psi_group *group, int cpu, · 2 unmodified lines
725745 if (set & (1 << t))
726746 groupc->tasks[t]++;
727747
728− /* Calculate state mask representing active states */
748+ if (!group->enabled) {
749+ /*
750+ * On the first group change after disabling PSI, conclude
751+ * the current state and flush its time. This is unlikely
752+ * to matter to the user, but aggregation (get_recent_times)
753+ * may have already incorporated the live state into times_prev;
754+ * avoid a delta sample underflow when PSI is later re-enabled.
755+ */
756+ if (unlikely(groupc->state_mask & (1 << PSI_NONIDLE)))
757+ record_times(groupc, now);
758+
759+ groupc->state_mask = state_mask;
760+
761+ write_seqcount_end(&groupc->seq);
762+ return;
763+ }
764+
729765 for (s = 0; s < NR_PSI_STATES; s++) {
730− if (test_state(groupc->tasks, s))
766+ if (test_state(groupc->tasks, s, state_mask & PSI_ONCPU))
731767 state_mask |= (1 << s);
732768 }
733769
@@ -739,9 +775,11 @@ static void psi_group_change(struct psi_group *group, int cpu, · 5 unmodified lines
739775 * task in a cgroup is in_memstall, the corresponding groupc
740776 * on that cpu is in PSI_MEM_FULL state.
741777 */
742− if (unlikely(groupc->tasks[NR_ONCPU] && cpu_curr(cpu)->in_memstall))
778+ if (unlikely((state_mask & PSI_ONCPU) && cpu_curr(cpu)->in_memstall))
743779 state_mask |= (1 << PSI_MEM_FULL);
744780
781+ record_times(groupc, now);
782+
745783 groupc->state_mask = state_mask;
746784
747785 write_seqcount_end(&groupc->seq);
@@ -753,27 +791,12 @@ static void psi_group_change(struct psi_group *group, int cpu, · 5 unmodified lines
753791 schedule_delayed_work(&group->avgs_work, PSI_FREQ);
754792 }
755793
756−static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
794+static inline struct psi_group *task_psi_group(struct task_struct *task)
757795 {
758− if (*iter == &psi_system)
759− return NULL;
760−
761796 #ifdef CONFIG_CGROUPS
762− if (static_branch_likely(&psi_cgroups_enabled)) {
763− struct cgroup *cgroup = NULL;
764−
765− if (!*iter)
766− cgroup = task->cgroups->dfl_cgrp;
767− else
768− cgroup = cgroup_parent(*iter);
769−
770− if (cgroup && cgroup_parent(cgroup)) {
771− *iter = cgroup;
772− return cgroup_psi(cgroup);
773− }
774− }
797+ if (static_branch_likely(&psi_cgroups_enabled))
798+ return cgroup_psi(task_dfl_cgroup(task));
775799 #endif
776− *iter = &psi_system;
777800 return &psi_system;
778801 }
779802
@@ -796,8 +819,6 @@ void psi_task_change(struct task_struct *task, int clear, int set) · 16 unmodified lines
796819 {
797820 int cpu = task_cpu(task);
798821 struct psi_group *group;
799− bool wake_clock = true;
800− void *iter = NULL;
801822 u64 now;
802823
803824 if (!task->pid)
@@ -806,19 +827,11 @@ void psi_task_change(struct task_struct *task, int clear, int set) · 2 unmodified lines
806827 psi_flags_change(task, clear, set);
807828
808829 now = cpu_clock(cpu);
809− /*
810− * Periodic aggregation shuts off if there is a period of no
811− * task changes, so we wake it back up if necessary. However,
812− * don't do this if the task change is the aggregation worker
813− * itself going to sleep, or we'll ping-pong forever.
814− */
815− if (unlikely((clear & TSK_RUNNING) &&
816− (task->flags & PF_WQ_WORKER) &&
817− wq_worker_last_func(task) == psi_avgs_work))
818− wake_clock = false;
819830
820− while ((group = iterate_groups(task, &iter)))
821− psi_group_change(group, cpu, clear, set, now, wake_clock);
831+ group = task_psi_group(task);
832+ do {
833+ psi_group_change(group, cpu, clear, set, now, true);
834+ } while ((group = group->parent));
822835 }
823836
824837 void psi_task_switch(struct task_struct *prev, struct task_struct *next,
@@ -826,34 +839,30 @@ void psi_task_switch(struct task_struct *prev, struct task_struct *next, · 1 unmodified line
826839 {
827840 struct psi_group *group, *common = NULL;
828841 int cpu = task_cpu(prev);
829− void *iter;
830842 u64 now = cpu_clock(cpu);
831843
832844 if (next->pid) {
833− bool identical_state;
834−
835845 psi_flags_change(next, 0, TSK_ONCPU);
836846 /*
837− * When switching between tasks that have an identical
838− * runtime state, the cgroup that contains both tasks
839− * we reach the first common ancestor. Iterate @next's
840− * ancestors only until we encounter @prev's ONCPU.
847+ * Set TSK_ONCPU on @next's cgroups. If @next shares any
848+ * ancestors with @prev, those will already have @prev's
849+ * TSK_ONCPU bit set, and we can stop the iteration there.
841850 */
842− identical_state = prev->psi_flags == next->psi_flags;
843− iter = NULL;
844− while ((group = iterate_groups(next, &iter))) {
845− if (identical_state &&
846− per_cpu_ptr(group->pcpu, cpu)->tasks[NR_ONCPU]) {
851+ group = task_psi_group(next);
852+ do {
853+ if (per_cpu_ptr(group->pcpu, cpu)->state_mask &
854+ PSI_ONCPU) {
847855 common = group;
848856 break;
849857 }
850858
851859 psi_group_change(group, cpu, 0, TSK_ONCPU, now, true);
852− }
860+ } while ((group = group->parent));
853861 }
854862
855863 if (prev->pid) {
856864 int clear = TSK_ONCPU, set = 0;
865+ bool wake_clock = true;
857866
858867 /*
859868 * When we're going to sleep, psi_dequeue() lets us
@@ -867,26 +876,74 @@ void psi_task_switch(struct task_struct *prev, struct task_struct *next, · 7 unmodified lines
867876 clear |= TSK_MEMSTALL_RUNNING;
868877 if (prev->in_iowait)
869878 set |= TSK_IOWAIT;
879+
880+ /*
881+ * Periodic aggregation shuts off if there is a period of no
882+ * task changes, so we wake it back up if necessary. However,
883+ * don't do this if the task change is the aggregation worker
884+ * itself going to sleep, or we'll ping-pong forever.
885+ */
886+ if (unlikely((prev->flags & PF_WQ_WORKER) &&
887+ wq_worker_last_func(prev) == psi_avgs_work))
888+ wake_clock = false;
870889 }
871890
872891 psi_flags_change(prev, clear, set);
873892
874− iter = NULL;
875− while ((group = iterate_groups(prev, &iter)) && group != common)
876− psi_group_change(group, cpu, clear, set, now, true);
893+ group = task_psi_group(prev);
894+ do {
895+ if (group == common)
896+ break;
897+ psi_group_change(group, cpu, clear, set, now, wake_clock);
898+ } while ((group = group->parent));
877899
878900 /*
879− * TSK_ONCPU is handled up to the common ancestor. If we're tasked
880− * with dequeuing too, finish that for the rest of the hierarchy.
901+ * TSK_ONCPU is handled up to the common ancestor. If there are
902+ * any other differences between the two tasks (e.g. prev goes
903+ * to sleep, or only one task is memstall), finish propagating
904+ * those differences all the way up to the root.
881905 */
882− if (sleep) {
906+ if ((prev->psi_flags ^ next->psi_flags) & ~TSK_ONCPU) {
883907 clear &= ~TSK_ONCPU;
884− for (; group; group = iterate_groups(prev, &iter))
885− psi_group_change(group, cpu, clear, set, now, true);
908+ for (; group; group = group->parent)
909+ psi_group_change(group, cpu, clear, set, now, wake_clock);
886910 }
887911 }
888912 }
889913
914+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
915+void psi_account_irqtime(struct task_struct *task, u32 delta)
916+{
917+ int cpu = task_cpu(task);
918+ struct psi_group *group;
919+ struct psi_group_cpu *groupc;
920+ u64 now;
921+
922+ if (!task->pid)
923+ return;
924+
925+ now = cpu_clock(cpu);
926+
927+ group = task_psi_group(task);
928+ do {
929+ if (!group->enabled)
930+ continue;
931+
932+ groupc = per_cpu_ptr(group->pcpu, cpu);
933+
934+ write_seqcount_begin(&groupc->seq);
935+
936+ record_times(groupc, now);
937+ groupc->times[PSI_IRQ_FULL] += delta;
938+
939+ write_seqcount_end(&groupc->seq);
940+
941+ if (group->poll_states & (1 << PSI_IRQ_FULL))
942+ psi_schedule_poll_work(group, 1);
943+ } while ((group = group->parent));
944+}
945+#endif
946+
890947 /**
891948 * psi_memstall_enter - mark the beginning of a memory stall section
892949 * @flags: flags to handle nested sections
@@ -952,7 +1009,7 @@ EXPORT_SYMBOL_GPL(psi_memstall_leave); · 59 unmodified lines
9521009 #ifdef CONFIG_CGROUPS
9531010 int psi_cgroup_alloc(struct cgroup *cgroup)
9541011 {
955− if (static_branch_likely(&psi_disabled))
1012+ if (!static_branch_likely(&psi_cgroups_enabled))
9561013 return 0;
9571014
9581015 cgroup->psi = kzalloc(sizeof(struct psi_group), GFP_KERNEL);
@@ -965,12 +1022,13 @@ int psi_cgroup_alloc(struct cgroup *cgroup) · 6 unmodified lines
9651022 return -ENOMEM;
9661023 }
9671024 group_init(cgroup->psi);
1025+ cgroup->psi->parent = cgroup_psi(cgroup_parent(cgroup));
9681026 return 0;
9691027 }
9701028
9711029 void psi_cgroup_free(struct cgroup *cgroup)
9721030 {
973− if (static_branch_likely(&psi_disabled))
1031+ if (!static_branch_likely(&psi_cgroups_enabled))
9741032 return;
9751033
9761034 cancel_delayed_work_sync(&cgroup->psi->avgs_work);
@@ -998,7 +1056,7 @@ void cgroup_move_task(struct task_struct *task, struct css_set *to) · 21 unmodified lines
9981056 struct rq_flags rf;
9991057 struct rq *rq;
10001058
1001− if (static_branch_likely(&psi_disabled)) {
1059+ if (!static_branch_likely(&psi_cgroups_enabled)) {
10021060 /*
10031061 * Lame to do this here, but the scheduler cannot be locked
10041062 * from the outside, so we move cgroups from inside sched/.
@@ -1046,10 +1104,45 @@ void cgroup_move_task(struct task_struct *task, struct css_set *to) · 41 unmodified lines
10461104
10471105 task_rq_unlock(rq, task, &rf);
10481106 }
1107+
1108+void psi_cgroup_restart(struct psi_group *group)
1109+{
1110+ int cpu;
1111+
1112+ /*
1113+ * After we disable psi_group->enabled, we don't actually
1114+ * stop percpu tasks accounting in each psi_group_cpu,
1115+ * instead only stop test_state() loop, record_times()
1116+ * and averaging worker, see psi_group_change() for details.
1117+ *
1118+ * When disable cgroup PSI, this function has nothing to sync
1119+ * since cgroup pressure files are hidden and percpu psi_group_cpu
1120+ * would see !psi_group->enabled and only do task accounting.
1121+ *
1122+ * When re-enable cgroup PSI, this function use psi_group_change()
1123+ * to get correct state mask from test_state() loop on tasks[],
1124+ * and restart groupc->state_start from now, use .clear = .set = 0
1125+ * here since no task status really changed.
1126+ */
1127+ if (!group->enabled)
1128+ return;
1129+
1130+ for_each_possible_cpu(cpu) {
1131+ struct rq *rq = cpu_rq(cpu);
1132+ struct rq_flags rf;
1133+ u64 now;
1134+
1135+ rq_lock_irq(rq, &rf);
1136+ now = cpu_clock(cpu);
1137+ psi_group_change(group, cpu, 0, 0, now, true);
1138+ rq_unlock_irq(rq, &rf);
1139+ }
1140+}
10491141 #endif /* CONFIG_CGROUPS */
10501142
10511143 int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
10521144 {
1145+ bool only_full = false;
10531146 int full;
10541147 u64 now;
10551148
@@ -1064,7 +1157,11 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res) · 8 unmodified lines
10641157 group->avg_next_update = update_averages(group, now);
10651158 mutex_unlock(&group->avgs_lock);
10661159
1067− for (full = 0; full < 2; full++) {
1160+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
1161+ only_full = res == PSI_IRQ;
1162+#endif
1163+
1164+ for (full = 0; full < 2 - only_full; full++) {
10681165 unsigned long avg[3] = { 0, };
10691166 u64 total = 0;
10701167 int w;
@@ -1078,7 +1175,7 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res) · 7 unmodified lines
10781175 }
10791176
10801177 seq_printf(m, "%s avg10=%lu.%02lu avg60=%lu.%02lu avg300=%lu.%02lu total=%llu\n",
1081− full ? "full" : "some",
1178+ full || only_full ? "full" : "some",
10821179 LOAD_INT(avg[0]), LOAD_FRAC(avg[0]),
10831180 LOAD_INT(avg[1]), LOAD_FRAC(avg[1]),
10841181 LOAD_INT(avg[2]), LOAD_FRAC(avg[2]),
@@ -1106,6 +1203,11 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, · 21 unmodified lines
11061203 else
11071204 return ERR_PTR(-EINVAL);
11081205
1206+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
1207+ if (res == PSI_IRQ && --state != PSI_IRQ_FULL)
1208+ return ERR_PTR(-EINVAL);
1209+#endif
1210+
11091211 if (state >= PSI_NONIDLE)
11101212 return ERR_PTR(-EINVAL);
11111213
@@ -1390,6 +1492,33 @@ static const struct proc_ops psi_cpu_proc_ops = { · 278 unmodified lines
13901492 .proc_release = psi_fop_release,
13911493 };
13921494
1495+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
1496+static int psi_irq_show(struct seq_file *m, void *v)
1497+{
1498+ return psi_show(m, &psi_system, PSI_IRQ);
1499+}
1500+
1501+static int psi_irq_open(struct inode *inode, struct file *file)
1502+{
1503+ return psi_open(file, psi_irq_show);
1504+}
1505+
1506+static ssize_t psi_irq_write(struct file *file, const char __user *user_buf,
1507+ size_t nbytes, loff_t *ppos)
1508+{
1509+ return psi_write(file, user_buf, nbytes, PSI_IRQ);
1510+}
1511+
1512+static const struct proc_ops psi_irq_proc_ops = {
1513+ .proc_open = psi_irq_open,
1514+ .proc_read = seq_read,
1515+ .proc_lseek = seq_lseek,
1516+ .proc_write = psi_irq_write,
1517+ .proc_poll = psi_fop_poll,
1518+ .proc_release = psi_fop_release,
1519+};
1520+#endif
1521+
13931522 static int __init psi_proc_init(void)
13941523 {
13951524 if (psi_enable) {
@@ -1397,6 +1526,9 @@ static int __init psi_proc_init(void) · 1 unmodified line
13971526 proc_create("pressure/io", 0666, NULL, &psi_io_proc_ops);
13981527 proc_create("pressure/memory", 0666, NULL, &psi_memory_proc_ops);
13991528 proc_create("pressure/cpu", 0666, NULL, &psi_cpu_proc_ops);
1529+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
1530+ proc_create("pressure/irq", 0666, NULL, &psi_irq_proc_ops);
1531+#endif
14001532 }
14011533 return 0;
14021534 }
kernel/sched/stats.h+6−0
@@ -107,6 +107,11 @@ __schedstats_from_se(struct sched_entity *se) · 106 unmodified lines
107107 }
108108
109109 #ifdef CONFIG_PSI
110+void psi_task_change(struct task_struct *task, int clear, int set);
111+void psi_task_switch(struct task_struct *prev, struct task_struct *next,
112+ bool sleep);
113+void psi_account_irqtime(struct task_struct *task, u32 delta);
114+
110115 /*
111116 * PSI tracks state that persists across sleeps, such as iowaits and
112117 * memory stalls. As a result, it has to distinguish between sleeps,
@@ -201,6 +206,7 @@ static inline void psi_ttwu_dequeue(struct task_struct *p) {} · 88 unmodified lines
201206 static inline void psi_sched_switch(struct task_struct *prev,
202207 struct task_struct *next,
203208 bool sleep) {}
209+static inline void psi_account_irqtime(struct task_struct *task, u32 delta) {}
204210 #endif /* CONFIG_PSI */
205211
206212 #ifdef CONFIG_SCHED_INFO