aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2008-04-29 04:00:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:09 -0400
commit472b1053f3c319cc60bfb2a0bb062fed77a93eb6 (patch)
tree2ef88bfdb7e397d3718a1bed38f13194f894097e /kernel/cgroup.c
parent08ce5f16ee466ffc5bf243800deeecd77d9eaf50 (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.c59
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;
193static DEFINE_RWLOCK(css_set_lock); 194static DEFINE_RWLOCK(css_set_lock);
194static int css_set_count; 195static 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)
201static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE];
202
203static 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;
219static void unlink_css_set(struct css_set *cg) 241static 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;