aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched.c
diff options
context:
space:
mode:
authorVenkatesh Pallipadi <venki@google.com>2010-12-21 20:09:03 -0500
committerIngo Molnar <mingo@elte.hu>2011-01-26 06:33:21 -0500
commitabb74cefa9c682fb38ba86c17ca3c86fed6cc464 (patch)
tree6a2cbcbb8d509c607cd61051d18ebd6019855aaf /kernel/sched.c
parent70a89a6620f658d47a1488515bada4b8ee6291d8 (diff)
sched: Export ns irqtimes through /proc/stat
CONFIG_IRQ_TIME_ACCOUNTING adds ns granularity irq time on each CPU. This info is already used in scheduler to do proper task chargeback (earlier patches). This patch retro-fits this ns granularity hardirq and softirq information to /proc/stat irq and softirq fields. The update is still done on timer tick, where we look at accumulated ns hardirq/softirq time and account the tick to user/system/irq/hardirq/guest accordingly. No new interface added. Earlier versions looked at adding this as new fields in some /proc files. This one seems to be the best in terms of impact to existing apps, even though it has somewhat more kernel code than earlier versions. Tested-by: Shaun Ruffell <sruffell@digium.com> Signed-off-by: Venkatesh Pallipadi <venki@google.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1292980144-28796-5-git-send-email-venki@google.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index e3fa92106ed7..2a3c9799d76b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1920,8 +1920,40 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
1920 sched_rt_avg_update(rq, irq_delta); 1920 sched_rt_avg_update(rq, irq_delta);
1921} 1921}
1922 1922
1923static int irqtime_account_hi_update(void)
1924{
1925 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
1926 unsigned long flags;
1927 u64 latest_ns;
1928 int ret = 0;
1929
1930 local_irq_save(flags);
1931 latest_ns = this_cpu_read(cpu_hardirq_time);
1932 if (cputime64_gt(nsecs_to_cputime64(latest_ns), cpustat->irq))
1933 ret = 1;
1934 local_irq_restore(flags);
1935 return ret;
1936}
1937
1938static int irqtime_account_si_update(void)
1939{
1940 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
1941 unsigned long flags;
1942 u64 latest_ns;
1943 int ret = 0;
1944
1945 local_irq_save(flags);
1946 latest_ns = this_cpu_read(cpu_softirq_time);
1947 if (cputime64_gt(nsecs_to_cputime64(latest_ns), cpustat->softirq))
1948 ret = 1;
1949 local_irq_restore(flags);
1950 return ret;
1951}
1952
1923#else /* CONFIG_IRQ_TIME_ACCOUNTING */ 1953#else /* CONFIG_IRQ_TIME_ACCOUNTING */
1924 1954
1955#define sched_clock_irqtime (0)
1956
1925static void update_rq_clock_task(struct rq *rq, s64 delta) 1957static void update_rq_clock_task(struct rq *rq, s64 delta)
1926{ 1958{
1927 rq->clock_task += delta; 1959 rq->clock_task += delta;
@@ -3621,6 +3653,65 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
3621 __account_system_time(p, cputime, cputime_scaled, target_cputime64); 3653 __account_system_time(p, cputime, cputime_scaled, target_cputime64);
3622} 3654}
3623 3655
3656#ifdef CONFIG_IRQ_TIME_ACCOUNTING
3657/*
3658 * Account a tick to a process and cpustat
3659 * @p: the process that the cpu time gets accounted to
3660 * @user_tick: is the tick from userspace
3661 * @rq: the pointer to rq
3662 *
3663 * Tick demultiplexing follows the order
3664 * - pending hardirq update
3665 * - pending softirq update
3666 * - user_time
3667 * - idle_time
3668 * - system time
3669 * - check for guest_time
3670 * - else account as system_time
3671 *
3672 * Check for hardirq is done both for system and user time as there is
3673 * no timer going off while we are on hardirq and hence we may never get an
3674 * opportunity to update it solely in system time.
3675 * p->stime and friends are only updated on system time and not on irq
3676 * softirq as those do not count in task exec_runtime any more.
3677 */
3678static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
3679 struct rq *rq)
3680{
3681 cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
3682 cputime64_t tmp = cputime_to_cputime64(cputime_one_jiffy);
3683 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
3684
3685 if (irqtime_account_hi_update()) {
3686 cpustat->irq = cputime64_add(cpustat->irq, tmp);
3687 } else if (irqtime_account_si_update()) {
3688 cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
3689 } else if (user_tick) {
3690 account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
3691 } else if (p == rq->idle) {
3692 account_idle_time(cputime_one_jiffy);
3693 } else if (p->flags & PF_VCPU) { /* System time or guest time */
3694 account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled);
3695 } else {
3696 __account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
3697 &cpustat->system);
3698 }
3699}
3700
3701static void irqtime_account_idle_ticks(int ticks)
3702{
3703 int i;
3704 struct rq *rq = this_rq();
3705
3706 for (i = 0; i < ticks; i++)
3707 irqtime_account_process_tick(current, 0, rq);
3708}
3709#else
3710static void irqtime_account_idle_ticks(int ticks) {}
3711static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
3712 struct rq *rq) {}
3713#endif
3714
3624/* 3715/*
3625 * Account for involuntary wait time. 3716 * Account for involuntary wait time.
3626 * @steal: the cpu time spent in involuntary wait 3717 * @steal: the cpu time spent in involuntary wait
@@ -3661,6 +3752,11 @@ void account_process_tick(struct task_struct *p, int user_tick)
3661 cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); 3752 cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
3662 struct rq *rq = this_rq(); 3753 struct rq *rq = this_rq();
3663 3754
3755 if (sched_clock_irqtime) {
3756 irqtime_account_process_tick(p, user_tick, rq);
3757 return;
3758 }
3759
3664 if (user_tick) 3760 if (user_tick)
3665 account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); 3761 account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
3666 else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) 3762 else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
@@ -3686,6 +3782,12 @@ void account_steal_ticks(unsigned long ticks)
3686 */ 3782 */
3687void account_idle_ticks(unsigned long ticks) 3783void account_idle_ticks(unsigned long ticks)
3688{ 3784{
3785
3786 if (sched_clock_irqtime) {
3787 irqtime_account_idle_ticks(ticks);
3788 return;
3789 }
3790
3689 account_idle_time(jiffies_to_cputime(ticks)); 3791 account_idle_time(jiffies_to_cputime(ticks));
3690} 3792}
3691 3793