Commit 472b1053f3c319cc60bfb2a0bb062fed77a93eb6
Committed by
Linus Torvalds
1 parent
08ce5f16ee
Exists in
master
and in
4 other branches
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 | /* |
kernel/cgroup.c
... | ... | @@ -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) |