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.


---

 25-akpm/include/linux/mmzone.h     |    5 ++++
 25-akpm/include/linux/page-flags.h |   40 +++++++++++++++++++++++++++++++------
 25-akpm/mm/page_alloc.c            |   33 +++++++++++++++++++++++-------
 25-akpm/mm/vmscan.c                |   15 +++++++++----
 4 files changed, 74 insertions(+), 19 deletions(-)

diff -puN mm/page_alloc.c~instrument-highmem-page-reclaim mm/page_alloc.c
--- 25/mm/page_alloc.c~instrument-highmem-page-reclaim	Wed Mar 10 11:48:09 2004
+++ 25-akpm/mm/page_alloc.c	Wed Mar 10 11:48:09 2004
@@ -518,7 +518,7 @@ static struct page *buffered_rmqueue(str
 
 	if (page != NULL) {
 		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);
 	}
 	return page;
@@ -1061,6 +1061,7 @@ void show_free_areas(void)
 			" high:%lukB"
 			" active:%lukB"
 			" inactive:%lukB"
+			" present:%lukB"
 			"\n",
 			zone->name,
 			K(zone->free_pages),
@@ -1068,7 +1069,8 @@ void show_free_areas(void)
 			K(zone->pages_low),
 			K(zone->pages_high),
 			K(zone->nr_active),
-			K(zone->nr_inactive)
+			K(zone->nr_inactive),
+			K(zone->present_pages)
 			);
 	}
 
@@ -1626,23 +1628,38 @@ static char *vmstat_text[] = {
 	"pgpgout",
 	"pswpin",
 	"pswpout",
-	"pgalloc",
+	"pgalloc_high",
 
+	"pgalloc_normal",
+	"pgalloc_dma",
 	"pgfree",
 	"pgactivate",
 	"pgdeactivate",
+
 	"pgfault",
 	"pgmajfault",
-
-	"pgscan",
-	"pgrefill",
-	"pgsteal",
+	"pgrefill_high",
+	"pgrefill_normal",
+	"pgrefill_dma",
+
+	"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",
-	"kswapd_steal",
 
+	"slabs_scanned",
+	"kswapd_steal",
 	"kswapd_inodesteal",
 	"pageoutrun",
 	"allocstall",
+
 	"pgrotated",
 };
 
diff -puN include/linux/page-flags.h~instrument-highmem-page-reclaim include/linux/page-flags.h
--- 25/include/linux/page-flags.h~instrument-highmem-page-reclaim	Wed Mar 10 11:48:09 2004
+++ 25-akpm/include/linux/page-flags.h	Wed Mar 10 11:48:09 2004
@@ -98,23 +98,38 @@ struct page_state {
 	unsigned long pgpgout;		/* Disk writes */
 	unsigned long pswpin;		/* swap reads */
 	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 pgactivate;	/* pages moved inactive->active */
 	unsigned long pgdeactivate;	/* pages moved active->inactive */
+
 	unsigned long pgfault;		/* faults (major+minor) */
 	unsigned long pgmajfault;	/* faults (major only) */
-
-	unsigned long pgscan;		/* pages scanned by page reclaim */
-	unsigned long pgrefill;		/* inspected in refill_inactive_zone */
-	unsigned long pgsteal;		/* total pages reclaimed */
+	unsigned long pgrefill_high;	/* inspected in refill_inactive_zone */
+	unsigned long pgrefill_normal;
+	unsigned long pgrefill_dma;
+
+	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 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 pageoutrun;	/* kswapd's calls to page reclaim */
 	unsigned long allocstall;	/* direct reclaim calls */
+
 	unsigned long pgrotated;	/* pages rotated to tail of the LRU */
 } ____cacheline_aligned;
 
@@ -131,11 +146,24 @@ extern void get_full_page_state(struct p
 		local_irq_restore(flags);				\
 	} while (0)
 
+
 #define inc_page_state(member)	mod_page_state(member, 1UL)
 #define dec_page_state(member)	mod_page_state(member, 0UL - 1)
 #define add_page_state(member,delta) mod_page_state(member, (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
diff -puN mm/vmscan.c~instrument-highmem-page-reclaim mm/vmscan.c
--- 25/mm/vmscan.c~instrument-highmem-page-reclaim	Wed Mar 10 11:48:09 2004
+++ 25-akpm/mm/vmscan.c	Wed Mar 10 11:48:09 2004
@@ -155,6 +155,7 @@ static int shrink_slab(long scanned, uns
 			long nr_to_scan = shrinker->nr;
 
 			shrinker->nr = 0;
+			mod_page_state(slabs_scanned, nr_to_scan);
 			while (nr_to_scan) {
 				long this_scan = nr_to_scan;
 
@@ -459,9 +460,6 @@ keep:
 	list_splice(&ret_pages, page_list);
 	if (pagevec_count(&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);
 	return ret;
 }
@@ -532,9 +530,16 @@ shrink_cache(const int nr_pages, struct 
 			goto done;
 
 		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,
 					&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;
 		if (nr_freed <= 0 && list_empty(&page_list))
 			goto done;
@@ -733,7 +738,7 @@ refill_inactive_zone(struct zone *zone, 
 	spin_unlock_irq(&zone->lru_lock);
 	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);
 }
 
diff -puN include/linux/mmzone.h~instrument-highmem-page-reclaim include/linux/mmzone.h
--- 25/include/linux/mmzone.h~instrument-highmem-page-reclaim	Wed Mar 10 11:48:09 2004
+++ 25-akpm/include/linux/mmzone.h	Wed Mar 10 11:48:09 2004
@@ -288,6 +288,11 @@ static inline int is_highmem(struct zone
 	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 */
 struct ctl_table;
 struct file;

_