Commit 472b1053f3c319cc60bfb2a0bb062fed77a93eb6

Authored by Li Zefan
Committed by Linus Torvalds
1 parent 08ce5f16ee

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>

Showing 2 changed files with 53 additions and 13 deletions Side-by-side Diff

include/linux/cgroup.h
... ... @@ -156,6 +156,12 @@
156 156 struct list_head list;
157 157  
158 158 /*
  159 + * List running through all cgroup groups in the same hash
  160 + * slot. Protected by css_set_lock
  161 + */
  162 + struct hlist_node hlist;
  163 +
  164 + /*
159 165 * List running through all tasks using this cgroup
160 166 * group. Protected by css_set_lock
161 167 */
... ... @@ -174,7 +180,6 @@
174 180 * during subsystem registration (at boot time).
175 181 */
176 182 struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
177   -
178 183 };
179 184  
180 185 /*
... ... @@ -44,6 +44,7 @@
44 44 #include <linux/kmod.h>
45 45 #include <linux/delayacct.h>
46 46 #include <linux/cgroupstats.h>
  47 +#include <linux/hash.h>
47 48  
48 49 #include <asm/atomic.h>
49 50  
... ... @@ -193,6 +194,27 @@
193 194 static DEFINE_RWLOCK(css_set_lock);
194 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 218 /* We don't maintain the lists running through each css_set to its
197 219 * task until after the first call to cgroup_iter_start(). This
198 220 * reduces the fork()/exit() overhead for people who have cgroups
... ... @@ -219,6 +241,7 @@
219 241 static void unlink_css_set(struct css_set *cg)
220 242 {
221 243 write_lock(&css_set_lock);
  244 + hlist_del(&cg->hlist);
222 245 list_del(&cg->list);
223 246 css_set_count--;
224 247 while (!list_empty(&cg->cg_links)) {
... ... @@ -284,9 +307,7 @@
284 307 /*
285 308 * find_existing_css_set() is a helper for
286 309 * find_css_set(), and checks to see whether an existing
287   - * css_set is suitable. This currently walks a linked-list for
288   - * simplicity; a later patch will use a hash table for better
289   - * performance
  310 + * css_set is suitable.
290 311 *
291 312 * oldcg: the cgroup group that we're using before the cgroup
292 313 * transition
... ... @@ -303,7 +324,9 @@
303 324 {
304 325 int i;
305 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 331 /* Built the set of subsystem state objects that we want to
309 332 * see in the new css_set */
310 333  
... ... @@ -320,18 +343,13 @@
320 343 }
321 344 }
322 345  
323   - /* Look through existing cgroup groups to find one to reuse */
324   - do {
325   - struct css_set *cg =
326   - list_entry(l, struct css_set, list);
327   -
  346 + hhead = css_set_hash(template);
  347 + hlist_for_each_entry(cg, node, hhead, hlist) {
328 348 if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
329 349 /* All subsystems matched */
330 350 return cg;
331 351 }
332   - /* Try the next cgroup group */
333   - l = l->next;
334   - } while (l != &init_css_set.list);
  352 + }
335 353  
336 354 /* No existing cgroup group matched */
337 355 return NULL;
... ... @@ -393,6 +411,8 @@
393 411 struct list_head tmp_cg_links;
394 412 struct cg_cgroup_link *link;
395 413  
  414 + struct hlist_head *hhead;
  415 +
396 416 /* First see if we already have a cgroup group that matches
397 417 * the desired set */
398 418 write_lock(&css_set_lock);
... ... @@ -417,6 +437,7 @@
417 437 kref_init(&res->ref);
418 438 INIT_LIST_HEAD(&res->cg_links);
419 439 INIT_LIST_HEAD(&res->tasks);
  440 + INIT_HLIST_NODE(&res->hlist);
420 441  
421 442 /* Copy the set of subsystem state objects generated in
422 443 * find_existing_css_set() */
... ... @@ -459,6 +480,11 @@
459 480 /* Link this cgroup group into the list */
460 481 list_add(&res->list, &init_css_set.list);
461 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 488 write_unlock(&css_set_lock);
463 489  
464 490 return res;
... ... @@ -2508,6 +2534,7 @@
2508 2534 INIT_LIST_HEAD(&init_css_set.list);
2509 2535 INIT_LIST_HEAD(&init_css_set.cg_links);
2510 2536 INIT_LIST_HEAD(&init_css_set.tasks);
  2537 + INIT_HLIST_NODE(&init_css_set.hlist);
2511 2538 css_set_count = 1;
2512 2539 init_cgroup_root(&rootnode);
2513 2540 list_add(&rootnode.root_list, &roots);
... ... @@ -2520,6 +2547,9 @@
2520 2547 list_add(&init_css_set_link.cg_link_list,
2521 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 2553 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
2524 2554 struct cgroup_subsys *ss = subsys[i];
2525 2555  
... ... @@ -2549,6 +2579,7 @@
2549 2579 {
2550 2580 int err;
2551 2581 int i;
  2582 + struct hlist_head *hhead;
2552 2583  
2553 2584 err = bdi_init(&cgroup_backing_dev_info);
2554 2585 if (err)
... ... @@ -2559,6 +2590,10 @@
2559 2590 if (!ss->early_init)
2560 2591 cgroup_init_subsys(ss);
2561 2592 }
  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);
2562 2597  
2563 2598 err = register_filesystem(&cgroup_fs_type);
2564 2599 if (err < 0)