[Devel] [RFC] memory controller : backgorund reclaim and avoid excessive locking [3/5] throttling
KAMEZAWA Hiroyuki
kamezawa.hiroyu at jp.fujitsu.com
Thu Feb 14 00:30:43 PST 2008
Throttle memory reclaim interface for cgroup.
This patch adds..
- a limit for simultaneous callers of try_to_free_mem_cgroup_pages().
- interface for that. memory.shrinkers.
There are some reasons.
- try_to_free... is very heavy and shoulnd't be called too much at once.
- When the number of callers of try_to_free.. is big, we'll reclaim
too much memory.
By this interface, a user can control the # of threads which can enter
try_to_free...
Default is 10240 ...a enough big number for unlimited. Maybe this should
be changed.
Changes from previous one.
- Added an interface to control the limit.
- don't call wake_up at uncharge()...it seems hevay..
Instead of that, sleepers use schedule_timeout(HZ/100). (10ms)
Considerations:
- Should we add this 'throttle' to global_lru at first ?
- Do we need more knobs ?
- Should default value to be automtically estimated value ?
(I used '# of cpus/4' as default in previous version.)
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu at jp.fujitsu.com>
mm/memcontrol.c | 235 ++++++++++++++++++++++++++++++--------------------------
1 files changed, 127 insertions(+), 108 deletions(-)
Index: linux-2.6.24-mm1/mm/memcontrol.c
===================================================================
--- linux-2.6.24-mm1.orig/mm/memcontrol.c
+++ linux-2.6.24-mm1/mm/memcontrol.c
@@ -145,8 +145,17 @@ struct mem_cgroup {
wait_queue_head_t waitq;
struct task_struct *kthread;
} daemon;
+ /*
+ * throttling params for reclaim.
+ */
+ struct {
+ int limit;
+ atomic_t reclaimers;
+ wait_queue_head_t waitq;
+ } throttle;
};
+
/*
* We use the lower bit of the page->page_cgroup pointer as a bit spin
* lock. We need to ensure that page->page_cgroup is atleast two
@@ -520,6 +529,27 @@ static inline void mem_cgroup_schedule_d
wake_up_interruptible(&mem->daemon.waitq);
}
+static inline void mem_cgroup_wait_reclaim(struct mem_cgroup *mem)
+{
+ DEFINE_WAIT(wait);
+ while (1) {
+ prepare_to_wait(&mem->throttle.waitq, &wait,
+ TASK_INTERRUPTIBLE);
+ if (res_counter_check_under_limit(&mem->res)) {
+ finish_wait(&mem->throttle.waitq, &wait);
+ break;
+ }
+ /* expect some progress in... */
+ schedule_timeout(HZ/50);
+ finish_wait(&mem->throttle.waitq, &wait);
+ }
+}
+
+static inline int mem_cgroup_throttle_reclaim(struct mem_cgroup *mem)
+{
+ return atomic_add_unless(&mem->throttle.reclaimers, 1,
+ mem->throttle.limit);
+}
unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
struct list_head *dst,
@@ -652,11 +682,22 @@ retry:
* the cgroup limit.
*/
while (res_counter_charge(&mem->res, PAGE_SIZE)) {
+ int ret;
if (!(gfp_mask & __GFP_WAIT))
goto out;
- if (try_to_free_mem_cgroup_pages(mem, gfp_mask))
+ if (((gfp_mask & (__GFP_FS|__GFP_IO)) != (__GFP_FS|__GFP_IO))
+ || mem_cgroup_throttle_reclaim(mem)) {
+ ret = try_to_free_mem_cgroup_pages(mem, gfp_mask);
+ atomic_dec(&mem->throttle.reclaimers);
+ if (waitqueue_active(&mem->throttle.waitq))
+ wake_up_all(&mem->throttle.waitq);
+ if (ret)
+ continue;
+ } else {
+ mem_cgroup_wait_reclaim(mem);
continue;
+ }
/*
* try_to_free_mem_cgroup_pages() might not give us a full
@@ -1054,6 +1095,19 @@ static ssize_t mem_force_empty_read(stru
return -EINVAL;
}
+static int mem_throttle_write(struct cgroup *cont, struct cftype *cft, u64 val)
+{
+ struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+ int limit = (int)val;
+ mem->throttle.limit = limit;
+ return 0;
+}
+
+static u64 mem_throttle_read(struct cgroup *cont, struct cftype *cft)
+{
+ struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+ return (u64)mem->throttle.limit;
+}
static const struct mem_cgroup_stat_desc {
const char *msg;
@@ -1146,6 +1200,11 @@ static struct cftype mem_cgroup_files[]
.read = mem_force_empty_read,
},
{
+ .name = "shrinks",
+ .write_uint = mem_throttle_write,
+ .read_uint = mem_throttle_read,
+ },
+ {
.name = "stat",
.open = mem_control_stat_open,
},
@@ -1215,6 +1274,11 @@ mem_cgroup_create(struct cgroup_subsys *
goto free_out;
init_waitqueue_head(&mem->daemon.waitq);
mem->daemon.kthread = NULL;
+
+ init_waitqueue_head(&mem->throttle.waitq);
+ mem->throttle.limit = 10240; /* maybe enough big for no throttle */
+ atomic_set(&mem->throttle.reclaimers, 0);
+
return &mem->css;
free_out:
for_each_node_state(node, N_POSSIBLE)
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list