Skip to contentSkip to conversation

cpuacct: VIRT_CPU_ACCOUNTING don't prevent percpu cputime count

PATCH In review KOSAKI Motohiro 10 participants 62 messages May 7, 2009 – Jan 28, 2010 Per-CPU memory allocator

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 cpuacct: VIRT_CPU_ACCOUNTING don't prevent percpu cputime count

Changelog:
since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

-------------------------------------
Subject: [PATCH v3] cpuacct: VIRT_CPU_ACCOUNTING don't prevent percpu cputime count

cpuacct_update_stats() is called at every tick updating. and it use percpu_counter for avoiding performance degression.

For archs which define VIRT_CPU_ACCOUNTING, every tick would result in >1000 units of cputime updates and since this is much much greater than percpu_batch_counter, we end up taking spinlock on every tick.

This patch change batch rule. now, any cpu can store "percpu_counter_bach * jiffies" cputime in per-cpu cache.
it mean this patch don't have behavior change if VIRT_CPU_ACCOUNTING=n.

Cc Bharata B Rao <[email protected]>
Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/sched.c +5 -1
Index: b/kernel/sched.c
===================================================================
@@ -10221,6 +10221,7 @@ struct cpuacct {
 };
 
 struct cgroup_subsys cpuacct_subsys;
+static s32 cpuacct_batch;
 
 /* return cpu accounting group corresponding to this container */
 static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
@@ -10250,6 +10251,9 @@ static struct cgroup_subsys_state *cpuac
 	if (!ca->cpuusage)
 		goto out_free_ca;
 
+	if (!cpuacct_batch)
+		cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
 		if (percpu_counter_init(&ca->cpustat[i], 0))
 			goto out_free_counters;
@@ -10446,7 +10450,7 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#1 lore raw
Quoted 41 lines · KOSAKI Motohiro

Changelog:
since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

-------------------------------------
Subject: [PATCH v3] cpuacct: VIRT_CPU_ACCOUNTING don't prevent percpu cputime count

cpuacct_update_stats() is called at every tick updating. and it use percpu_counter for avoiding performance degression.

For archs which define VIRT_CPU_ACCOUNTING, every tick would result in >1000 units of cputime updates and since this is much much greater than percpu_batch_counter, we end up taking spinlock on every tick.

This patch change batch rule. now, any cpu can store "percpu_counter_bach * jiffies" cputime in per-cpu cache.
it mean this patch don't have behavior change if VIRT_CPU_ACCOUNTING=n.

Cc Bharata B Rao <[email protected]>
Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Index: b/kernel/sched.c
===================================================================

kernel/sched.c struct cpuacct { · line 10224

Quoted 4 lines
kernel/sched.c +1 -0
@@ -10221,6 +10221,7 @@ struct cpuacct {
 };
 
 struct cgroup_subsys cpuacct_subsys;
+static s32 cpuacct_batch;

should be __read_mostly i guess.

kernel/sched.c static struct cgroup_subsys_state *cpuac · line 10255

Quoted 9 lines
kernel/sched.c +2 -0
 /* return cpu accounting group corresponding to this container */
 static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
@@ -10250,6 +10251,9 @@ static struct cgroup_subsys_state *cpuac
 	if (!ca->cpuusage)
 		goto out_free_ca;
 
+	if (!cpuacct_batch)
+		cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);

So this is a once per boot condition? Why not initialize it in sched_init() or so? (instead of incuring this ugly check all the time)

Ingo

#2 lore raw
Quoted 58 lines · KOSAKI Motohiro
Quoted 42 lines

Changelog:
since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

-------------------------------------
Subject: [PATCH v3] cpuacct: VIRT_CPU_ACCOUNTING don't prevent percpu cputime count

cpuacct_update_stats() is called at every tick updating. and it use percpu_counter for avoiding performance degression.

For archs which define VIRT_CPU_ACCOUNTING, every tick would result in >1000 units of cputime updates and since this is much much greater than percpu_batch_counter, we end up taking spinlock on every tick.

This patch change batch rule. now, any cpu can store "percpu_counter_bach * jiffies" cputime in per-cpu cache.
it mean this patch don't have behavior change if VIRT_CPU_ACCOUNTING=n.

Cc Bharata B Rao <[email protected]>
Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Index: b/kernel/sched.c
===================================================================

kernel/sched.c struct cpuacct { · line 10224

Quoted 4 lines
kernel/sched.c +1 -0
@@ -10221,6 +10221,7 @@ struct cpuacct {
 };
 
 struct cgroup_subsys cpuacct_subsys;
+static s32 cpuacct_batch;

should be __read_mostly i guess.

Quoted 7 lines
kernel/sched.c +0 -0
 /* return cpu accounting group corresponding to this container */
 static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
@@ -10250,6 +10251,9 @@ static struct cgroup_subsys_state *cpuac
 	if (!ca->cpuusage)
 		goto out_free_ca;
 
Quoted 6 lines

kernel/sched.c static struct cgroup_subsys_state *cpuac · line 10255

Quoted 2 lines
kernel/sched.c +2 -0
+	if (!cpuacct_batch)
+		cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);

So this is a once per boot condition? Why not initialize it in sched_init() or so? (instead of incuring this ugly check all the time)

Thanks! fixed.

Changelog:
since V3
- rewirte patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init()

since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

---------------------------------------------------------
Subject: [PATCH v4] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
kernel/sched.c +6 -1
Index: b/kernel/sched.c
===================================================================
@@ -824,8 +824,12 @@ static struct file_operations sched_feat
 	.release	= single_release,
 };
 
+static __read_mostly s32 cpuacct_batch;
+
 static __init int sched_init_debug(void)
 {
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
 	debugfs_create_file("sched_features", 0644, NULL, NULL,
 			&sched_feat_fops);
 
@@ -10457,7 +10461,8 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#3 lore raw
Quoted 7 lines · KOSAKI Motohiro

Index: b/kernel/sched.c
===================================================================

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +0 -0
@@ -824,8 +824,12 @@ static struct file_operations sched_feat
        .release        = single_release,

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 static struct file_operations sched_feat · line 834

Quoted 10 lines
kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +4 -0
 };
 
+static __read_mostly s32 cpuacct_batch;
+
 static __init int sched_init_debug(void)
 {
+       cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
        debugfs_create_file("sched_features", 0644, NULL, NULL,
                        &sched_feat_fops);

I'm pretty user you can select cpu accounting without SCHED_DEBUG...

Quoted 11 lines
kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +2 -1
@@ -10457,7 +10461,8 @@ static void cpuacct_update_stats(struct 
        ca = task_ca(tsk);
 
        do {
-               percpu_counter_add(&ca->cpustat[idx], val);
+               __percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
                ca = ca->parent;
        } while (ca);
        rcu_read_unlock();
#4 lore raw
Quoted 10 lines · KOSAKI Motohiro
Quoted 9 lines

Index: b/kernel/sched.c
===================================================================

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +0 -0
@@ -824,8 +824,12 @@ static struct file_operations sched_feat
        .release        = single_release,
 };
 
Quoted 10 lines

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 static struct file_operations sched_feat · line 834

Quoted 8 lines
kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +4 -0
+static __read_mostly s32 cpuacct_batch;
+
 static __init int sched_init_debug(void)
 {
+       cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
        debugfs_create_file("sched_features", 0644, NULL, NULL,
                        &sched_feat_fops);

I'm pretty user you can select cpu accounting without SCHED_DEBUG...

Grr, yes, it's idiot ;)
I'll fix it soon.

#5 lore raw
Quoted 21 lines
Quoted 10 lines · KOSAKI Motohiro
Quoted 9 lines

Index: b/kernel/sched.c
===================================================================

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +0 -0
@@ -824,8 +824,12 @@ static struct file_operations sched_feat
        .release        = single_release,
 };
 
Quoted 10 lines

kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 static struct file_operations sched_feat · line 834

Quoted 8 lines
kernel/sched.c 2009-05-09 18:16:00.000000000 +0900 renamed from kernel/sched.c 2009-05-09 16:48:08.000000000 +0900 +4 -0
+static __read_mostly s32 cpuacct_batch;
+
 static __init int sched_init_debug(void)
 {
+       cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
        debugfs_create_file("sched_features", 0644, NULL, NULL,
                        &sched_feat_fops);

I'm pretty user you can select cpu accounting without SCHED_DEBUG...

Quoted 2 lines

Grr, yes, it's idiot ;)
I'll fix it soon.

Done.

Changelog:
since V4
- move cpuacct_batch initialization into sched_init()

since V3
- rewirte patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init_debug()

since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

---------------------------------------------------------
Subject: [PATCH v5] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
kernel/sched.c +6 -1
Index: b/kernel/sched.c
===================================================================
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9284,6 +9286,8 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
 	scheduler_running = 1;
 }
 
@@ -10457,7 +10461,8 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#6 lore raw

[tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Commit-ID:  0719318fea31d54d13ed8ead7f4a277038bd75a2
Gitweb:     http://git.kernel.org/tip/0719318fea31d54d13ed8ead7f4a277038bd75a2
Author:     KOSAKI Motohiro <[email protected]>
AuthorDate: Sat, 9 May 2009 19:14:58 +0900
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 11 May 2009 14:21:32 +0200

sched: cpuacct: Use bigger percpu counter batch values for stats counters

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

v5:
- move cpuacct_batch initialization into sched_init()

v4:
- rewrite patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init_debug()

v3:
- revert using percpu_counter_sum()

v2:
- use percpu_counter_sum() instead percpu_counter_read()

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Martin Schwidefsky <[email protected]>
Cc KOSAKI Motohiro <[email protected]>

LKML-Reference: <[email protected]>

---
 kernel/sched.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)
kernel/sched.c +6 -1
index 8908d19..beadb82 100644
@@ -872,6 +872,8 @@ static __read_mostly int scheduler_running;
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9181,6 +9183,8 @@ void __init sched_init(void)
 	alloc_bootmem_cpumask_var(&cpu_isolated_map);
 #endif /* SMP */
 
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
 	scheduler_running = 1;
 }
 
@@ -10354,7 +10358,8 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#7 lore raw

[tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to KOSAKI Motohiro
Commit-ID:  50fbed3bb72cbe38a665512771a91a96d028de46
Gitweb:     http://git.kernel.org/tip/50fbed3bb72cbe38a665512771a91a96d028de46
Author:     KOSAKI Motohiro <[email protected]>
AuthorDate: Sat, 9 May 2009 19:14:58 +0900
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 11 May 2009 14:32:57 +0200

sched: cpuacct: Use bigger percpu counter batch values for stats counters

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

v5:
- move cpuacct_batch initialization into sched_init()

v4:
- rewrite patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init_debug()

v3:
- revert using percpu_counter_sum()

v2:
- use percpu_counter_sum() instead percpu_counter_read()

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Martin Schwidefsky <[email protected]>
Cc KOSAKI Motohiro <[email protected]>

LKML-Reference: <[email protected]>

---
 kernel/sched.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)
kernel/sched.c +6 -1
index 8908d19..873bc3b 100644
@@ -872,6 +872,8 @@ static __read_mostly int scheduler_running;
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9171,6 +9173,8 @@ void __init sched_init(void)
 	 */
 	current->sched_class = &fair_sched_class;
 
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+
 	/* Allocate the nohz_cpu_mask if CONFIG_CPUMASK_OFFSTACK */
 	alloc_bootmem_cpumask_var(&nohz_cpu_mask);
 #ifdef CONFIG_SMP
@@ -10354,7 +10358,8 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#8 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 8 lines · tip-bot for KOSAKI Motohiro
Commit-ID:  50fbed3bb72cbe38a665512771a91a96d028de46
Gitweb:     http://git.kernel.org/tip/50fbed3bb72cbe38a665512771a91a96d028de46
Author:     KOSAKI Motohiro <[email protected]>
AuthorDate: Sat, 9 May 2009 19:14:58 +0900
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 11 May 2009 14:32:57 +0200

sched: cpuacct: Use bigger percpu counter batch values for stats counters

-tip testing found a build failure with this patch:

kernel/sched.c:9278: error: ‘percpu_counter_batch’ undeclared (first use in this function) kernel/sched.c:9278: error: (Each undeclared identifier is reported only once kernel/sched.c:9278: error: for each function it appears in.)

Ingo

#9 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 10 lines · tip-bot for KOSAKI Motohiro
Quoted 8 lines
Commit-ID:  50fbed3bb72cbe38a665512771a91a96d028de46
Gitweb:     http://git.kernel.org/tip/50fbed3bb72cbe38a665512771a91a96d028de46
Author:     KOSAKI Motohiro <[email protected]>
AuthorDate: Sat, 9 May 2009 19:14:58 +0900
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 11 May 2009 14:32:57 +0200
Quoted 7 lines
Quoted 1 line

sched: cpuacct: Use bigger percpu counter batch values for stats counters

-tip testing found a build failure with this patch:

kernel/sched.c:9278: error: ‘percpu_counter_batch’ undeclared (first use in this function) kernel/sched.c:9278: error: (Each undeclared identifier is reported only once kernel/sched.c:9278: error: for each function it appears in.)

Oh, my fault again. Good catch!

Changelog:
since V5
- fix build error when UP

since V4
- move cpuacct_batch initialization into sched_init()

since V3
- rewirte patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init()

since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

---------------------------------------------------------
Subject: [PATCH v6] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/sched.c +8 -1
Index: b/kernel/sched.c
===================================================================
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9284,6 +9286,10 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif
+
 	scheduler_running = 1;
 }
 
@@ -10457,7 +10463,8 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#10 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 1 line · KOSAKI Motohiro

+#ifdef CONFIGCONFIG_SMP

typo ?

#11 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 4 lines · KOSAKI Motohiro
Quoted 1 line

+#ifdef CONFIGCONFIG_SMP

typo ?

yes, this week is my memorial stupid one ;)

#12 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 6 lines
Quoted 4 lines · KOSAKI Motohiro
Quoted 1 line

+#ifdef CONFIGCONFIG_SMP

typo ?

yes, this week is my memorial stupid one ;)

ok, assemble list indicate current patch have no typo ;)

ffffffff814ae920:       48 c7 40 30 10 eb 2a    movq   $0xffffffff812aeb10,0x30(%rax)
ffffffff814ae927:       81
ffffffff814ae928:       c7 05 3e 37 fe ff 01    movl   $0x1,-0x1c8c2(%rip)        # ffffffff81492070 <scheduler_running>
ffffffff814ae92f:       00 00 00
ffffffff814ae932:       8b 05 28 52 fe ff       mov    -0x1add8(%rip),%eax        # ffffffff81493b60 <percpu_counter_batch>
ffffffff814ae938:       89 05 36 37 fe ff       mov    %eax,-0x1c8ca(%rip)        # ffffffff81492074 <cpuacct_batch>
ffffffff814ae93e:       41 5c                   pop    %r12

---------------------------------------------------------
Subject: [PATCH] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/sched.c +8 -1
Index: b/kernel/sched.c
===================================================================
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9284,6 +9286,10 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+#ifdef CONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif
+
 	scheduler_running = 1;
 }
 
@@ -10457,7 +10463,8 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#13 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 43 lines · KOSAKI Motohiro
Quoted 6 lines
Quoted 4 lines · KOSAKI Motohiro
Quoted 1 line

+#ifdef CONFIGCONFIG_SMP

typo ?

yes, this week is my memorial stupid one ;)

ok, assemble list indicate current patch have no typo ;)

ffffffff814ae920:       48 c7 40 30 10 eb 2a    movq   $0xffffffff812aeb10,0x30(%rax)
ffffffff814ae927:       81
ffffffff814ae928:       c7 05 3e 37 fe ff 01    movl   $0x1,-0x1c8c2(%rip)        # ffffffff81492070 <scheduler_running>
ffffffff814ae92f:       00 00 00
ffffffff814ae932:       8b 05 28 52 fe ff       mov    -0x1add8(%rip),%eax        # ffffffff81493b60 <percpu_counter_batch>
ffffffff814ae938:       89 05 36 37 fe ff       mov    %eax,-0x1c8ca(%rip)        # ffffffff81492074 <cpuacct_batch>
ffffffff814ae93e:       41 5c                   pop    %r12

---------------------------------------------------------
Subject: [PATCH] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
Quoted 3 lines
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Please reuse the commit log formatting fixes i did when i applied your patch. (you should still have that commit notification email)

Ingo

#14 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 13 lines
Quoted 9 lines
Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
Quoted 3 lines
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
Quoted 2 lines

Please reuse the commit log formatting fixes i did when i applied your patch. (you should still have that commit notification email)

Oh, I didn't notice this change. I'll resend it. thanks

#15 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to KOSAKI Motohiro
Quoted 83 lines · KOSAKI Motohiro
Quoted 10 lines · tip-bot for KOSAKI Motohiro
Quoted 8 lines
Commit-ID:  50fbed3bb72cbe38a665512771a91a96d028de46
Gitweb:     http://git.kernel.org/tip/50fbed3bb72cbe38a665512771a91a96d028de46
Author:     KOSAKI Motohiro <[email protected]>
AuthorDate: Sat, 9 May 2009 19:14:58 +0900
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 11 May 2009 14:32:57 +0200
Quoted 7 lines
Quoted 1 line

sched: cpuacct: Use bigger percpu counter batch values for stats counters

-tip testing found a build failure with this patch:

kernel/sched.c:9278: error: ?$B!Fpercpu_counter_batch?$B!G undeclared (first use in this function) kernel/sched.c:9278: error: (Each undeclared identifier is reported only once kernel/sched.c:9278: error: for each function it appears in.)

Oh, my fault again. Good catch!

Changelog:
since V5
- fix build error when UP

since V4
- move cpuacct_batch initialization into sched_init()

since V3
- rewirte patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init()

since v2
- revert using percpu_counter_sum()

since v1
- use percpu_counter_sum() instead percpu_counter_read()

---------------------------------------------------------
Subject: [PATCH v6] cpuacct: Use bigger percpu counter batch values for stats counters on archs that have VIRT_CPU_ACCOUNTING=y

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Index: b/kernel/sched.c
===================================================================

kernel/sched.c +2 -0
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;

kernel/sched.c void __init sched_init(void) · line 9291

Quoted 6 lines
kernel/sched.c +3 -0
@@ -9284,6 +9286,10 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

Slow down and compile patches before sending them out.. please. That is a basic expectation if you expect it to be merged.

Signature · 1 line
	Balbir
#16 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 6 lines

kernel/sched.c void __init sched_init(void) · line 9291

Quoted 3 lines
kernel/sched.c +3 -0
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

Slow down and compile patches before sending them out.. please. That is a basic expectation if you expect it to be merged.

Unfortunately, this mistake pass test successfully ;) it because cpuacct_batch=0 works even SMP.

#17 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 10 lines · KOSAKI Motohiro
Quoted 6 lines

kernel/sched.c void __init sched_init(void) · line 9291

Quoted 3 lines
kernel/sched.c +3 -0
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

Slow down and compile patches before sending them out.. please. That is a basic expectation if you expect it to be merged.

Unfortunately, this mistake pass test successfully ;) it because cpuacct_batch=0 works even SMP.

OK, BTW, using an #ifdef right in the middle of a function makes the code harder to read, can't we use an inline function to abstract out SMP?

Signature · 1 line
	Balbir
#18 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 9 lines · Balbir Singh
Quoted 7 lines · KOSAKI Motohiro
Quoted 6 lines

kernel/sched.c void __init sched_init(void) · line 9291

Quoted 3 lines
kernel/sched.c +3 -0
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

Slow down and compile patches before sending them out.. please. That is a basic expectation if you expect it to be merged.

Quoted 7 lines
Quoted 3 lines

Unfortunately, this mistake pass test successfully ;) it because cpuacct_batch=0 works even SMP.

OK, BTW, using an #ifdef right in the middle of a function makes the code harder to read, can't we use an inline function to abstract out SMP?

or rather, to make cpuacct_batch have a sane value on UP too. (1? 0?)

Ingo

#19 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 16 lines · Balbir Singh
Quoted 14 lines · KOSAKI Motohiro
Quoted 11 lines
Quoted 7 lines

Review

Quoted 4 lines
(quoted diff) +3 -0
+#ifdef CONFIGCONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

Slow down and compile patches before sending them out.. please. That is a basic expectation if you expect it to be merged.

Unfortunately, this mistake pass test successfully ;) it because cpuacct_batch=0 works even SMP.

Quoted 6 lines
Quoted 3 lines

OK, BTW, using an #ifdef right in the middle of a function makes the code harder to read, can't we use an inline function to abstract out SMP?

or rather, to make cpuacct_batch have a sane value on UP too. (1? 0?)

umm..

I've reviewed my patch again.
but sched_init() already has multiple #ifdef SMP. Thus I don't think cosmetic changing improve readability largely.

------------------------------------
Subject: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

v7:
- fix typo and changelog

v6:
- fix build error when UP

v5:
- move cpuacct_batch initialization into sched_init()

v4:
- rewrite patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init_debug()

v3:
- revert using percpu_counter_sum()

v2:
- use percpu_counter_sum() instead percpu_counter_read()

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/sched.c +8 -1
Index: b/kernel/sched.c
===================================================================
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
@@ -9284,6 +9286,10 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+#ifdef CONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif
+
 	scheduler_running = 1;
 }
 
@@ -10457,7 +10463,8 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, cpuacct_batch);
+
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#20 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 7 lines · KOSAKI Motohiro
Quoted 2 lines

or rather, to make cpuacct_batch have a sane value on UP too. (1? 0?)

umm..

I've reviewed my patch again.
but sched_init() already has multiple #ifdef SMP. [...]

Patches are welcome to remove more of them.

Quoted 2 lines

[...] Thus I don't think cosmetic changing improve readability largely.

an avoidable #ifdef should aways be avoided.

Ingo

#21 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

2009/5/12 Ingo Molnar <[email protected]>:

Quoted 11 lines · KOSAKI Motohiro
Quoted 8 lines
Quoted 3 lines

or rather, to make cpuacct_batch have a sane value on UP too. (1? 0?)

umm..

I've reviewed my patch again.
but sched_init() already has multiple #ifdef SMP. [...]

Quoted 6 lines

Patches are welcome to remove more of them.

Quoted 2 lines

[...] Thus I don't think cosmetic changing improve readability largely.

an avoidable #ifdef should aways be avoided.

ok. I'll fix it tommorow.

#22 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 12 lines · KOSAKI Motohiro

2009/5/12 Ingo Molnar <[email protected]>:

Quoted 11 lines · KOSAKI Motohiro
Quoted 8 lines
Quoted 3 lines

or rather, to make cpuacct_batch have a sane value on UP too. (1? 0?)

umm..

I've reviewed my patch again.
but sched_init() already has multiple #ifdef SMP. [...]

Quoted 8 lines
Quoted 6 lines

Patches are welcome to remove more of them.

Quoted 2 lines

[...] Thus I don't think cosmetic changing improve readability largely.

an avoidable #ifdef should aways be avoided.

ok. I'll fix it tommorow.

With the caveat that you should do it only if i'm right and if it results in better code in general.

Ingo

#23 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to KOSAKI Motohiro
Quoted 62 lines · KOSAKI Motohiro

------------------------------------
Subject: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

percpu counters used to accumulate statistics in cpuacct controller use the default batch value [max(2*nr_cpus, 32)] which can be too small for archs that define VIRT_CPU_ACCOUNTING. In such archs, a tick could result in cputime updates in the range of thousands. As a result, cpuacct_update_stats() would end up acquiring the percpu counter spinlock on every tick which is not good for performance.

Let those architectures to have a bigger batch threshold so that percpu counter spinlock isn't taken on every tick. This change doesn't affect the archs which don't define VIRT_CPU_ACCOUNTING and they continue to have the default percpu counter batch value.

v7:
- fix typo and changelog

v6:
- fix build error when UP

v5:
- move cpuacct_batch initialization into sched_init()

v4:
- rewrite patch description (thanks Bharata!)
- append read_mostly to cpuacct_batch
- cpuacct_batch is initialized by sched_init_debug()

v3:
- revert using percpu_counter_sum()

v2:
- use percpu_counter_sum() instead percpu_counter_read()

Cc Balaji Rao <[email protected]>
Cc Dhaval Giani <[email protected]>
Cc KAMEZAWA Hiroyuki <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Balbir Singh <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Martin Schwidefsky <[email protected]>
---
 kernel/sched.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Index: b/kernel/sched.c
===================================================================

kernel/sched.c +2 -0
@@ -870,6 +870,8 @@ static __read_mostly int scheduler_runni
  */
 int sysctl_sched_rt_runtime = 950000;
 
+static __read_mostly s32 cpuacct_batch;
+
 static inline u64 global_rt_period(void)
 {
 	return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;

kernel/sched.c void __init sched_init(void) · line 9291

Quoted 6 lines
kernel/sched.c +3 -0
@@ -9284,6 +9286,10 @@ void __init sched_init(void)
 
 	perf_counter_init();
 
+#ifdef CONFIG_SMP
+	cpuacct_batch = jiffies_to_cputime(percpu_counter_batch);
+#endif

On ppc64, calling jiffies_to_cputime() from sched_init() is too early because jiffies_to_cputime() needs tb_ticks_per_sec which gets initialized only later in time_init(). Because of this I see that cpuacct_batch will always be zero effectively negating what this patch is trying to do.

As explained by you earlier, we too are finding the default batch value to be too low for ppc64 with VIRT_CPU_ACCOUNTING turned on. Hence I guess if this patch is taken in (ofcourse with the above issue fixed), it will benefit ppc64 also.

Regards,
Bharata.

#24 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi,

Quoted 9 lines

On ppc64, calling jiffies_to_cputime() from sched_init() is too early because jiffies_to_cputime() needs tb_ticks_per_sec which gets initialized only later in time_init(). Because of this I see that cpuacct_batch will always be zero effectively negating what this patch is trying to do.

As explained by you earlier, we too are finding the default batch value to be too low for ppc64 with VIRT_CPU_ACCOUNTING turned on. Hence I guess if this patch is taken in (ofcourse with the above issue fixed), it will benefit ppc64 also.

I created this patch earlier today when I hit the problem. Thoughts?

Anton
--

When CONFIG_VIRT_CPU_ACCOUNTING is enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock.

Since reading of the CPU accounting cgroup counters is not performance critical, we can use a maximum size batch of INT_MAX and use percpu_counter_sum on the read side which will add all the percpu counters.

With this patch an 8 core POWER6 with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT shows an improvement in aggregate context switch rate of 397k/sec to 3.9M/sec, a 10x improvement.

---

kernel/sched.c +2 -2
Index: linux.trees.git/kernel/sched.c
===================================================================
@@ -10551,7 +10551,7 @@
 	int i;
 
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++) {
-		s64 val = percpu_counter_read(&ca->cpustat[i]);
+		s64 val = percpu_counter_sum(&ca->cpustat[i]);
 		val = cputime64_to_clock_t(val);
 		cb->fill(cb, cpuacct_stat_desc[i], val);
 	}
@@ -10621,7 +10621,7 @@
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, INT_MAX);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#25 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi,

Looks like this issue is still present. I tested on a 32 core box and the patch improved maximum context switch rate from from 76k/sec to 9.5M/sec. Thats over 100x faster, or 50x per line of code. That's got to be some sort of record :)

Any chance we can get a fix in for 2.6.31? Don't make me find an even bigger box so I can break the 200x mark :)

Anton

Quoted 41 lines

--

When CONFIG_VIRT_CPU_ACCOUNTING is enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock.

Since reading of the CPU accounting cgroup counters is not performance critical, we can use a maximum size batch of INT_MAX and use percpu_counter_sum on the read side which will add all the percpu counters.

With this patch an 8 core POWER6 with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT shows an improvement in aggregate context switch rate of 397k/sec to 3.9M/sec, a 10x improvement.

---

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +2 -2
@@ -10551,7 +10551,7 @@
 	int i;
 
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++) {
-		s64 val = percpu_counter_read(&ca->cpustat[i]);
+		s64 val = percpu_counter_sum(&ca->cpustat[i]);
 		val = cputime64_to_clock_t(val);
 		cb->fill(cb, cpuacct_stat_desc[i], val);
 	}
@@ -10621,7 +10621,7 @@
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, INT_MAX);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#26 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 11 lines · On Thu, 20 Aug 2009 15:10:38 +1000 Anton Blanchard <[email protected]> wrote:

Hi,

Looks like this issue is still present. I tested on a 32 core box and the patch improved maximum context switch rate from from 76k/sec to 9.5M/sec. Thats over 100x faster, or 50x per line of code. That's got to be some sort of record :)

Any chance we can get a fix in for 2.6.31? Don't make me find an even bigger box so I can break the 200x mark :)

I like the patch itself, I think it does a correct fix.

Hmm, but, IIRC, there was a discssion "what happens at reading this counter once per 1ms ?" or some.

What overhead at read on big system ? Can you show it ?

Thanks,
-Kame

Quoted 44 lines

Anton

Quoted 41 lines

--

When CONFIG_VIRT_CPU_ACCOUNTING is enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock.

Since reading of the CPU accounting cgroup counters is not performance critical, we can use a maximum size batch of INT_MAX and use percpu_counter_sum on the read side which will add all the percpu counters.

With this patch an 8 core POWER6 with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT shows an improvement in aggregate context switch rate of 397k/sec to 3.9M/sec, a 10x improvement.

---

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +2 -2
@@ -10551,7 +10551,7 @@
 	int i;
 
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++) {
-		s64 val = percpu_counter_read(&ca->cpustat[i]);
+		s64 val = percpu_counter_sum(&ca->cpustat[i]);
 		val = cputime64_to_clock_t(val);
 		cb->fill(cb, cpuacct_stat_desc[i], val);
 	}
@@ -10621,7 +10621,7 @@
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, INT_MAX);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#27 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 8 lines · Anton Blanchard

Hi,

Looks like this issue is still present. I tested on a 32 core box and the patch improved maximum context switch rate from from 76k/sec to 9.5M/sec. Thats over 100x faster, or 50x per line of code. That's got to be some sort of record :)

Quoted 21 lines

Any chance we can get a fix in for 2.6.31? Don't make me find an even bigger box so I can break the 200x mark :)

Anton

Quoted 16 lines

--

When CONFIG_VIRT_CPU_ACCOUNTING is enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock.

Since reading of the CPU accounting cgroup counters is not performance critical, we can use a maximum size batch of INT_MAX and use percpu_counter_sum on the read side which will add all the percpu counters.

With this patch an 8 core POWER6 with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT shows an improvement in aggregate context switch rate of 397k/sec to 3.9M/sec, a 10x improvement.

Looks good overall, why not keep the batch size conditional on CONFIG_VIRT_CPU_ACCOUNTING? I'd still like to stick with percpu_counter_read() on the read side because My concern is that a bad user space application can read cpuacct.stat and bring the kernel to its knees.

Quoted 25 lines
Quoted 25 lines

---

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +2 -2
@@ -10551,7 +10551,7 @@
 	int i;
 
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++) {
-		s64 val = percpu_counter_read(&ca->cpustat[i]);
+		s64 val = percpu_counter_sum(&ca->cpustat[i]);
 		val = cputime64_to_clock_t(val);
 		cb->fill(cb, cpuacct_stat_desc[i], val);
 	}
@@ -10621,7 +10621,7 @@
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, INT_MAX);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
Signature · 1 line
	Balbir
#28 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 5 lines · Balbir Singh

Looks good overall, why not keep the batch size conditional on CONFIG_VIRT_CPU_ACCOUNTING? I'd still like to stick with percpu_counter_read() on the read side because My concern is that a bad user space application can read cpuacct.stat and bring the kernel to its knees.

Agreed, the first hunk is dangerous, on the second hunk, I'm not sure about the INT_MAX thing, that's a 4s gap per cpu, that might be a tad much.

Quoted 26 lines
Quoted 25 lines
Quoted 25 lines

---

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +2 -2
@@ -10551,7 +10551,7 @@
 	int i;
 
 	for (i = 0; i < CPUACCT_STAT_NSTATS; i++) {
-		s64 val = percpu_counter_read(&ca->cpustat[i]);
+		s64 val = percpu_counter_sum(&ca->cpustat[i]);
 		val = cputime64_to_clock_t(val);
 		cb->fill(cb, cpuacct_stat_desc[i], val);
 	}
@@ -10621,7 +10621,7 @@
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, INT_MAX);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#29 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi,

Quoted 3 lines

Agreed, the first hunk is dangerous, on the second hunk, I'm not sure about the INT_MAX thing, that's a 4s gap per cpu, that might be a tad much.

Yeah I somehow missed the fact we read it every timer tick. I was hoping for an easy fix but I guess we just need to set a reasonable batch size at runtime.

Anton

#30 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 11 lines · On Thu, 20 Aug 2009 16:05:28 +1000 Anton Blanchard <[email protected]> wrote:

Hi,

Quoted 3 lines

Agreed, the first hunk is dangerous, on the second hunk, I'm not sure about the INT_MAX thing, that's a 4s gap per cpu, that might be a tad much.

Yeah I somehow missed the fact we read it every timer tick. I was hoping for an easy fix but I guess we just need to set a reasonable batch size at runtime.

Could you share contex-switch-test program ?
I'd like to play with it to find out what I can do against percpu counter.

Thanks,
-Kame

Quoted 2 lines

Anton

#31 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi,

Quoted 2 lines

Could you share contex-switch-test program ?
I'd like to play with it to find out what I can do against percpu counter.

Sure:

http://ozlabs.org/~anton/junkcode/context_switch.c

Very simple, just run it once per core:

for i in seq 0 31
do
taskset -c $i ./context_switch &
done

Then look at the context switch rates in vmstat.

Anton

#32 lore raw

PATCH 1/1 better align percpu counter (Was Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 10 lines · On Thu, 20 Aug 2009 16:24:51 +1000 Anton Blanchard <[email protected]> wrote:

Hi,

Quoted 2 lines

Could you share contex-switch-test program ?
I'd like to play with it to find out what I can do against percpu counter.

Sure:

http://ozlabs.org/~anton/junkcode/context_switch.c

Quoted 9 lines

Very simple, just run it once per core:

for i in seq 0 31
do
taskset -c $i ./context_switch &
done

Then look at the context switch rates in vmstat.

Thank you for test program.

Before adjusting batch counter (I think you should modify it), Could you try this ?

I only have 8cpu(2socket) host but works well. (But...my host is x86-64 and has not virt-cpu-accouting.)

with your program
before patch.
cpuacct off : 414000-416000 ctsw per sec.
cpuacct on : 401000-404000 ctsw per sec.

after patch
cpuacct on : 412000-413000 ctsw per sec.

Maybe I should check cache-miss late ;)
==
It's bad to place pointer for array of per-cpu-data on the same cache line of spinlock. This patch moves percpu_counter's cacheline to reduce false sharing.

---
 include/linux/percpu_counter.h |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
include/linux/percpu_counter.h +11 -1
Index: linux-2.6.31-rc6/include/linux/percpu_counter.h
===================================================================
@@ -14,14 +14,24 @@
 #include <linux/types.h>
 
 #ifdef CONFIG_SMP
+struct __percpu_counter_padding {
+	char x[0];
+} ____cacheline_internodealigned_in_smp;
+#define CACHELINE_PADDING(name)  struct __percpu_counter_padding name
 
 struct percpu_counter {
+	/*
+	 * This pointer is persistent and accessed firstly.
+	 * Then, should not be purged by locking in other cpus.
+	 */
+	s32 *counters;
+	CACHELINE_PADDING(pad);
 	spinlock_t lock;
 	s64 count;
 #ifdef CONFIG_HOTPLUG_CPU
+	/* rarely accessed field */
 	struct list_head list;	/* All percpu_counters are on a list */
 #endif
-	s32 *counters;
 };
 
 extern int percpu_counter_batch;
#33 lore raw

Re: [PATCH] better align percpu counter (Was Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 35 lines · KAMEZAWA Hiroyuki
Quoted 10 lines · On Thu, 20 Aug 2009 16:24:51 +1000 Anton Blanchard <[email protected]> wrote:

Hi,

Quoted 2 lines

Could you share contex-switch-test program ?
I'd like to play with it to find out what I can do against percpu counter.

Sure:

http://ozlabs.org/~anton/junkcode/context_switch.c

Quoted 9 lines

Very simple, just run it once per core:

for i in seq 0 31
do
taskset -c $i ./context_switch &
done

Then look at the context switch rates in vmstat.

Thank you for test program.

Before adjusting batch counter (I think you should modify it), Could you try this ?

I only have 8cpu(2socket) host but works well. (But...my host is x86-64 and has not virt-cpu-accouting.)

with your program
before patch.
cpuacct off : 414000-416000 ctsw per sec.
cpuacct on : 401000-404000 ctsw per sec.

Quoted 4 lines

after patch
cpuacct on : 412000-413000 ctsw per sec.

Maybe I should check cache-miss late ;)

Btw., in latest upstream you can do that via:

cd tools/perf/
make -j install

  perf stat --repeat 5 -- taskset -c 1 ./context_switch

there will be cache-miss and other stats, error bars so you can compare the before/after better, etc.

Ingo

#34 lore raw

Re: [PATCH] better align percpu counter (Was Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 9 lines · On Thu, 20 Aug 2009 12:04:03 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 8 lines · KAMEZAWA Hiroyuki

with your program
before patch.
cpuacct off : 414000-416000 ctsw per sec.
cpuacct on : 401000-404000 ctsw per sec.

after patch
cpuacct on : 412000-413000 ctsw per sec.

Quoted 9 lines
Quoted 1 line

Maybe I should check cache-miss late ;)

Btw., in latest upstream you can do that via:

cd tools/perf/
make -j install

  perf stat --repeat 5 -- taskset -c 1 ./context_switch

tried. (on 8cpu/2socket host). It seems cache-miss decreases.
But IPC ..?
==
/root/bin/perf stat --repeat 5 -a -e cycles,instructions,cache-misses,L1-dcache-load-misses,L1-dcache-store-misses -- ./ctxt_sw.sh [Before] patch
Performance counter stats for './ctxt_sw.sh' (5 runs):

  1511260148530  cycles                     ( +-   0.025% )  (scaled from 63.49%             )
   470690642181  instructions             #      0.311 IPC     ( +-   0.098% )(scaled from 79.49%)
     1210051728  cache-misses               ( +-   0.629% )  (scaled from 79.00%             )
     3202978828  L1-dcache-load-misses      ( +-   1.118% )  (scaled from 78.00%             )
     1803963907  L1-dcache-store-misses     ( +-   0.728% )  (scaled from 42.99%             )

60.161941918 seconds time elapsed ( +- 0.029% )

[After] patch
Performance counter stats for './ctxt_sw.sh' (5 runs):

  1511961867506  cycles                     ( +-   0.018% )  (scaled from 71.50%)
   448724406149  instructions             #      0.297 IPC     ( +-   0.133% )  (scaled from 75.49%)
     1184548041  cache-misses               ( +-   0.136% )  (scaled from 75.50%)
     3086357048  L1-dcache-load-misses      ( +-   0.822% )  (scaled from 77.50%)
     1708375493  L1-dcache-store-misses     ( +-   0.328% )  (scaled from 47.00%)

60.179814774 seconds time elapsed ( +- 0.052% )

Thanks,
-Kame

#35 lore raw

Re: [PATCH] better align percpu counter (Was Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 15 lines · KAMEZAWA Hiroyuki
Quoted 13 lines · On Thu, 20 Aug 2009 12:04:03 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 9 lines · KAMEZAWA Hiroyuki

with your program
before patch.
cpuacct off : 414000-416000 ctsw per sec.
cpuacct on : 401000-404000 ctsw per sec.

after patch
cpuacct on : 412000-413000 ctsw per sec.

Maybe I should check cache-miss late ;)

Btw., in latest upstream you can do that via:

Quoted 8 lines
Quoted 5 lines

cd tools/perf/
make -j install

  perf stat --repeat 5 -- taskset -c 1 ./context_switch

tried. (on 8cpu/2socket host). It seems cache-miss decreases. But IPC ..?

All the numbers have gone down - about the same amount of cycles but fewer instructions executed, and fewer cache-misses. That's good.

The Instructions Per Cycle metric got worse because cycles stayed constant. One thing is that you have triggered counter-over-commit (the 'scaled from' messages) - this means that more counters are used than the hardware has space for - so we round-robin schedule them.

If you want to get to the bottom of that, to get the most precise result try something like:

    perf stat --repeat 5 -a -e \
        cycles,instructions,L1-dcache-load-misses,L1-dcache-store-misses \
        -- ./ctxt_sw.sh

( this is almost the same as the command line you used, but without
the 'cache-misses' counter. Your CPU should be able to simultaneously activate all these counters and they should count 100% of the events. )

Ingo

#36 lore raw

Re: [PATCH] better align percpu counter (Was Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to KAMEZAWA Hiroyuki
Quoted 11 lines · On Thu, 20 Aug 2009 17:41:23 +0900 KAMEZAWA Hiroyuki…
---
 include/linux/percpu_counter.h |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Index: linux-2.6.31-rc6/include/linux/percpu_counter.h
===================================================================

include/linux/percpu_counter.h line 19

Quoted 6 lines
include/linux/percpu_counter.h +3 -0
@@ -14,14 +14,24 @@
 #include <linux/types.h>
 
 #ifdef CONFIG_SMP
+struct __percpu_counter_padding {
+	char x[0];
+} ____cacheline_internodealigned_in_smp;

above alignement is too big...plz ignore this patch :(

-Kame

Quoted 27 lines
include/linux/percpu_counter.h +8 -2
+#define CACHELINE_PADDING(name)  struct __percpu_counter_padding name
 
 struct percpu_counter {
+	/*
+	 * This pointer is persistent and accessed firstly.
+	 * Then, should not be purged by locking in other cpus.
+	 */
+	s32 *counters;
+	CACHELINE_PADDING(pad);
 	spinlock_t lock;
 	s64 count;
 #ifdef CONFIG_HOTPLUG_CPU
+	/* rarely accessed field */
 	struct list_head list;	/* All percpu_counters are on a list */
 #endif
-	s32 *counters;
 };
 
 extern int percpu_counter_batch;
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#37 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard

Hi, Anton,

Do you have any data on what level of batching is good for VIRT_CPU_ACCOUNTING? If it is going to be as high as INT_MAX, then your patch seems to be the best way to go forward. We'll need to herd away bad users who read cpuacct.stat frequently enough to create a problem.

Balbir Singh.

#38 lore raw

Re: [tip:sched/core] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 10 lines · On Thu, 20 Aug 2009 16:24:51 +1000 Anton Blanchard <[email protected]> wrote:

Hi,

Quoted 2 lines

Could you share contex-switch-test program ?
I'd like to play with it to find out what I can do against percpu counter.

Sure:

http://ozlabs.org/~anton/junkcode/context_switch.c

Quoted 9 lines

Very simple, just run it once per core:

for i in seq 0 31
do
taskset -c $i ./context_switch &
done

Then look at the context switch rates in vmstat.

Ok, I reproduced it on ia64 box (ia64 supports VIRT_CPU_ACCOUNTING)

On 8cpu
-- config=on--
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
11  0      0 7185152  66048 284416    0    0     0     0 5918 12354  0 100  0  0  0

--config=off--
11 0 0 7194496 66304 283392 0 0 0 20 8023 1424022 32 68 0 0 0

Wow, yes. 100x regression.

I'll dig this more.

IIUC, If CONFIG_VIRT_CPU_ACCOUNTING=on, process's stime/utime records "nanosecond". Then, batch=32 is too small. How about once per msec ?

Thanks,
-Kame

#39 lore raw

PATCH 1/1 sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard

Hi,

Another try at this percpu_counter batch issue with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled. Thoughts?

--

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled: 16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled: 61720 ctx switches/sec
CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec

Tested with:

wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

---

Note: ccing ia64 and s390 who have not yet added code to statically initialise cputime_one_jiffy at boot.
See a42548a18866e87092db93b771e6c5b060d78401 (cputime: Optimize jiffies_to_cputime(1) for details). Adding this would help optimise not only this patch but many other areas of the scheduler when CONFIG_VIRT_CPU_ACCOUNTING is enabled.

kernel/sched.c +3 -1
Index: linux.trees.git/kernel/sched.c
===================================================================
@@ -10894,6 +10894,7 @@ static void cpuacct_update_stats(struct 
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;
@@ -10901,8 +10902,9 @@ static void cpuacct_update_stats(struct 
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
author Reviewed-by on v1 1/1
#40 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 37 lines

Hi,

Another try at this percpu_counter batch issue with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled. Thoughts?

--

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled: 16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled: 61720 ctx switches/sec
CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec

Quoted 8 lines

Tested with:

wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

Looks fine to me. Thanks Anton!

Quoted 32 lines

---

Note: ccing ia64 and s390 who have not yet added code to statically initialise cputime_one_jiffy at boot.
See a42548a18866e87092db93b771e6c5b060d78401 (cputime: Optimize jiffies_to_cputime(1) for details). Adding this would help optimise not only this patch but many other areas of the scheduler when CONFIG_VIRT_CPU_ACCOUNTING is enabled.

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +3 -1
@@ -10894,6 +10894,7 @@ static void cpuacct_update_stats(struct 
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;
@@ -10901,8 +10902,9 @@ static void cpuacct_update_stats(struct 
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#41 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 4 lines · Anton Blanchard

Hi,

Another try at this percpu_counter batch issue with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled. Thoughts?

Seems like a good idea, but isn't that batch number rather static? If so, computing it in some init path would save that multiply on the actual accounting path.

Quoted 24 lines

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +3 -1
@@ -10894,6 +10894,7 @@ static void cpuacct_update_stats(struct 
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;
@@ -10901,8 +10902,9 @@ static void cpuacct_update_stats(struct 
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#42 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi Peter,

Quoted 3 lines

Seems like a good idea, but isn't that batch number rather static? If so, computing it in some init path would save that multiply on the actual accounting path.

It is mostly static, but percpu_counter_batch does change with hotplug operations. Adding a hotplug notifier felt like a lot of work but I was worried we have issues if we didn't scale with hotplug add operations.

Anton

#43 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 9 lines · Anton Blanchard

Hi Peter,

Quoted 3 lines

Seems like a good idea, but isn't that batch number rather static? If so, computing it in some init path would save that multiply on the actual accounting path.

It is mostly static, but percpu_counter_batch does change with hotplug operations. Adding a hotplug notifier felt like a lot of work but I was worried we have issues if we didn't scale with hotplug add operations.

OK, trading a notifier for a mult might be worth it, we'll see if someone complains ;-)

Lets got with this for now.

Acked-by on v1 1/1
#44 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 67 lines · Anton Blanchard

Hi,

Another try at this percpu_counter batch issue with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled. Thoughts?

--

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled: 16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled: 61720 ctx switches/sec
CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec

Tested with:

wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

---

Note: ccing ia64 and s390 who have not yet added code to statically initialise cputime_one_jiffy at boot.
See a42548a18866e87092db93b771e6c5b060d78401 (cputime: Optimize jiffies_to_cputime(1) for details). Adding this would help optimise not only this patch but many other areas of the scheduler when CONFIG_VIRT_CPU_ACCOUNTING is enabled.

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +1 -0
@@ -10894,6 +10894,7 @@ static void cpuacct_update_stats(struct 
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;

kernel/sched.c static void cpuacct_update_stats(struct · line 10910

Quoted 10 lines
kernel/sched.c +2 -1
@@ -10901,8 +10902,9 @@ static void cpuacct_update_stats(struct 
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();

Looks good to me, but I'll test it as well and revert back. I think we might need to look at the call side where we do the percpu_counter_read().

Balbir

#45 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard

Hi Anton,

Quoted 6 lines · On Mon, 18 Jan 2010 15:41:42 +1100 Anton Blanchard <[email protected]> wrote:

Note: ccing ia64 and s390 who have not yet added code to statically initialise cputime_one_jiffy at boot.
See a42548a18866e87092db93b771e6c5b060d78401 (cputime: Optimize jiffies_to_cputime(1) for details). Adding this would help optimise not only this patch but many other areas of the scheduler when CONFIG_VIRT_CPU_ACCOUNTING is enabled.

For s390 the jiffies_to_cputime is a compile time constant. No need to initialize it at runtime, no?

Quoted 13 lines

Index: linux.trees.git/kernel/sched.c
===================================================================

kernel/sched.c +1 -0
@@ -10894,6 +10894,7 @@ static void cpuacct_update_stats(struct 
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;

kernel/sched.c static void cpuacct_update_stats(struct · line 10910

Quoted 10 lines
kernel/sched.c +2 -1
@@ -10901,8 +10902,9 @@ static void cpuacct_update_stats(struct 
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();

The patch itself trades some accuracy (larger cpu accounting value that are stored per-cpu) against runtime overhead (spinlock to transfer the value to the global variable in __percpu_counter_add). Did you calculate how big the loss in accuracy is?

Signature · 4 lines
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.
#46 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi Martin,

Quoted 2 lines

For s390 the jiffies_to_cputime is a compile time constant. No need to initialize it at runtime, no?

Indeed it is, I didn't look closely enough. Same with ia64 so no work to do on either arch :)

Quoted 4 lines

The patch itself trades some accuracy (larger cpu accounting value that are stored per-cpu) against runtime overhead (spinlock to transfer the value to the global variable in __percpu_counter_add). Did you calculate how big the loss in accuracy is?

The idea is we are already batching percpu_counter_batch jiffies, so with CONFIG_VIRT_CPU_ACCOUNTING we batch the equivalent amount in cputime.

Anton

Acked-by Tested-by
#47 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 9 lines · Anton Blanchard

Hi Martin,

Quoted 2 lines

For s390 the jiffies_to_cputime is a compile time constant. No need to initialize it at runtime, no?

Indeed it is, I didn't look closely enough. Same with ia64 so no work to do on either arch :)

Quoted 9 lines
Quoted 4 lines

The patch itself trades some accuracy (larger cpu accounting value that are stored per-cpu) against runtime overhead (spinlock to transfer the value to the global variable in __percpu_counter_add). Did you calculate how big the loss in accuracy is?

The idea is we are already batching percpu_counter_batch jiffies, so with CONFIG_VIRT_CPU_ACCOUNTING we batch the equivalent amount in cputime.

This patch worked well for me.

Balbir Singh.

#48 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 9 lines · Anton Blanchard

Hi Martin,

Quoted 2 lines

For s390 the jiffies_to_cputime is a compile time constant. No need to initialize it at runtime, no?

Indeed it is, I didn't look closely enough. Same with ia64 so no work to do on either arch :)

Quoted 9 lines
Quoted 4 lines

The patch itself trades some accuracy (larger cpu accounting value that are stored per-cpu) against runtime overhead (spinlock to transfer the value to the global variable in __percpu_counter_add). Did you calculate how big the loss in accuracy is?

The idea is we are already batching percpu_counter_batch jiffies, so with CONFIG_VIRT_CPU_ACCOUNTING we batch the equivalent amount in cputime.

Hi, Peter, Ingo

Could we please pick up the patch for -tip?

Signature · 2 lines
Three Cheers,
Balbir Singh
#49 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 1 line · Balbir Singh

Could we please pick up the patch for -tip?

OK, will queue it up if Ingo doesn't beat me to it.

#50 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Quoted 5 lines · On Mon, 18 Jan 2010 15:41:42 +1100 Anton Blanchard <[email protected]> wrote:

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

When one looks at the end result:

: static void cpuacct_update_stats(struct task_struct *tsk,
: enum cpuacct_stat_index idx, cputime_t val)
: {
: struct cpuacct *ca;
: int batch;
:
: if (unlikely(!cpuacct_subsys.active))
: return;
:
: rcu_read_lock();
: ca = task_ca(tsk);
:
: batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
: do {
: __percpu_counter_add(&ca->cpustat[idx], val, batch);
: ca = ca->parent;
: } while (ca);
: rcu_read_unlock();
: }

the code (which used to be quite obvious) becomes pretty unobvious. In fact it looks quite wrong.

Shouldn't there be a comment there explaining wtf is going on?

#51 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 10 lines
Quoted 5 lines · On Mon, 18 Jan 2010 15:41:42 +1100 Anton Blanchard <[email protected]> wrote:

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

When one looks at the end result:

We have about 32 jiffies batch both with or without CONFIG_VIRT_CPU_ACCOUNTING. Then, The enduser can looks some jiffies after.

#52 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Andrew Morton
Quoted 31 lines · Andrew Morton
Quoted 5 lines · On Mon, 18 Jan 2010 15:41:42 +1100 Anton Blanchard <[email protected]> wrote:

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

When one looks at the end result:

: static void cpuacct_update_stats(struct task_struct *tsk,
: enum cpuacct_stat_index idx, cputime_t val)
: {
: struct cpuacct *ca;
: int batch;
:
: if (unlikely(!cpuacct_subsys.active))
: return;
:
: rcu_read_lock();
: ca = task_ca(tsk);
:
: batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
: do {
: __percpu_counter_add(&ca->cpustat[idx], val, batch);
: ca = ca->parent;
: } while (ca);
: rcu_read_unlock();
: }

Quoted 4 lines

the code (which used to be quite obvious) becomes pretty unobvious. In fact it looks quite wrong.

Shouldn't there be a comment there explaining wtf is going on?

Andrew,

I guess a lot of the changelog and comments are in the email history, but your point on the comment is valid. Why does it look quite wrong to you?

cputime_one_jiffy tells us how many cputime_t's we've gotten in one jiffy. If virtual accounting is enabled, this number is quite large, and 1 if virtual accounting is not enabled. Overall the value is set to 32 for non-virtual accounting enabled systems. On systems that support virtual accounting, the value is set to 32*cputime_per_jifffy, so the per cpu counter syncs up roughly once in 32 jiffies assuming cpuacct_update_stats is called once per jiffy for non-virtual machines.

If the above comment, pleases you I'll polish it and send it across. Anton, could you please confirm what I've said above is indeed correct.

Signature · 2 lines
Three Cheers,
Balbir Singh
#53 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 32 lines · On Tue, 26 Jan 2010 11:47:15 +0530 Balbir Singh <[email protected]>…
Quoted 31 lines · Andrew Morton
Quoted 5 lines · On Mon, 18 Jan 2010 15:41:42 +1100 Anton Blanchard <[email protected]> wrote:

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

When one looks at the end result:

: static void cpuacct_update_stats(struct task_struct *tsk,
: enum cpuacct_stat_index idx, cputime_t val)
: {
: struct cpuacct *ca;
: int batch;
:
: if (unlikely(!cpuacct_subsys.active))
: return;
:
: rcu_read_lock();
: ca = task_ca(tsk);
:
: batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
: do {
: __percpu_counter_add(&ca->cpustat[idx], val, batch);
: ca = ca->parent;
: } while (ca);
: rcu_read_unlock();
: }

Quoted 8 lines
Quoted 4 lines

the code (which used to be quite obvious) becomes pretty unobvious. In fact it looks quite wrong.

Shouldn't there be a comment there explaining wtf is going on?

Andrew,

I guess a lot of the changelog and comments are in the email history,

Not a very useful location for it!

Quoted 1 line

Why does it look quite wrong to you?

Because it computes the correct value and then if it's larger than INT_MAX, it inexplicably assigns INT_MAX to it, giving a wrong result!

Does that code actually work, btw? percpu_counter_batch has type int' and cputime_one_jiffy has type int' so their product has type `int'. So by the time min_t performs its comparison, the upper 32 bits of the product are already lost.

#54 lore raw

Re: [PATCH] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Hi Andrew,

Quoted 3 lines
Quoted 1 line

I guess a lot of the changelog and comments are in the email history,

Not a very useful location for it!

Good point, I'll work on a useful comment.

Quoted 9 lines
Quoted 1 line

Why does it look quite wrong to you?

Because it computes the correct value and then if it's larger than INT_MAX, it inexplicably assigns INT_MAX to it, giving a wrong result!

Does that code actually work, btw? percpu_counter_batch has type int' and cputime_one_jiffy has type int' so their product has type `int'. So by the time min_t performs its comparison, the upper 32 bits of the product are already lost.

On ppc64, s390 and ia64 cputime_one_jiffy is 64bit and I want to prevent us creating too large a batch value:

void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)

If we pass in something bigger than INT_MAX we could end up with 0 after truncation which will turn the percpu counter into a single spinlock global counter.

Anton

#55 lore raw

[tip:sched/urgent] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Anton Blanchard
Commit-ID:  43f85eab1411905afe5db510fbf9841b516e7e6a
Gitweb:     http://git.kernel.org/tip/43f85eab1411905afe5db510fbf9841b516e7e6a
Author:     Anton Blanchard <[email protected]>
AuthorDate: Mon, 18 Jan 2010 15:41:42 +1100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 Jan 2010 08:34:38 +0100

sched: cpuacct: Use bigger percpu counter batch values for stats counters

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled: 16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled: 61720 ctx switches/sec
CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec

Tested with:

wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

LKML-Reference: <20100118044142.GS12666@kryten>

---
 kernel/sched.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
kernel/sched.c +3 -1
index 3a8fb30..8f94138 100644
@@ -10906,6 +10906,7 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;
@@ -10913,8 +10914,9 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 	rcu_read_lock();
 	ca = task_ca(tsk);
 
+	batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#56 lore raw

Re: [tip:sched/urgent] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 67 lines · tip-bot for Anton Blanchard

Commit-ID:  43f85eb1411905afe5db510fbf9841b516e7e6a
Gitweb:     http://git.kernel.org/tip/43f85eab1411905afe5db510fbf9841b516e7e6a
Author:     Anton Blanchard <[email protected]>
AuthorDate: Mon, 18 Jan 2010 15:41:42 +1100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 27 Jan 2010 08:34:38 +0100

sched: cpuacct: Use bigger percpu counter batch values for stats counters

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled:         16906698 ctx switches/sec CONFIG_CGROUP_CPUACCT enabled:             61720 ctx switches/sec CONFIG_CGROUP_CPUACCT + patch:          16663217 ctx switches/sec

Tested with:

 wget http://ozlabs.org/~anton/junkcode/context_switch.c
 make context_switch
 for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

LKML-Reference: <20100118044142.GS12666@kryten>

---
 kernel/sched.c |    4 +++-

 1 files changed, 3 insertions(+), 1 deletions(-)
kernel/sched.c +1 -0
index 3a8fb30..8f94138 100644
@@ -10906,6 +10906,7 @@ static void cpuacct_update_stats(struct task_struct *tsk,
                enum cpuacct_stat_index idx, cputime_t val)
  {
        struct cpuacct *ca;
+       int batch;
 
        if (unlikely(!cpuacct_subsys.active))
                return;

kernel/sched.c static void cpuacct_update_stats(struct task_struct *tsk, · line 10922

Quoted 10 lines
kernel/sched.c +2 -1
@@ -10913,8 +10914,9 @@ static void cpuacct_update_stats(struct task_struct *tsk,
        rcu_read_lock();
        ca = task_ca(tsk);
 
+       batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
        do {
-               percpu_counter_add(&ca->cpustat[idx], val);
+               __percpu_counter_add(&ca->cpustat[idx], val, batch);
                ca = ca->parent;
        } while (ca);
        rcu_read_unlock();

IIRC, Andrew picked up this patch as well and applied some checkpatch fixes too..

Balbir

#57 lore raw

Re: [tip:sched/urgent] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 72 lines · On Wed, 27 Jan 2010 19:04:55 +0530 Balbir Singh <[email protected]>…
Quoted 70 lines · tip-bot for Anton Blanchard

Commit-ID: __43f85eb1411905afe5db510fbf9841b516e7e6a
Gitweb: __ __ http://git.kernel.org/tip/43f85eab1411905afe5db510fbf9841b516e7e6a
Author: __ __ Anton Blanchard <[email protected]>
AuthorDate: Mon, 18 Jan 2010 15:41:42 +1100
Committer: __Ingo Molnar <[email protected]>
CommitDate: Wed, 27 Jan 2010 08:34:38 +0100

sched: cpuacct: Use bigger percpu counter batch values for stats counters

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled: __ __ __ __ 16906698 ctx switches/sec CONFIG_CGROUP_CPUACCT enabled: __ __ __ __ __ __ 61720 ctx switches/sec CONFIG_CGROUP_CPUACCT + patch: __ __ __ __ __16663217 ctx switches/sec

Tested with:

__wget http://ozlabs.org/~anton/junkcode/context_switch.c
__make context_switch
__for i in seq 0 63; do taskset -c $i ./context_switch & done __vmstat 1

LKML-Reference: <20100118044142.GS12666@kryten>

---
__kernel/sched.c | __ __4 +++-
__1 files changed, 3 insertions(+), 1 deletions(-)

kernel/sched.c +1 -0
index 3a8fb30..8f94138 100644
@@ -10906,6 +10906,7 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 __ __ __ __ __ __ __ __enum cpuacct_stat_index idx, cputime_t val)
 __{
 __ __ __ __struct cpuacct *ca;
+ __ __ __ int batch;
 
 __ __ __ __if (unlikely(!cpuacct_subsys.active))
 __ __ __ __ __ __ __ __return;
@@ -10913,8 +10914,9 @@ static void cpuacct_update_stats(struct task_struct *tsk,
 __ __ __ __rcu_read_lock();
 __ __ __ __ca = task_ca(tsk);
 
Quoted 7 lines

kernel/sched.c static void cpuacct_update_stats(struct task_struct *tsk, · line 10922

Quoted 7 lines
kernel/sched.c +2 -1
+ __ __ __ batch = min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX);
 __ __ __ __do {
- __ __ __ __ __ __ __ percpu_counter_add(&ca->cpustat[idx], val);
+ __ __ __ __ __ __ __ __percpu_counter_add(&ca->cpustat[idx], val, batch);
 __ __ __ __ __ __ __ __ca = ca->parent;
 __ __ __ __} while (ca);
 __ __ __ __rcu_read_unlock();

^^ your email client inexplicably fills emails with 0xa0

Quoted 2 lines

IIRC, Andrew picked up this patch as well and applied some checkpatch fixes too..

No, I have no changes.

Last I heard, Anton was "working on a useful comment" and will be redoing the patch.

#58 lore raw

Re: [tip:sched/urgent] sched: cpuacct: Use bigger percpu counter batch values for stats counters

Quoted 2 lines · Andrew Morton

Last I heard, Anton was "working on a useful comment" and will be redoing the patch.

If Anton is working on a new version, would Anton then also care to post one that compiles on UP? :-)

#59 lore raw

PATCH 1/2 percpu_counter: Make __percpu_counter_add an inline function on UP

Even though batch isn't used on UP, we may want to pass one in to keep the SMP and UP code paths similar. Convert __percpu_counter_add to an inline function so we wont get variable unused warnings if we do.

---

include/linux/percpu_counter.h +6 -3
index a7684a5..794662b 100644
@@ -98,9 +98,6 @@ static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
 	fbc->count = amount;
 }
 
-#define __percpu_counter_add(fbc, amount, batch) \
-	percpu_counter_add(fbc, amount)
-
 static inline void
 percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 {
@@ -109,6 +106,12 @@ percpu_counter_add(struct percpu_counter *fbc, s64 amount)
 	preempt_enable();
 }
 
+static inline void
+__percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
+{
+	percpu_counter_add(fbc, amount);
+}
+
 static inline s64 percpu_counter_read(struct percpu_counter *fbc)
 {
 	return fbc->count;
#60 lore raw

PATCH 2/2 sched: cpuacct: Use bigger percpu counter batch values for stats counters

When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.

Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.

This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.

For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.

On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:

CONFIG_CGROUP_CPUACCT disabled:         16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled:             61720 ctx switches/sec

CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec

Tested with:

wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1

---

v2: Added a comment and fixed the UP build.

kernel/sched.c +19 -1
Index: linux-cpumask/kernel/sched.c
===================================================================
@@ -10885,12 +10885,30 @@ static void cpuacct_charge(struct task_s
 }
 
 /*
+ * When CONFIG_VIRT_CPU_ACCOUNTING is enabled one jiffy can be very large
+ * in cputime_t units. As a result, cpuacct_update_stats calls
+ * percpu_counter_add with values large enough to always overflow the
+ * per cpu batch limit causing bad SMP scalability.
+ *
+ * To fix this we scale percpu_counter_batch by cputime_one_jiffy so we
+ * batch the same amount of time with CONFIG_VIRT_CPU_ACCOUNTING disabled
+ * and enabled. We cap it at INT_MAX which is the largest allowed batch value.
+ */
+#ifdef CONFIG_SMP
+#define CPUACCT_BATCH	\
+	min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX)
+#else
+#define CPUACCT_BATCH	0
+#endif
+
+/*
  * Charge the system/user time to the task's accounting group.
  */
 static void cpuacct_update_stats(struct task_struct *tsk,
 		enum cpuacct_stat_index idx, cputime_t val)
 {
 	struct cpuacct *ca;
+	int batch = CPUACCT_BATCH;
 
 	if (unlikely(!cpuacct_subsys.active))
 		return;
@@ -10899,7 +10917,7 @@ static void cpuacct_update_stats(struct 
 	ca = task_ca(tsk);
 
 	do {
-		percpu_counter_add(&ca->cpustat[idx], val);
+		__percpu_counter_add(&ca->cpustat[idx], val, batch);
 		ca = ca->parent;
 	} while (ca);
 	rcu_read_unlock();
#61 lore raw

Re: [tip:sched/urgent] sched: cpuacct: Use bigger percpu counter batch values for stats counters

In reply to Andrew Morton
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

__ __ __ __ __ __ __ __ca = ca->parent;
__ __ __ __} while (ca);
__ __ __ __rcu_read_unlock();

^^ your email client inexplicably fills emails with 0xa0

I am going to be changing my email client soon, back to the good old text client.

Quoted 5 lines
Quoted 2 lines

IIRC, Andrew picked up this patch as well and applied some checkpatch fixes too..

No, I have no changes.

Sorry, I was confused, the changes you had were for getdelays.c

Quoted 2 lines

Last I heard, Anton was "working on a useful comment" and will be redoing the patch.

Yep, lets wait on him.

Three Cheers,
Balbir