Commit 760d95b5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] vm: per-zone vmscan instrumentation

To check on zone balancing, split the /proc/vmstat:pgsteal, pgreclaim pgalloc
and pgscan stats into per-zone counters.

Additionally, split the pgscan stats into pgscan_direct and pgscan_kswapd to
see who's doing how much scanning.

And add a metric for the number of slab objects which were scanned.
parent bae30a3f
...@@ -288,6 +288,11 @@ static inline int is_highmem(struct zone *zone) ...@@ -288,6 +288,11 @@ static inline int is_highmem(struct zone *zone)
return (zone - zone->zone_pgdat->node_zones == ZONE_HIGHMEM); return (zone - zone->zone_pgdat->node_zones == ZONE_HIGHMEM);
} }
static inline int is_normal(struct zone *zone)
{
return (zone - zone->zone_pgdat->node_zones == ZONE_NORMAL);
}
/* These two functions are used to setup the per zone pages min values */ /* These two functions are used to setup the per zone pages min values */
struct ctl_table; struct ctl_table;
struct file; struct file;
......
...@@ -98,23 +98,38 @@ struct page_state { ...@@ -98,23 +98,38 @@ struct page_state {
unsigned long pgpgout; /* Disk writes */ unsigned long pgpgout; /* Disk writes */
unsigned long pswpin; /* swap reads */ unsigned long pswpin; /* swap reads */
unsigned long pswpout; /* swap writes */ unsigned long pswpout; /* swap writes */
unsigned long pgalloc; /* page allocations */ unsigned long pgalloc_high; /* page allocations */
unsigned long pgalloc_normal;
unsigned long pgalloc_dma;
unsigned long pgfree; /* page freeings */ unsigned long pgfree; /* page freeings */
unsigned long pgactivate; /* pages moved inactive->active */ unsigned long pgactivate; /* pages moved inactive->active */
unsigned long pgdeactivate; /* pages moved active->inactive */ unsigned long pgdeactivate; /* pages moved active->inactive */
unsigned long pgfault; /* faults (major+minor) */ unsigned long pgfault; /* faults (major+minor) */
unsigned long pgmajfault; /* faults (major only) */ unsigned long pgmajfault; /* faults (major only) */
unsigned long pgrefill_high; /* inspected in refill_inactive_zone */
unsigned long pgscan; /* pages scanned by page reclaim */ unsigned long pgrefill_normal;
unsigned long pgrefill; /* inspected in refill_inactive_zone */ unsigned long pgrefill_dma;
unsigned long pgsteal; /* total pages reclaimed */
unsigned long pgsteal_high; /* total highmem pages reclaimed */
unsigned long pgsteal_normal;
unsigned long pgsteal_dma;
unsigned long pgscan_kswapd_high;/* total highmem pages scanned */
unsigned long pgscan_kswapd_normal;
unsigned long pgscan_kswapd_dma;
unsigned long pgscan_direct_high;/* total highmem pages scanned */
unsigned long pgscan_direct_normal;
unsigned long pgscan_direct_dma;
unsigned long pginodesteal; /* pages reclaimed via inode freeing */ unsigned long pginodesteal; /* pages reclaimed via inode freeing */
unsigned long kswapd_steal; /* pages reclaimed by kswapd */
unsigned long slabs_scanned; /* slab objects scanned */
unsigned long kswapd_steal; /* pages reclaimed by kswapd */
unsigned long kswapd_inodesteal;/* reclaimed via kswapd inode freeing */ unsigned long kswapd_inodesteal;/* reclaimed via kswapd inode freeing */
unsigned long pageoutrun; /* kswapd's calls to page reclaim */ unsigned long pageoutrun; /* kswapd's calls to page reclaim */
unsigned long allocstall; /* direct reclaim calls */ unsigned long allocstall; /* direct reclaim calls */
unsigned long pgrotated; /* pages rotated to tail of the LRU */ unsigned long pgrotated; /* pages rotated to tail of the LRU */
} ____cacheline_aligned; } ____cacheline_aligned;
...@@ -131,11 +146,24 @@ extern void get_full_page_state(struct page_state *ret); ...@@ -131,11 +146,24 @@ extern void get_full_page_state(struct page_state *ret);
local_irq_restore(flags); \ local_irq_restore(flags); \
} while (0) } while (0)
#define inc_page_state(member) mod_page_state(member, 1UL) #define inc_page_state(member) mod_page_state(member, 1UL)
#define dec_page_state(member) mod_page_state(member, 0UL - 1) #define dec_page_state(member) mod_page_state(member, 0UL - 1)
#define add_page_state(member,delta) mod_page_state(member, (delta)) #define add_page_state(member,delta) mod_page_state(member, (delta))
#define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta)) #define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta))
#define mod_page_state_zone(zone, member, delta) \
do { \
unsigned long flags; \
local_irq_save(flags); \
if (is_highmem(zone)) \
__get_cpu_var(page_states).member##_high += (delta);\
else if (is_normal(zone)) \
__get_cpu_var(page_states).member##_normal += (delta);\
else \
__get_cpu_var(page_states).member##_dma += (delta);\
local_irq_restore(flags); \
} while (0)
/* /*
* Manipulation of page state flags * Manipulation of page state flags
......
...@@ -518,7 +518,7 @@ static struct page *buffered_rmqueue(struct zone *zone, int order, int cold) ...@@ -518,7 +518,7 @@ static struct page *buffered_rmqueue(struct zone *zone, int order, int cold)
if (page != NULL) { if (page != NULL) {
BUG_ON(bad_range(zone, page)); BUG_ON(bad_range(zone, page));
mod_page_state(pgalloc, 1 << order); mod_page_state_zone(zone, pgalloc, 1 << order);
prep_new_page(page, order); prep_new_page(page, order);
} }
return page; return page;
...@@ -1021,6 +1021,7 @@ void show_free_areas(void) ...@@ -1021,6 +1021,7 @@ void show_free_areas(void)
" high:%lukB" " high:%lukB"
" active:%lukB" " active:%lukB"
" inactive:%lukB" " inactive:%lukB"
" present:%lukB"
"\n", "\n",
zone->name, zone->name,
K(zone->free_pages), K(zone->free_pages),
...@@ -1028,7 +1029,8 @@ void show_free_areas(void) ...@@ -1028,7 +1029,8 @@ void show_free_areas(void)
K(zone->pages_low), K(zone->pages_low),
K(zone->pages_high), K(zone->pages_high),
K(zone->nr_active), K(zone->nr_active),
K(zone->nr_inactive) K(zone->nr_inactive),
K(zone->present_pages)
); );
} }
...@@ -1586,23 +1588,38 @@ static char *vmstat_text[] = { ...@@ -1586,23 +1588,38 @@ static char *vmstat_text[] = {
"pgpgout", "pgpgout",
"pswpin", "pswpin",
"pswpout", "pswpout",
"pgalloc", "pgalloc_high",
"pgalloc_normal",
"pgalloc_dma",
"pgfree", "pgfree",
"pgactivate", "pgactivate",
"pgdeactivate", "pgdeactivate",
"pgfault", "pgfault",
"pgmajfault", "pgmajfault",
"pgrefill_high",
"pgscan", "pgrefill_normal",
"pgrefill", "pgrefill_dma",
"pgsteal",
"pgsteal_high",
"pgsteal_normal",
"pgsteal_dma",
"pgscan_kswapd_high",
"pgscan_kswapd_normal",
"pgscan_kswapd_dma",
"pgscan_direct_high",
"pgscan_direct_normal",
"pgscan_direct_dma",
"pginodesteal", "pginodesteal",
"kswapd_steal",
"slabs_scanned",
"kswapd_steal",
"kswapd_inodesteal", "kswapd_inodesteal",
"pageoutrun", "pageoutrun",
"allocstall", "allocstall",
"pgrotated", "pgrotated",
}; };
......
...@@ -155,6 +155,7 @@ static int shrink_slab(long scanned, unsigned int gfp_mask) ...@@ -155,6 +155,7 @@ static int shrink_slab(long scanned, unsigned int gfp_mask)
long nr_to_scan = shrinker->nr; long nr_to_scan = shrinker->nr;
shrinker->nr = 0; shrinker->nr = 0;
mod_page_state(slabs_scanned, nr_to_scan);
while (nr_to_scan) { while (nr_to_scan) {
long this_scan = nr_to_scan; long this_scan = nr_to_scan;
...@@ -459,9 +460,6 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, ...@@ -459,9 +460,6 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask,
list_splice(&ret_pages, page_list); list_splice(&ret_pages, page_list);
if (pagevec_count(&freed_pvec)) if (pagevec_count(&freed_pvec))
__pagevec_release_nonlru(&freed_pvec); __pagevec_release_nonlru(&freed_pvec);
mod_page_state(pgsteal, ret);
if (current_is_kswapd())
mod_page_state(kswapd_steal, ret);
mod_page_state(pgactivate, pgactivate); mod_page_state(pgactivate, pgactivate);
return ret; return ret;
} }
...@@ -532,9 +530,16 @@ shrink_cache(const int nr_pages, struct zone *zone, ...@@ -532,9 +530,16 @@ shrink_cache(const int nr_pages, struct zone *zone,
goto done; goto done;
max_scan -= nr_scan; max_scan -= nr_scan;
mod_page_state(pgscan, nr_scan); if (current_is_kswapd())
mod_page_state_zone(zone, pgscan_kswapd, nr_scan);
else
mod_page_state_zone(zone, pgscan_direct, nr_scan);
nr_freed = shrink_list(&page_list, gfp_mask, nr_freed = shrink_list(&page_list, gfp_mask,
&max_scan, nr_mapped); &max_scan, nr_mapped);
if (current_is_kswapd())
mod_page_state(kswapd_steal, nr_freed);
mod_page_state_zone(zone, pgsteal, nr_freed);
ret += nr_freed; ret += nr_freed;
if (nr_freed <= 0 && list_empty(&page_list)) if (nr_freed <= 0 && list_empty(&page_list))
goto done; goto done;
...@@ -733,7 +738,7 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in, ...@@ -733,7 +738,7 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in,
spin_unlock_irq(&zone->lru_lock); spin_unlock_irq(&zone->lru_lock);
pagevec_release(&pvec); pagevec_release(&pvec);
mod_page_state(pgrefill, nr_pages_in - nr_pages); mod_page_state_zone(zone, pgrefill, nr_pages_in - nr_pages);
mod_page_state(pgdeactivate, pgdeactivate); mod_page_state(pgdeactivate, pgdeactivate);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment