Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 472b1053 authored by Li Zefan's avatar Li Zefan Committed by Linus Torvalds
Browse files

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: default avatarLi Zefan <lizf@cn.fujitsu.com>
Reviewed-by: default avatarPaul 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 08ce5f16
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -155,6 +155,12 @@ struct css_set {
	 */
	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
	 * group. Protected by css_set_lock
@@ -174,7 +180,6 @@ struct css_set {
	 * during subsystem registration (at boot time).
	 */
	struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];

};

/*
+47 −12
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include <linux/kmod.h>
#include <linux/delayacct.h>
#include <linux/cgroupstats.h>
#include <linux/hash.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 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
 * task until after the first call to cgroup_iter_start(). This
 * 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)
{
	write_lock(&css_set_lock);
	hlist_del(&cg->hlist);
	list_del(&cg->list);
	css_set_count--;
	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_css_set(), and checks to see whether an existing
 * css_set is suitable. This currently walks a linked-list for
 * simplicity; a later patch will use a hash table for better
 * performance
 * css_set is suitable.
 *
 * oldcg: the cgroup group that we're using before the cgroup
 * transition
@@ -303,7 +324,9 @@ static struct css_set *find_existing_css_set(
{
	int i;
	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
	 * 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 */
	do {
		struct css_set *cg =
			list_entry(l, struct css_set, list);

	hhead = css_set_hash(template);
	hlist_for_each_entry(cg, node, hhead, hlist) {
		if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
			/* All subsystems matched */
			return cg;
		}
		/* Try the next cgroup group */
		l = l->next;
	} while (l != &init_css_set.list);
	}

	/* No existing cgroup group matched */
	return NULL;
@@ -393,6 +411,8 @@ static struct css_set *find_css_set(
	struct list_head tmp_cg_links;
	struct cg_cgroup_link *link;

	struct hlist_head *hhead;

	/* First see if we already have a cgroup group that matches
	 * the desired set */
	write_lock(&css_set_lock);
@@ -417,6 +437,7 @@ static struct css_set *find_css_set(
	kref_init(&res->ref);
	INIT_LIST_HEAD(&res->cg_links);
	INIT_LIST_HEAD(&res->tasks);
	INIT_HLIST_NODE(&res->hlist);

	/* Copy the set of subsystem state objects generated in
	 * find_existing_css_set() */
@@ -459,6 +480,11 @@ static struct css_set *find_css_set(
	/* Link this cgroup group into the list */
	list_add(&res->list, &init_css_set.list);
	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);

	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.cg_links);
	INIT_LIST_HEAD(&init_css_set.tasks);
	INIT_HLIST_NODE(&init_css_set.hlist);
	css_set_count = 1;
	init_cgroup_root(&rootnode);
	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,
		 &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++) {
		struct cgroup_subsys *ss = subsys[i];

@@ -2549,6 +2579,7 @@ int __init cgroup_init(void)
{
	int err;
	int i;
	struct hlist_head *hhead;

	err = bdi_init(&cgroup_backing_dev_info);
	if (err)
@@ -2560,6 +2591,10 @@ int __init cgroup_init(void)
			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);
	if (err < 0)
		goto out;