diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2008-04-29 04:00:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:09 -0400 |
commit | 472b1053f3c319cc60bfb2a0bb062fed77a93eb6 (patch) | |
tree | 2ef88bfdb7e397d3718a1bed38f13194f894097e /kernel/cgroup.c | |
parent | 08ce5f16ee466ffc5bf243800deeecd77d9eaf50 (diff) |
cgroups: use a hash table for css_set finding
When we attach a process to a different cgroup, the css_set linked-list will
be run through to find a suitable existing css_set to use. This patch
implements a hash table for better performance.
The following benchmarks have been tested:
For N in 1, 5, 10, 50, 100, 500, 1000, create N cgroups with one sleeping
task in each, and then move an additional task through each cgroup in
turn.
Here is a test result:
N Loop orig - Time(s) hash - Time(s)
----------------------------------------------
1 10000 1.201231728 1.196311177
5 2000 1.065743872 1.040566424
10 1000 0.991054735 0.986876440
50 200 0.976554203 0.969608733
100 100 0.998504680 0.969218270
500 20 1.157347764 0.962602963
1000 10 1.619521852 1.085140172
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Reviewed-by: Paul Menage <menage@google.com>
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7c8cc5141877..c447c29f8749 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/kmod.h> | 44 | #include <linux/kmod.h> |
45 | #include <linux/delayacct.h> | 45 | #include <linux/delayacct.h> |
46 | #include <linux/cgroupstats.h> | 46 | #include <linux/cgroupstats.h> |
47 | #include <linux/hash.h> | ||
47 | 48 | ||
48 | #include <asm/atomic.h> | 49 | #include <asm/atomic.h> |
49 | 50 | ||
@@ -193,6 +194,27 @@ static struct cg_cgroup_link init_css_set_link; | |||
193 | static DEFINE_RWLOCK(css_set_lock); | 194 | static DEFINE_RWLOCK(css_set_lock); |
194 | static int css_set_count; | 195 | static int css_set_count; |
195 | 196 | ||
197 | /* hash table for cgroup groups. This improves the performance to | ||
198 | * find an existing css_set */ | ||
199 | #define CSS_SET_HASH_BITS 7 | ||
200 | #define CSS_SET_TABLE_SIZE (1 << CSS_SET_HASH_BITS) | ||
201 | static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE]; | ||
202 | |||
203 | static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[]) | ||
204 | { | ||
205 | int i; | ||
206 | int index; | ||
207 | unsigned long tmp = 0UL; | ||
208 | |||
209 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) | ||
210 | tmp += (unsigned long)css[i]; | ||
211 | tmp = (tmp >> 16) ^ tmp; | ||
212 | |||
213 | index = hash_long(tmp, CSS_SET_HASH_BITS); | ||
214 | |||
215 | return &css_set_table[index]; | ||
216 | } | ||
217 | |||
196 | /* We don't maintain the lists running through each css_set to its | 218 | /* We don't maintain the lists running through each css_set to its |
197 | * task until after the first call to cgroup_iter_start(). This | 219 | * task until after the first call to cgroup_iter_start(). This |
198 | * reduces the fork()/exit() overhead for people who have cgroups | 220 | * reduces the fork()/exit() overhead for people who have cgroups |
@@ -219,6 +241,7 @@ static int use_task_css_set_links; | |||
219 | static void unlink_css_set(struct css_set *cg) | 241 | static void unlink_css_set(struct css_set *cg) |
220 | { | 242 | { |
221 | write_lock(&css_set_lock); | 243 | write_lock(&css_set_lock); |
244 | hlist_del(&cg->hlist); | ||
222 | list_del(&cg->list); | 245 | list_del(&cg->list); |
223 | css_set_count--; | 246 | css_set_count--; |
224 | while (!list_empty(&cg->cg_links)) { | 247 | while (!list_empty(&cg->cg_links)) { |
@@ -284,9 +307,7 @@ static inline void put_css_set_taskexit(struct css_set *cg) | |||
284 | /* | 307 | /* |
285 | * find_existing_css_set() is a helper for | 308 | * find_existing_css_set() is a helper for |
286 | * find_css_set(), and checks to see whether an existing | 309 | * find_css_set(), and checks to see whether an existing |
287 | * css_set is suitable. This currently walks a linked-list for | 310 | * css_set is suitable. |
288 | * simplicity; a later patch will use a hash table for better | ||
289 | * performance | ||
290 | * | 311 | * |
291 | * oldcg: the cgroup group that we're using before the cgroup | 312 | * oldcg: the cgroup group that we're using before the cgroup |
292 | * transition | 313 | * transition |
@@ -303,7 +324,9 @@ static struct css_set *find_existing_css_set( | |||
303 | { | 324 | { |
304 | int i; | 325 | int i; |
305 | struct cgroupfs_root *root = cgrp->root; | 326 | struct cgroupfs_root *root = cgrp->root; |
306 | struct list_head *l = &init_css_set.list; | 327 | struct hlist_head *hhead; |
328 | struct hlist_node *node; | ||
329 | struct css_set *cg; | ||
307 | 330 | ||
308 | /* Built the set of subsystem state objects that we want to | 331 | /* Built the set of subsystem state objects that we want to |
309 | * see in the new css_set */ | 332 | * see in the new css_set */ |
@@ -320,18 +343,13 @@ static struct css_set *find_existing_css_set( | |||
320 | } | 343 | } |
321 | } | 344 | } |
322 | 345 | ||
323 | /* Look through existing cgroup groups to find one to reuse */ | 346 | hhead = css_set_hash(template); |
324 | do { | 347 | hlist_for_each_entry(cg, node, hhead, hlist) { |
325 | struct css_set *cg = | ||
326 | list_entry(l, struct css_set, list); | ||
327 | |||
328 | if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) { | 348 | if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) { |
329 | /* All subsystems matched */ | 349 | /* All subsystems matched */ |
330 | return cg; | 350 | return cg; |
331 | } | 351 | } |
332 | /* Try the next cgroup group */ | 352 | } |
333 | l = l->next; | ||
334 | } while (l != &init_css_set.list); | ||
335 | 353 | ||
336 | /* No existing cgroup group matched */ | 354 | /* No existing cgroup group matched */ |
337 | return NULL; | 355 | return NULL; |
@@ -393,6 +411,8 @@ static struct css_set *find_css_set( | |||
393 | struct list_head tmp_cg_links; | 411 | struct list_head tmp_cg_links; |
394 | struct cg_cgroup_link *link; | 412 | struct cg_cgroup_link *link; |
395 | 413 | ||
414 | struct hlist_head *hhead; | ||
415 | |||
396 | /* First see if we already have a cgroup group that matches | 416 | /* First see if we already have a cgroup group that matches |
397 | * the desired set */ | 417 | * the desired set */ |
398 | write_lock(&css_set_lock); | 418 | write_lock(&css_set_lock); |
@@ -417,6 +437,7 @@ static struct css_set *find_css_set( | |||
417 | kref_init(&res->ref); | 437 | kref_init(&res->ref); |
418 | INIT_LIST_HEAD(&res->cg_links); | 438 | INIT_LIST_HEAD(&res->cg_links); |
419 | INIT_LIST_HEAD(&res->tasks); | 439 | INIT_LIST_HEAD(&res->tasks); |
440 | INIT_HLIST_NODE(&res->hlist); | ||
420 | 441 | ||
421 | /* Copy the set of subsystem state objects generated in | 442 | /* Copy the set of subsystem state objects generated in |
422 | * find_existing_css_set() */ | 443 | * find_existing_css_set() */ |
@@ -459,6 +480,11 @@ static struct css_set *find_css_set( | |||
459 | /* Link this cgroup group into the list */ | 480 | /* Link this cgroup group into the list */ |
460 | list_add(&res->list, &init_css_set.list); | 481 | list_add(&res->list, &init_css_set.list); |
461 | css_set_count++; | 482 | css_set_count++; |
483 | |||
484 | /* Add this cgroup group to the hash table */ | ||
485 | hhead = css_set_hash(res->subsys); | ||
486 | hlist_add_head(&res->hlist, hhead); | ||
487 | |||
462 | write_unlock(&css_set_lock); | 488 | write_unlock(&css_set_lock); |
463 | 489 | ||
464 | return res; | 490 | return res; |
@@ -2508,6 +2534,7 @@ int __init cgroup_init_early(void) | |||
2508 | INIT_LIST_HEAD(&init_css_set.list); | 2534 | INIT_LIST_HEAD(&init_css_set.list); |
2509 | INIT_LIST_HEAD(&init_css_set.cg_links); | 2535 | INIT_LIST_HEAD(&init_css_set.cg_links); |
2510 | INIT_LIST_HEAD(&init_css_set.tasks); | 2536 | INIT_LIST_HEAD(&init_css_set.tasks); |
2537 | INIT_HLIST_NODE(&init_css_set.hlist); | ||
2511 | css_set_count = 1; | 2538 | css_set_count = 1; |
2512 | init_cgroup_root(&rootnode); | 2539 | init_cgroup_root(&rootnode); |
2513 | list_add(&rootnode.root_list, &roots); | 2540 | list_add(&rootnode.root_list, &roots); |
@@ -2520,6 +2547,9 @@ int __init cgroup_init_early(void) | |||
2520 | list_add(&init_css_set_link.cg_link_list, | 2547 | list_add(&init_css_set_link.cg_link_list, |
2521 | &init_css_set.cg_links); | 2548 | &init_css_set.cg_links); |
2522 | 2549 | ||
2550 | for (i = 0; i < CSS_SET_TABLE_SIZE; i++) | ||
2551 | INIT_HLIST_HEAD(&css_set_table[i]); | ||
2552 | |||
2523 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | 2553 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { |
2524 | struct cgroup_subsys *ss = subsys[i]; | 2554 | struct cgroup_subsys *ss = subsys[i]; |
2525 | 2555 | ||
@@ -2549,6 +2579,7 @@ int __init cgroup_init(void) | |||
2549 | { | 2579 | { |
2550 | int err; | 2580 | int err; |
2551 | int i; | 2581 | int i; |
2582 | struct hlist_head *hhead; | ||
2552 | 2583 | ||
2553 | err = bdi_init(&cgroup_backing_dev_info); | 2584 | err = bdi_init(&cgroup_backing_dev_info); |
2554 | if (err) | 2585 | if (err) |
@@ -2560,6 +2591,10 @@ int __init cgroup_init(void) | |||
2560 | cgroup_init_subsys(ss); | 2591 | cgroup_init_subsys(ss); |
2561 | } | 2592 | } |
2562 | 2593 | ||
2594 | /* Add init_css_set to the hash table */ | ||
2595 | hhead = css_set_hash(init_css_set.subsys); | ||
2596 | hlist_add_head(&init_css_set.hlist, hhead); | ||
2597 | |||
2563 | err = register_filesystem(&cgroup_fs_type); | 2598 | err = register_filesystem(&cgroup_fs_type); |
2564 | if (err < 0) | 2599 | if (err < 0) |
2565 | goto out; | 2600 | goto out; |