History

[PATCH] idle cputime accounting

The cpu time spent by the idle process actually doing something is currently accounted as idle time. This is plain wrong, the architectures that support VIRT_CPU_ACCOUNTING=y can do better: distinguish between the time spent doing nothing and the time spent by idle doing work. The first is accounted with account_idle_time and the second with account_system_time. The architectures that use the account_xxx_time interface directly and not the account_xxx_ticks interface now need to do the check for the idle process in their arch code. In particular to improve the system vs true idle time accounting the arch code needs to measure the true idle time instead of just testing for the idle process. To improve the tick based accounting as well we would need an architecture primitive that can tell us if the pt_regs of the interrupted context points to the magic instruction that halts the cpu. In addition idle time is no more added to the stime of the idle process. This field now contains the system time of the idle process as it should be. On systems without VIRT_CPU_ACCOUNTING this will always be zero as every tick that occurs while idle is running will be accounted as idle time. This patch contains the necessary common code changes to be able to distinguish idle system time and true idle time. The architectures with support for VIRT_CPU_ACCOUNTING need some changes to exploit this.

Martin Schwidefsky committed 17 years ago

Commit 79741dd1 parent 457533a10 files · +114 −54Browse files

Unified · Split

10 files
  1. arch/ia64/kernel/time.c +8 −2
  2. arch/powerpc/kernel/process.c +1 −0
  3. arch/powerpc/kernel/time.c +10 −3
  4. arch/s390/kernel/vtime.c +16 −4
  5. arch/x86/xen/time.c +4 −6
  6. include/linux/kernel_stat.h +6 −1
  7. include/linux/sched.h +0 −1
  8. kernel/sched.c +63 −17
  9. kernel/time/tick-sched.c +6 −7
  10. kernel/timer.c +0 −13
arch/ia64/kernel/time.c+8−2
@@ -93,7 +93,10 @@ void ia64_account_on_switch(struct task_struct *prev, struct task_struct *next) · 92 unmodified lines
9393 now = ia64_get_itc();
9494
9595 delta_stime = cycle_to_cputime(pi->ac_stime + (now - pi->ac_stamp));
96− account_system_time(prev, 0, delta_stime, delta_stime);
96+ if (idle_task(smp_processor_id()) != prev)
97+ account_system_time(prev, 0, delta_stime, delta_stime);
98+ else
99+ account_idle_time(delta_stime);
97100
98101 if (pi->ac_utime) {
99102 delta_utime = cycle_to_cputime(pi->ac_utime);
@@ -120,7 +123,10 @@ void account_system_vtime(struct task_struct *tsk) · 20 unmodified lines
120123 now = ia64_get_itc();
121124
122125 delta_stime = cycle_to_cputime(ti->ac_stime + (now - ti->ac_stamp));
123− account_system_time(tsk, 0, delta_stime, delta_stime);
126+ if (irq_count() || idle_task(smp_processor_id()) != tsk)
127+ account_system_time(tsk, 0, delta_stime, delta_stime);
128+ else
129+ account_idle_time(delta_stime);
124130 ti->ac_stime = 0;
125131
126132 ti->ac_stamp = now;
arch/powerpc/kernel/process.c+1−0
@@ -33,6 +33,7 @@ · 32 unmodified lines
3333 #include <linux/mqueue.h>
3434 #include <linux/hardirq.h>
3535 #include <linux/utsname.h>
36+#include <linux/kernel_stat.h>
3637
3738 #include <asm/pgtable.h>
3839 #include <asm/uaccess.h>
arch/powerpc/kernel/time.c+10−3
@@ -256,7 +256,10 @@ void account_system_vtime(struct task_struct *tsk) · 255 unmodified lines
256256 delta += sys_time;
257257 get_paca()->system_time = 0;
258258 }
259− account_system_time(tsk, 0, delta, deltascaled);
259+ if (in_irq() || idle_task(smp_processor_id()) != tsk)
260+ account_system_time(tsk, 0, delta, deltascaled);
261+ else
262+ account_idle_time(delta);
260263 per_cpu(cputime_last_delta, smp_processor_id()) = delta;
261264 per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
262265 local_irq_restore(flags);
@@ -335,8 +338,12 @@ void calculate_steal_time(void) · 72 unmodified lines
335338 tb = mftb();
336339 purr = mfspr(SPRN_PURR);
337340 stolen = (tb - pme->tb) - (purr - pme->purr);
338− if (stolen > 0)
339− account_steal_time(current, stolen);
341+ if (stolen > 0) {
342+ if (idle_task(smp_processor_id()) != current)
343+ account_steal_time(stolen);
344+ else
345+ account_idle_time(stolen);
346+ }
340347 pme->tb = tb;
341348 pme->purr = purr;
342349 }
arch/s390/kernel/vtime.c+16−4
@@ -55,13 +55,19 @@ void account_process_tick(struct task_struct *tsk, int user_tick) · 54 unmodified lines
5555 cputime = S390_lowcore.system_timer >> 12;
5656 S390_lowcore.system_timer -= cputime << 12;
5757 S390_lowcore.steal_clock -= cputime << 12;
58− account_system_time(tsk, HARDIRQ_OFFSET, cputime, cputime);
58+ if (idle_task(smp_processor_id()) != current)
59+ account_system_time(tsk, HARDIRQ_OFFSET, cputime, cputime);
60+ else
61+ account_idle_time(cputime);
5962
6063 cputime = S390_lowcore.steal_clock;
6164 if ((__s64) cputime > 0) {
6265 cputime >>= 12;
6366 S390_lowcore.steal_clock -= cputime << 12;
64− account_steal_time(tsk, cputime);
67+ if (idle_task(smp_processor_id()) != current)
68+ account_steal_time(cputime);
69+ else
70+ account_idle_time(cputime);
6571 }
6672 }
6773
@@ -87,7 +93,10 @@ void account_vtime(struct task_struct *tsk) · 19 unmodified lines
8793 cputime = S390_lowcore.system_timer >> 12;
8894 S390_lowcore.system_timer -= cputime << 12;
8995 S390_lowcore.steal_clock -= cputime << 12;
90− account_system_time(tsk, 0, cputime, cputime);
96+ if (idle_task(smp_processor_id()) != current)
97+ account_system_time(tsk, 0, cputime, cputime);
98+ else
99+ account_idle_time(cputime);
91100 }
92101
93102 /*
@@ -107,7 +116,10 @@ void account_system_vtime(struct task_struct *tsk) · 13 unmodified lines
107116 cputime = S390_lowcore.system_timer >> 12;
108117 S390_lowcore.system_timer -= cputime << 12;
109118 S390_lowcore.steal_clock -= cputime << 12;
110− account_system_time(tsk, 0, cputime, cputime);
119+ if (in_irq() || idle_task(smp_processor_id()) != current)
120+ account_system_time(tsk, 0, cputime, cputime);
121+ else
122+ account_idle_time(cputime);
111123 }
112124 EXPORT_SYMBOL_GPL(account_system_vtime);
113125
arch/x86/xen/time.c+4−6
@@ -132,8 +132,7 @@ static void do_stolen_accounting(void) · 131 unmodified lines
132132 *snap = state;
133133
134134 /* Add the appropriate number of ticks of stolen time,
135− including any left-overs from last time. Passing NULL to
136− account_steal_time accounts the time as stolen. */
135+ including any left-overs from last time. */
137136 stolen = runnable + offline + __get_cpu_var(residual_stolen);
138137
139138 if (stolen < 0)
@@ -141,11 +140,10 @@ static void do_stolen_accounting(void) · 1 unmodified line
141140
142141 ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
143142 __get_cpu_var(residual_stolen) = stolen;
144− account_steal_time(NULL, ticks);
143+ account_steal_ticks(ticks);
145144
146145 /* Add the appropriate number of ticks of blocked time,
147− including any left-overs from last time. Passing idle to
148− account_steal_time accounts the time as idle/wait. */
146+ including any left-overs from last time. */
149147 blocked += __get_cpu_var(residual_blocked);
150148
151149 if (blocked < 0)
@@ -153,7 +151,7 @@ static void do_stolen_accounting(void) · 1 unmodified line
153151
154152 ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
155153 __get_cpu_var(residual_blocked) = blocked;
156− account_steal_time(idle_task(smp_processor_id()), ticks);
154+ account_idle_ticks(ticks);
157155 }
158156
159157 /*
include/linux/kernel_stat.h+6−1
@@ -81,6 +81,11 @@ static inline unsigned int kstat_irqs(unsigned int irq) · 80 unmodified lines
8181 extern unsigned long long task_delta_exec(struct task_struct *);
8282 extern void account_user_time(struct task_struct *, cputime_t, cputime_t);
8383 extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t);
84−extern void account_steal_time(struct task_struct *, cputime_t);
84+extern void account_steal_time(cputime_t);
85+extern void account_idle_time(cputime_t);
86+
87+extern void account_process_tick(struct task_struct *, int user);
88+extern void account_steal_ticks(unsigned long ticks);
89+extern void account_idle_ticks(unsigned long ticks);
8590
8691 #endif /* _LINUX_KERNEL_STAT_H */
include/linux/sched.h+0−1
@@ -284,7 +284,6 @@ long io_schedule_timeout(long timeout); · 283 unmodified lines
284284
285285 extern void cpu_init (void);
286286 extern void trap_init(void);
287−extern void account_process_tick(struct task_struct *task, int user);
288287 extern void update_process_times(int user);
289288 extern void scheduler_tick(void);
290289
kernel/sched.c+63−17
@@ -4139,7 +4139,6 @@ void account_system_time(struct task_struct *p, int hardirq_offset, · 4138 unmodified lines
41394139 cputime_t cputime, cputime_t cputime_scaled)
41404140 {
41414141 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
4142− struct rq *rq = this_rq();
41434142 cputime64_t tmp;
41444143
41454144 if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
@@ -4158,37 +4157,84 @@ void account_system_time(struct task_struct *p, int hardirq_offset, · 12 unmodified lines
41584157 cpustat->irq = cputime64_add(cpustat->irq, tmp);
41594158 else if (softirq_count())
41604159 cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
4161− else if (p != rq->idle)
4162− cpustat->system = cputime64_add(cpustat->system, tmp);
4163− else if (atomic_read(&rq->nr_iowait) > 0)
4164− cpustat->iowait = cputime64_add(cpustat->iowait, tmp);
41654160 else
4166− cpustat->idle = cputime64_add(cpustat->idle, tmp);
4161+ cpustat->system = cputime64_add(cpustat->system, tmp);
4162+
41674163 /* Account for system time used */
41684164 acct_update_integrals(p);
41694165 }
41704166
41714167 /*
41724168 * Account for involuntary wait time.
4173− * @p: the process from which the cpu time has been stolen
41744169 * @steal: the cpu time spent in involuntary wait
41754170 */
4176−void account_steal_time(struct task_struct *p, cputime_t steal)
4171+void account_steal_time(cputime_t cputime)
4172+{
4173+ struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
4174+ cputime64_t cputime64 = cputime_to_cputime64(cputime);
4175+
4176+ cpustat->steal = cputime64_add(cpustat->steal, cputime64);
4177+}
4178+
4179+/*
4180+ * Account for idle time.
4181+ * @cputime: the cpu time spent in idle wait
4182+ */
4183+void account_idle_time(cputime_t cputime)
41774184 {
41784185 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
4179− cputime64_t tmp = cputime_to_cputime64(steal);
4186+ cputime64_t cputime64 = cputime_to_cputime64(cputime);
41804187 struct rq *rq = this_rq();
41814188
4182− if (p == rq->idle) {
4183− p->stime = cputime_add(p->stime, steal);
4184− if (atomic_read(&rq->nr_iowait) > 0)
4185− cpustat->iowait = cputime64_add(cpustat->iowait, tmp);
4186− else
4187− cpustat->idle = cputime64_add(cpustat->idle, tmp);
4188− } else
4189− cpustat->steal = cputime64_add(cpustat->steal, tmp);
4189+ if (atomic_read(&rq->nr_iowait) > 0)
4190+ cpustat->iowait = cputime64_add(cpustat->iowait, cputime64);
4191+ else
4192+ cpustat->idle = cputime64_add(cpustat->idle, cputime64);
4193+}
4194+
4195+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
4196+
4197+/*
4198+ * Account a single tick of cpu time.
4199+ * @p: the process that the cpu time gets accounted to
4200+ * @user_tick: indicates if the tick is a user or a system tick
4201+ */
4202+void account_process_tick(struct task_struct *p, int user_tick)
4203+{
4204+ cputime_t one_jiffy = jiffies_to_cputime(1);
4205+ cputime_t one_jiffy_scaled = cputime_to_scaled(one_jiffy);
4206+ struct rq *rq = this_rq();
4207+
4208+ if (user_tick)
4209+ account_user_time(p, one_jiffy, one_jiffy_scaled);
4210+ else if (p != rq->idle)
4211+ account_system_time(p, HARDIRQ_OFFSET, one_jiffy,
4212+ one_jiffy_scaled);
4213+ else
4214+ account_idle_time(one_jiffy);
4215+}
4216+
4217+/*
4218+ * Account multiple ticks of steal time.
4219+ * @p: the process from which the cpu time has been stolen
4220+ * @ticks: number of stolen ticks
4221+ */
4222+void account_steal_ticks(unsigned long ticks)
4223+{
4224+ account_steal_time(jiffies_to_cputime(ticks));
4225+}
4226+
4227+/*
4228+ * Account multiple ticks of idle time.
4229+ * @ticks: number of stolen ticks
4230+ */
4231+void account_idle_ticks(unsigned long ticks)
4232+{
4233+ account_idle_time(jiffies_to_cputime(ticks));
41904234 }
41914235
4236+#endif
4237+
41924238 /*
41934239 * Use precise platform statistics if available:
41944240 */
kernel/time/tick-sched.c+6−7
@@ -419,8 +419,9 @@ void tick_nohz_restart_sched_tick(void) · 418 unmodified lines
419419 {
420420 int cpu = smp_processor_id();
421421 struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
422+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
422423 unsigned long ticks;
423− cputime_t cputime;
424+#endif
424425 ktime_t now;
425426
426427 local_irq_disable();
@@ -442,6 +443,7 @@ void tick_nohz_restart_sched_tick(void) · 15 unmodified lines
442443 tick_do_update_jiffies64(now);
443444 cpu_clear(cpu, nohz_cpu_mask);
444445
446+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
445447 /*
446448 * We stopped the tick in idle. Update process times would miss the
447449 * time we slept as update_process_times does only a 1 tick
@@ -451,12 +453,9 @@ void tick_nohz_restart_sched_tick(void) · 3 unmodified lines
451453 /*
452454 * We might be one off. Do not randomly account a huge number of ticks!
453455 */
454− if (ticks && ticks < LONG_MAX) {
455− add_preempt_count(HARDIRQ_OFFSET);
456− cputime = jiffies_to_cputime(ticks);
457− account_system_time(current, HARDIRQ_OFFSET, cputime, cputime);
458− sub_preempt_count(HARDIRQ_OFFSET);
459− }
456+ if (ticks && ticks < LONG_MAX)
457+ account_idle_ticks(ticks);
458+#endif
460459
461460 touch_softlockup_watchdog();
462461 /*
kernel/timer.c+0−13
@@ -1018,19 +1018,6 @@ unsigned long get_next_timer_interrupt(unsigned long now) · 1017 unmodified lines
10181018 }
10191019 #endif
10201020
1021−#ifndef CONFIG_VIRT_CPU_ACCOUNTING
1022−void account_process_tick(struct task_struct *p, int user_tick)
1023−{
1024− cputime_t one_jiffy = jiffies_to_cputime(1);
1025−
1026− if (user_tick)
1027− account_user_time(p, one_jiffy, cputime_to_scaled(one_jiffy));
1028− else
1029− account_system_time(p, HARDIRQ_OFFSET, one_jiffy,
1030− cputime_to_scaled(one_jiffy));
1031−}
1032−#endif
1033−
10341021 /*
10351022 * Called from the timer interrupt handler to charge one tick to the current
10361023 * process. user_tick is 1 if the tick is user time, 0 for system.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t