memcg: add memory.vmscan_stat
The commit log of 0ae5e89c60
("memcg: count the soft_limit reclaim
in...") says it adds scanning stats to memory.stat file. But it doesn't
because we considered we needed to make a concensus for such new APIs.
This patch is a trial to add memory.scan_stat. This shows
- the number of scanned pages(total, anon, file)
- the number of rotated pages(total, anon, file)
- the number of freed pages(total, anon, file)
- the number of elaplsed time (including sleep/pause time)
for both of direct/soft reclaim.
The biggest difference with oringinal Ying's one is that this file
can be reset by some write, as
# echo 0 ...../memory.scan_stat
Example of output is here. This is a result after make -j 6 kernel
under 300M limit.
[kamezawa@bluextal ~]$ cat /cgroup/memory/A/memory.scan_stat
[kamezawa@bluextal ~]$ cat /cgroup/memory/A/memory.vmscan_stat
scanned_pages_by_limit 9471864
scanned_anon_pages_by_limit 6640629
scanned_file_pages_by_limit 2831235
rotated_pages_by_limit 4243974
rotated_anon_pages_by_limit 3971968
rotated_file_pages_by_limit 272006
freed_pages_by_limit 2318492
freed_anon_pages_by_limit 962052
freed_file_pages_by_limit 1356440
elapsed_ns_by_limit 351386416101
scanned_pages_by_system 0
scanned_anon_pages_by_system 0
scanned_file_pages_by_system 0
rotated_pages_by_system 0
rotated_anon_pages_by_system 0
rotated_file_pages_by_system 0
freed_pages_by_system 0
freed_anon_pages_by_system 0
freed_file_pages_by_system 0
elapsed_ns_by_system 0
scanned_pages_by_limit_under_hierarchy 9471864
scanned_anon_pages_by_limit_under_hierarchy 6640629
scanned_file_pages_by_limit_under_hierarchy 2831235
rotated_pages_by_limit_under_hierarchy 4243974
rotated_anon_pages_by_limit_under_hierarchy 3971968
rotated_file_pages_by_limit_under_hierarchy 272006
freed_pages_by_limit_under_hierarchy 2318492
freed_anon_pages_by_limit_under_hierarchy 962052
freed_file_pages_by_limit_under_hierarchy 1356440
elapsed_ns_by_limit_under_hierarchy 351386416101
scanned_pages_by_system_under_hierarchy 0
scanned_anon_pages_by_system_under_hierarchy 0
scanned_file_pages_by_system_under_hierarchy 0
rotated_pages_by_system_under_hierarchy 0
rotated_anon_pages_by_system_under_hierarchy 0
rotated_file_pages_by_system_under_hierarchy 0
freed_pages_by_system_under_hierarchy 0
freed_anon_pages_by_system_under_hierarchy 0
freed_file_pages_by_system_under_hierarchy 0
elapsed_ns_by_system_under_hierarchy 0
total_xxxx is for hierarchy management.
This will be useful for further memcg developments and need to be
developped before we do some complicated rework on LRU/softlimit
management.
This patch adds a new struct memcg_scanrecord into scan_control struct.
sc->nr_scanned at el is not designed for exporting information. For
example, nr_scanned is reset frequentrly and incremented +2 at scanning
mapped pages.
To avoid complexity, I added a new param in scan_control which is for
exporting scanning score.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Ying Han <yinghan@google.com>
Cc: Andrew Bresticker <abrestic@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
108b6a7846
commit
82f9d486e5
39
mm/vmscan.c
39
mm/vmscan.c
@ -105,6 +105,7 @@ struct scan_control {
|
||||
|
||||
/* Which cgroup do we reclaim from */
|
||||
struct mem_cgroup *mem_cgroup;
|
||||
struct memcg_scanrecord *memcg_record;
|
||||
|
||||
/*
|
||||
* Nodemask of nodes allowed by the caller. If NULL, all nodes
|
||||
@ -1348,6 +1349,8 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc,
|
||||
int file = is_file_lru(lru);
|
||||
int numpages = hpage_nr_pages(page);
|
||||
reclaim_stat->recent_rotated[file] += numpages;
|
||||
if (!scanning_global_lru(sc))
|
||||
sc->memcg_record->nr_rotated[file] += numpages;
|
||||
}
|
||||
if (!pagevec_add(&pvec, page)) {
|
||||
spin_unlock_irq(&zone->lru_lock);
|
||||
@ -1391,6 +1394,10 @@ static noinline_for_stack void update_isolated_counts(struct zone *zone,
|
||||
|
||||
reclaim_stat->recent_scanned[0] += *nr_anon;
|
||||
reclaim_stat->recent_scanned[1] += *nr_file;
|
||||
if (!scanning_global_lru(sc)) {
|
||||
sc->memcg_record->nr_scanned[0] += *nr_anon;
|
||||
sc->memcg_record->nr_scanned[1] += *nr_file;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1504,6 +1511,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
|
||||
nr_reclaimed += shrink_page_list(&page_list, zone, sc);
|
||||
}
|
||||
|
||||
if (!scanning_global_lru(sc))
|
||||
sc->memcg_record->nr_freed[file] += nr_reclaimed;
|
||||
|
||||
local_irq_disable();
|
||||
if (current_is_kswapd())
|
||||
__count_vm_events(KSWAPD_STEAL, nr_reclaimed);
|
||||
@ -1603,6 +1613,8 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
|
||||
}
|
||||
|
||||
reclaim_stat->recent_scanned[file] += nr_taken;
|
||||
if (!scanning_global_lru(sc))
|
||||
sc->memcg_record->nr_scanned[file] += nr_taken;
|
||||
|
||||
__count_zone_vm_events(PGREFILL, zone, pgscanned);
|
||||
if (file)
|
||||
@ -1654,6 +1666,8 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
|
||||
* get_scan_ratio.
|
||||
*/
|
||||
reclaim_stat->recent_rotated[file] += nr_rotated;
|
||||
if (!scanning_global_lru(sc))
|
||||
sc->memcg_record->nr_rotated[file] += nr_rotated;
|
||||
|
||||
move_active_pages_to_lru(zone, &l_active,
|
||||
LRU_ACTIVE + file * LRU_FILE);
|
||||
@ -2254,9 +2268,10 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
|
||||
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
|
||||
|
||||
unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
|
||||
gfp_t gfp_mask, bool noswap,
|
||||
struct zone *zone,
|
||||
unsigned long *nr_scanned)
|
||||
gfp_t gfp_mask, bool noswap,
|
||||
struct zone *zone,
|
||||
struct memcg_scanrecord *rec,
|
||||
unsigned long *scanned)
|
||||
{
|
||||
struct scan_control sc = {
|
||||
.nr_scanned = 0,
|
||||
@ -2266,7 +2281,9 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
|
||||
.may_swap = !noswap,
|
||||
.order = 0,
|
||||
.mem_cgroup = mem,
|
||||
.memcg_record = rec,
|
||||
};
|
||||
unsigned long start, end;
|
||||
|
||||
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
|
||||
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
|
||||
@ -2275,6 +2292,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
|
||||
sc.may_writepage,
|
||||
sc.gfp_mask);
|
||||
|
||||
start = sched_clock();
|
||||
/*
|
||||
* NOTE: Although we can get the priority field, using it
|
||||
* here is not a good idea, since it limits the pages we can scan.
|
||||
@ -2283,19 +2301,25 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
|
||||
* the priority and make it zero.
|
||||
*/
|
||||
shrink_zone(0, zone, &sc);
|
||||
end = sched_clock();
|
||||
|
||||
if (rec)
|
||||
rec->elapsed += end - start;
|
||||
*scanned = sc.nr_scanned;
|
||||
|
||||
trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
|
||||
|
||||
*nr_scanned = sc.nr_scanned;
|
||||
return sc.nr_reclaimed;
|
||||
}
|
||||
|
||||
unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
|
||||
gfp_t gfp_mask,
|
||||
bool noswap)
|
||||
bool noswap,
|
||||
struct memcg_scanrecord *rec)
|
||||
{
|
||||
struct zonelist *zonelist;
|
||||
unsigned long nr_reclaimed;
|
||||
unsigned long start, end;
|
||||
int nid;
|
||||
struct scan_control sc = {
|
||||
.may_writepage = !laptop_mode,
|
||||
@ -2304,6 +2328,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
|
||||
.nr_to_reclaim = SWAP_CLUSTER_MAX,
|
||||
.order = 0,
|
||||
.mem_cgroup = mem_cont,
|
||||
.memcg_record = rec,
|
||||
.nodemask = NULL, /* we don't care the placement */
|
||||
.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
|
||||
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
|
||||
@ -2312,6 +2337,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
|
||||
.gfp_mask = sc.gfp_mask,
|
||||
};
|
||||
|
||||
start = sched_clock();
|
||||
/*
|
||||
* Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
|
||||
* take care of from where we get pages. So the node where we start the
|
||||
@ -2326,6 +2352,9 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
|
||||
sc.gfp_mask);
|
||||
|
||||
nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
|
||||
end = sched_clock();
|
||||
if (rec)
|
||||
rec->elapsed += end - start;
|
||||
|
||||
trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
|
||||
|
||||
|
Reference in New Issue
Block a user