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>
This commit is contained in:
parent
08ce5f16ee
commit
472b1053f3
|
@ -155,6 +155,12 @@ struct css_set {
|
||||||
*/
|
*/
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List running through all cgroup groups in the same hash
|
||||||
|
* slot. Protected by css_set_lock
|
||||||
|
*/
|
||||||
|
struct hlist_node hlist;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List running through all tasks using this cgroup
|
* List running through all tasks using this cgroup
|
||||||
* group. Protected by css_set_lock
|
* group. Protected by css_set_lock
|
||||||
|
@ -174,7 +180,6 @@ struct css_set {
|
||||||
* during subsystem registration (at boot time).
|
* during subsystem registration (at boot time).
|
||||||
*/
|
*/
|
||||||
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
|
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
#include <linux/delayacct.h>
|
#include <linux/delayacct.h>
|
||||||
#include <linux/cgroupstats.h>
|
#include <linux/cgroupstats.h>
|
||||||
|
#include <linux/hash.h>
|
||||||
|
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
|
@ -193,6 +194,27 @@ static struct cg_cgroup_link init_css_set_link;
|
||||||
static DEFINE_RWLOCK(css_set_lock);
|
static DEFINE_RWLOCK(css_set_lock);
|
||||||
static int css_set_count;
|
static int css_set_count;
|
||||||
|
|
||||||
|
/* hash table for cgroup groups. This improves the performance to
|
||||||
|
* find an existing css_set */
|
||||||
|
#define CSS_SET_HASH_BITS 7
|
||||||
|
#define CSS_SET_TABLE_SIZE (1 << CSS_SET_HASH_BITS)
|
||||||
|
static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE];
|
||||||
|
|
||||||
|
static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int index;
|
||||||
|
unsigned long tmp = 0UL;
|
||||||
|
|
||||||
|
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++)
|
||||||
|
tmp += (unsigned long)css[i];
|
||||||
|
tmp = (tmp >> 16) ^ tmp;
|
||||||
|
|
||||||
|
index = hash_long(tmp, CSS_SET_HASH_BITS);
|
||||||
|
|
||||||
|
return &css_set_table[index];
|
||||||
|
}
|
||||||
|
|
||||||
/* We don't maintain the lists running through each css_set to its
|
/* We don't maintain the lists running through each css_set to its
|
||||||
* task until after the first call to cgroup_iter_start(). This
|
* task until after the first call to cgroup_iter_start(). This
|
||||||
* reduces the fork()/exit() overhead for people who have cgroups
|
* reduces the fork()/exit() overhead for people who have cgroups
|
||||||
|
@ -219,6 +241,7 @@ static int use_task_css_set_links;
|
||||||
static void unlink_css_set(struct css_set *cg)
|
static void unlink_css_set(struct css_set *cg)
|
||||||
{
|
{
|
||||||
write_lock(&css_set_lock);
|
write_lock(&css_set_lock);
|
||||||
|
hlist_del(&cg->hlist);
|
||||||
list_del(&cg->list);
|
list_del(&cg->list);
|
||||||
css_set_count--;
|
css_set_count--;
|
||||||
while (!list_empty(&cg->cg_links)) {
|
while (!list_empty(&cg->cg_links)) {
|
||||||
|
@ -284,9 +307,7 @@ static inline void put_css_set_taskexit(struct css_set *cg)
|
||||||
/*
|
/*
|
||||||
* find_existing_css_set() is a helper for
|
* find_existing_css_set() is a helper for
|
||||||
* find_css_set(), and checks to see whether an existing
|
* find_css_set(), and checks to see whether an existing
|
||||||
* css_set is suitable. This currently walks a linked-list for
|
* css_set is suitable.
|
||||||
* simplicity; a later patch will use a hash table for better
|
|
||||||
* performance
|
|
||||||
*
|
*
|
||||||
* oldcg: the cgroup group that we're using before the cgroup
|
* oldcg: the cgroup group that we're using before the cgroup
|
||||||
* transition
|
* transition
|
||||||
|
@ -303,7 +324,9 @@ static struct css_set *find_existing_css_set(
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct cgroupfs_root *root = cgrp->root;
|
struct cgroupfs_root *root = cgrp->root;
|
||||||
struct list_head *l = &init_css_set.list;
|
struct hlist_head *hhead;
|
||||||
|
struct hlist_node *node;
|
||||||
|
struct css_set *cg;
|
||||||
|
|
||||||
/* Built the set of subsystem state objects that we want to
|
/* Built the set of subsystem state objects that we want to
|
||||||
* see in the new css_set */
|
* see in the new css_set */
|
||||||
|
@ -320,18 +343,13 @@ static struct css_set *find_existing_css_set(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look through existing cgroup groups to find one to reuse */
|
hhead = css_set_hash(template);
|
||||||
do {
|
hlist_for_each_entry(cg, node, hhead, hlist) {
|
||||||
struct css_set *cg =
|
|
||||||
list_entry(l, struct css_set, list);
|
|
||||||
|
|
||||||
if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
|
if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
|
||||||
/* All subsystems matched */
|
/* All subsystems matched */
|
||||||
return cg;
|
return cg;
|
||||||
}
|
}
|
||||||
/* Try the next cgroup group */
|
}
|
||||||
l = l->next;
|
|
||||||
} while (l != &init_css_set.list);
|
|
||||||
|
|
||||||
/* No existing cgroup group matched */
|
/* No existing cgroup group matched */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -393,6 +411,8 @@ static struct css_set *find_css_set(
|
||||||
struct list_head tmp_cg_links;
|
struct list_head tmp_cg_links;
|
||||||
struct cg_cgroup_link *link;
|
struct cg_cgroup_link *link;
|
||||||
|
|
||||||
|
struct hlist_head *hhead;
|
||||||
|
|
||||||
/* First see if we already have a cgroup group that matches
|
/* First see if we already have a cgroup group that matches
|
||||||
* the desired set */
|
* the desired set */
|
||||||
write_lock(&css_set_lock);
|
write_lock(&css_set_lock);
|
||||||
|
@ -417,6 +437,7 @@ static struct css_set *find_css_set(
|
||||||
kref_init(&res->ref);
|
kref_init(&res->ref);
|
||||||
INIT_LIST_HEAD(&res->cg_links);
|
INIT_LIST_HEAD(&res->cg_links);
|
||||||
INIT_LIST_HEAD(&res->tasks);
|
INIT_LIST_HEAD(&res->tasks);
|
||||||
|
INIT_HLIST_NODE(&res->hlist);
|
||||||
|
|
||||||
/* Copy the set of subsystem state objects generated in
|
/* Copy the set of subsystem state objects generated in
|
||||||
* find_existing_css_set() */
|
* find_existing_css_set() */
|
||||||
|
@ -459,6 +480,11 @@ static struct css_set *find_css_set(
|
||||||
/* Link this cgroup group into the list */
|
/* Link this cgroup group into the list */
|
||||||
list_add(&res->list, &init_css_set.list);
|
list_add(&res->list, &init_css_set.list);
|
||||||
css_set_count++;
|
css_set_count++;
|
||||||
|
|
||||||
|
/* Add this cgroup group to the hash table */
|
||||||
|
hhead = css_set_hash(res->subsys);
|
||||||
|
hlist_add_head(&res->hlist, hhead);
|
||||||
|
|
||||||
write_unlock(&css_set_lock);
|
write_unlock(&css_set_lock);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -2508,6 +2534,7 @@ int __init cgroup_init_early(void)
|
||||||
INIT_LIST_HEAD(&init_css_set.list);
|
INIT_LIST_HEAD(&init_css_set.list);
|
||||||
INIT_LIST_HEAD(&init_css_set.cg_links);
|
INIT_LIST_HEAD(&init_css_set.cg_links);
|
||||||
INIT_LIST_HEAD(&init_css_set.tasks);
|
INIT_LIST_HEAD(&init_css_set.tasks);
|
||||||
|
INIT_HLIST_NODE(&init_css_set.hlist);
|
||||||
css_set_count = 1;
|
css_set_count = 1;
|
||||||
init_cgroup_root(&rootnode);
|
init_cgroup_root(&rootnode);
|
||||||
list_add(&rootnode.root_list, &roots);
|
list_add(&rootnode.root_list, &roots);
|
||||||
|
@ -2520,6 +2547,9 @@ int __init cgroup_init_early(void)
|
||||||
list_add(&init_css_set_link.cg_link_list,
|
list_add(&init_css_set_link.cg_link_list,
|
||||||
&init_css_set.cg_links);
|
&init_css_set.cg_links);
|
||||||
|
|
||||||
|
for (i = 0; i < CSS_SET_TABLE_SIZE; i++)
|
||||||
|
INIT_HLIST_HEAD(&css_set_table[i]);
|
||||||
|
|
||||||
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
|
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
|
||||||
struct cgroup_subsys *ss = subsys[i];
|
struct cgroup_subsys *ss = subsys[i];
|
||||||
|
|
||||||
|
@ -2549,6 +2579,7 @@ int __init cgroup_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
int i;
|
int i;
|
||||||
|
struct hlist_head *hhead;
|
||||||
|
|
||||||
err = bdi_init(&cgroup_backing_dev_info);
|
err = bdi_init(&cgroup_backing_dev_info);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -2560,6 +2591,10 @@ int __init cgroup_init(void)
|
||||||
cgroup_init_subsys(ss);
|
cgroup_init_subsys(ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add init_css_set to the hash table */
|
||||||
|
hhead = css_set_hash(init_css_set.subsys);
|
||||||
|
hlist_add_head(&init_css_set.hlist, hhead);
|
||||||
|
|
||||||
err = register_filesystem(&cgroup_fs_type);
|
err = register_filesystem(&cgroup_fs_type);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Loading…
Reference in New Issue