xref: /linux/mm/vmstat.c (revision 8f32f7e5ac2ed11b0659b6b55af926f3d58ffd9d)
1f6ac2354SChristoph Lameter /*
2f6ac2354SChristoph Lameter  *  linux/mm/vmstat.c
3f6ac2354SChristoph Lameter  *
4f6ac2354SChristoph Lameter  *  Manages VM statistics
5f6ac2354SChristoph Lameter  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
62244b95aSChristoph Lameter  *
72244b95aSChristoph Lameter  *  zoned VM statistics
82244b95aSChristoph Lameter  *  Copyright (C) 2006 Silicon Graphics, Inc.,
92244b95aSChristoph Lameter  *		Christoph Lameter <christoph@lameter.com>
10f6ac2354SChristoph Lameter  */
11*8f32f7e5SAlexey Dobriyan #include <linux/fs.h>
12f6ac2354SChristoph Lameter #include <linux/mm.h>
134e950f6fSAlexey Dobriyan #include <linux/err.h>
142244b95aSChristoph Lameter #include <linux/module.h>
15df9ecabaSChristoph Lameter #include <linux/cpu.h>
16c748e134SAdrian Bunk #include <linux/vmstat.h>
17e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
18f6ac2354SChristoph Lameter 
19f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
20f8891e5eSChristoph Lameter DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
21f8891e5eSChristoph Lameter EXPORT_PER_CPU_SYMBOL(vm_event_states);
22f8891e5eSChristoph Lameter 
23f8891e5eSChristoph Lameter static void sum_vm_events(unsigned long *ret, cpumask_t *cpumask)
24f8891e5eSChristoph Lameter {
259eccf2a8SChristoph Lameter 	int cpu;
26f8891e5eSChristoph Lameter 	int i;
27f8891e5eSChristoph Lameter 
28f8891e5eSChristoph Lameter 	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
29f8891e5eSChristoph Lameter 
306d6a4360SMike Travis 	for_each_cpu_mask_nr(cpu, *cpumask) {
31f8891e5eSChristoph Lameter 		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
32f8891e5eSChristoph Lameter 
33f8891e5eSChristoph Lameter 		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
34f8891e5eSChristoph Lameter 			ret[i] += this->event[i];
35f8891e5eSChristoph Lameter 	}
36f8891e5eSChristoph Lameter }
37f8891e5eSChristoph Lameter 
38f8891e5eSChristoph Lameter /*
39f8891e5eSChristoph Lameter  * Accumulate the vm event counters across all CPUs.
40f8891e5eSChristoph Lameter  * The result is unavoidably approximate - it can change
41f8891e5eSChristoph Lameter  * during and after execution of this function.
42f8891e5eSChristoph Lameter */
43f8891e5eSChristoph Lameter void all_vm_events(unsigned long *ret)
44f8891e5eSChristoph Lameter {
45b5be1132SKOSAKI Motohiro 	get_online_cpus();
46f8891e5eSChristoph Lameter 	sum_vm_events(ret, &cpu_online_map);
47b5be1132SKOSAKI Motohiro 	put_online_cpus();
48f8891e5eSChristoph Lameter }
4932dd66fcSHeiko Carstens EXPORT_SYMBOL_GPL(all_vm_events);
50f8891e5eSChristoph Lameter 
51f8891e5eSChristoph Lameter #ifdef CONFIG_HOTPLUG
52f8891e5eSChristoph Lameter /*
53f8891e5eSChristoph Lameter  * Fold the foreign cpu events into our own.
54f8891e5eSChristoph Lameter  *
55f8891e5eSChristoph Lameter  * This is adding to the events on one processor
56f8891e5eSChristoph Lameter  * but keeps the global counts constant.
57f8891e5eSChristoph Lameter  */
58f8891e5eSChristoph Lameter void vm_events_fold_cpu(int cpu)
59f8891e5eSChristoph Lameter {
60f8891e5eSChristoph Lameter 	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
61f8891e5eSChristoph Lameter 	int i;
62f8891e5eSChristoph Lameter 
63f8891e5eSChristoph Lameter 	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
64f8891e5eSChristoph Lameter 		count_vm_events(i, fold_state->event[i]);
65f8891e5eSChristoph Lameter 		fold_state->event[i] = 0;
66f8891e5eSChristoph Lameter 	}
67f8891e5eSChristoph Lameter }
68f8891e5eSChristoph Lameter #endif /* CONFIG_HOTPLUG */
69f8891e5eSChristoph Lameter 
70f8891e5eSChristoph Lameter #endif /* CONFIG_VM_EVENT_COUNTERS */
71f8891e5eSChristoph Lameter 
722244b95aSChristoph Lameter /*
732244b95aSChristoph Lameter  * Manage combined zone based / global counters
742244b95aSChristoph Lameter  *
752244b95aSChristoph Lameter  * vm_stat contains the global counters
762244b95aSChristoph Lameter  */
772244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
782244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat);
792244b95aSChristoph Lameter 
802244b95aSChristoph Lameter #ifdef CONFIG_SMP
812244b95aSChristoph Lameter 
82df9ecabaSChristoph Lameter static int calculate_threshold(struct zone *zone)
83df9ecabaSChristoph Lameter {
84df9ecabaSChristoph Lameter 	int threshold;
85df9ecabaSChristoph Lameter 	int mem;	/* memory in 128 MB units */
862244b95aSChristoph Lameter 
872244b95aSChristoph Lameter 	/*
88df9ecabaSChristoph Lameter 	 * The threshold scales with the number of processors and the amount
89df9ecabaSChristoph Lameter 	 * of memory per zone. More memory means that we can defer updates for
90df9ecabaSChristoph Lameter 	 * longer, more processors could lead to more contention.
91df9ecabaSChristoph Lameter  	 * fls() is used to have a cheap way of logarithmic scaling.
922244b95aSChristoph Lameter 	 *
93df9ecabaSChristoph Lameter 	 * Some sample thresholds:
94df9ecabaSChristoph Lameter 	 *
95df9ecabaSChristoph Lameter 	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
96df9ecabaSChristoph Lameter 	 * ------------------------------------------------------------------
97df9ecabaSChristoph Lameter 	 * 8		1		1	0.9-1 GB	4
98df9ecabaSChristoph Lameter 	 * 16		2		2	0.9-1 GB	4
99df9ecabaSChristoph Lameter 	 * 20 		2		2	1-2 GB		5
100df9ecabaSChristoph Lameter 	 * 24		2		2	2-4 GB		6
101df9ecabaSChristoph Lameter 	 * 28		2		2	4-8 GB		7
102df9ecabaSChristoph Lameter 	 * 32		2		2	8-16 GB		8
103df9ecabaSChristoph Lameter 	 * 4		2		2	<128M		1
104df9ecabaSChristoph Lameter 	 * 30		4		3	2-4 GB		5
105df9ecabaSChristoph Lameter 	 * 48		4		3	8-16 GB		8
106df9ecabaSChristoph Lameter 	 * 32		8		4	1-2 GB		4
107df9ecabaSChristoph Lameter 	 * 32		8		4	0.9-1GB		4
108df9ecabaSChristoph Lameter 	 * 10		16		5	<128M		1
109df9ecabaSChristoph Lameter 	 * 40		16		5	900M		4
110df9ecabaSChristoph Lameter 	 * 70		64		7	2-4 GB		5
111df9ecabaSChristoph Lameter 	 * 84		64		7	4-8 GB		6
112df9ecabaSChristoph Lameter 	 * 108		512		9	4-8 GB		6
113df9ecabaSChristoph Lameter 	 * 125		1024		10	8-16 GB		8
114df9ecabaSChristoph Lameter 	 * 125		1024		10	16-32 GB	9
1152244b95aSChristoph Lameter 	 */
116df9ecabaSChristoph Lameter 
117df9ecabaSChristoph Lameter 	mem = zone->present_pages >> (27 - PAGE_SHIFT);
118df9ecabaSChristoph Lameter 
119df9ecabaSChristoph Lameter 	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
120df9ecabaSChristoph Lameter 
121df9ecabaSChristoph Lameter 	/*
122df9ecabaSChristoph Lameter 	 * Maximum threshold is 125
123df9ecabaSChristoph Lameter 	 */
124df9ecabaSChristoph Lameter 	threshold = min(125, threshold);
125df9ecabaSChristoph Lameter 
126df9ecabaSChristoph Lameter 	return threshold;
127df9ecabaSChristoph Lameter }
128df9ecabaSChristoph Lameter 
129df9ecabaSChristoph Lameter /*
130df9ecabaSChristoph Lameter  * Refresh the thresholds for each zone.
131df9ecabaSChristoph Lameter  */
132df9ecabaSChristoph Lameter static void refresh_zone_stat_thresholds(void)
1332244b95aSChristoph Lameter {
134df9ecabaSChristoph Lameter 	struct zone *zone;
135df9ecabaSChristoph Lameter 	int cpu;
136df9ecabaSChristoph Lameter 	int threshold;
137df9ecabaSChristoph Lameter 
138df9ecabaSChristoph Lameter 	for_each_zone(zone) {
139df9ecabaSChristoph Lameter 
140df9ecabaSChristoph Lameter 		if (!zone->present_pages)
141df9ecabaSChristoph Lameter 			continue;
142df9ecabaSChristoph Lameter 
143df9ecabaSChristoph Lameter 		threshold = calculate_threshold(zone);
144df9ecabaSChristoph Lameter 
145df9ecabaSChristoph Lameter 		for_each_online_cpu(cpu)
146df9ecabaSChristoph Lameter 			zone_pcp(zone, cpu)->stat_threshold = threshold;
147df9ecabaSChristoph Lameter 	}
1482244b95aSChristoph Lameter }
1492244b95aSChristoph Lameter 
1502244b95aSChristoph Lameter /*
1512244b95aSChristoph Lameter  * For use when we know that interrupts are disabled.
1522244b95aSChristoph Lameter  */
1532244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1542244b95aSChristoph Lameter 				int delta)
1552244b95aSChristoph Lameter {
156df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
157df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
1582244b95aSChristoph Lameter 	long x;
1592244b95aSChristoph Lameter 
1602244b95aSChristoph Lameter 	x = delta + *p;
1612244b95aSChristoph Lameter 
162df9ecabaSChristoph Lameter 	if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) {
1632244b95aSChristoph Lameter 		zone_page_state_add(x, zone, item);
1642244b95aSChristoph Lameter 		x = 0;
1652244b95aSChristoph Lameter 	}
1662244b95aSChristoph Lameter 	*p = x;
1672244b95aSChristoph Lameter }
1682244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
1692244b95aSChristoph Lameter 
1702244b95aSChristoph Lameter /*
1712244b95aSChristoph Lameter  * For an unknown interrupt state
1722244b95aSChristoph Lameter  */
1732244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1742244b95aSChristoph Lameter 					int delta)
1752244b95aSChristoph Lameter {
1762244b95aSChristoph Lameter 	unsigned long flags;
1772244b95aSChristoph Lameter 
1782244b95aSChristoph Lameter 	local_irq_save(flags);
1792244b95aSChristoph Lameter 	__mod_zone_page_state(zone, item, delta);
1802244b95aSChristoph Lameter 	local_irq_restore(flags);
1812244b95aSChristoph Lameter }
1822244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
1832244b95aSChristoph Lameter 
1842244b95aSChristoph Lameter /*
1852244b95aSChristoph Lameter  * Optimized increment and decrement functions.
1862244b95aSChristoph Lameter  *
1872244b95aSChristoph Lameter  * These are only for a single page and therefore can take a struct page *
1882244b95aSChristoph Lameter  * argument instead of struct zone *. This allows the inclusion of the code
1892244b95aSChristoph Lameter  * generated for page_zone(page) into the optimized functions.
1902244b95aSChristoph Lameter  *
1912244b95aSChristoph Lameter  * No overflow check is necessary and therefore the differential can be
1922244b95aSChristoph Lameter  * incremented or decremented in place which may allow the compilers to
1932244b95aSChristoph Lameter  * generate better code.
1942244b95aSChristoph Lameter  * The increment or decrement is known and therefore one boundary check can
1952244b95aSChristoph Lameter  * be omitted.
1962244b95aSChristoph Lameter  *
197df9ecabaSChristoph Lameter  * NOTE: These functions are very performance sensitive. Change only
198df9ecabaSChristoph Lameter  * with care.
199df9ecabaSChristoph Lameter  *
2002244b95aSChristoph Lameter  * Some processors have inc/dec instructions that are atomic vs an interrupt.
2012244b95aSChristoph Lameter  * However, the code must first determine the differential location in a zone
2022244b95aSChristoph Lameter  * based on the processor number and then inc/dec the counter. There is no
2032244b95aSChristoph Lameter  * guarantee without disabling preemption that the processor will not change
2042244b95aSChristoph Lameter  * in between and therefore the atomicity vs. interrupt cannot be exploited
2052244b95aSChristoph Lameter  * in a useful way here.
2062244b95aSChristoph Lameter  */
207c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2082244b95aSChristoph Lameter {
209df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
210df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2112244b95aSChristoph Lameter 
2122244b95aSChristoph Lameter 	(*p)++;
2132244b95aSChristoph Lameter 
214df9ecabaSChristoph Lameter 	if (unlikely(*p > pcp->stat_threshold)) {
215df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
216df9ecabaSChristoph Lameter 
217df9ecabaSChristoph Lameter 		zone_page_state_add(*p + overstep, zone, item);
218df9ecabaSChristoph Lameter 		*p = -overstep;
2192244b95aSChristoph Lameter 	}
2202244b95aSChristoph Lameter }
221ca889e6cSChristoph Lameter 
222ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
223ca889e6cSChristoph Lameter {
224ca889e6cSChristoph Lameter 	__inc_zone_state(page_zone(page), item);
225ca889e6cSChristoph Lameter }
2262244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
2272244b95aSChristoph Lameter 
228c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2292244b95aSChristoph Lameter {
230df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
231df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2322244b95aSChristoph Lameter 
2332244b95aSChristoph Lameter 	(*p)--;
2342244b95aSChristoph Lameter 
235df9ecabaSChristoph Lameter 	if (unlikely(*p < - pcp->stat_threshold)) {
236df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
237df9ecabaSChristoph Lameter 
238df9ecabaSChristoph Lameter 		zone_page_state_add(*p - overstep, zone, item);
239df9ecabaSChristoph Lameter 		*p = overstep;
2402244b95aSChristoph Lameter 	}
2412244b95aSChristoph Lameter }
242c8785385SChristoph Lameter 
243c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
244c8785385SChristoph Lameter {
245c8785385SChristoph Lameter 	__dec_zone_state(page_zone(page), item);
246c8785385SChristoph Lameter }
2472244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
2482244b95aSChristoph Lameter 
249ca889e6cSChristoph Lameter void inc_zone_state(struct zone *zone, enum zone_stat_item item)
250ca889e6cSChristoph Lameter {
251ca889e6cSChristoph Lameter 	unsigned long flags;
252ca889e6cSChristoph Lameter 
253ca889e6cSChristoph Lameter 	local_irq_save(flags);
254ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
255ca889e6cSChristoph Lameter 	local_irq_restore(flags);
256ca889e6cSChristoph Lameter }
257ca889e6cSChristoph Lameter 
2582244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
2592244b95aSChristoph Lameter {
2602244b95aSChristoph Lameter 	unsigned long flags;
2612244b95aSChristoph Lameter 	struct zone *zone;
2622244b95aSChristoph Lameter 
2632244b95aSChristoph Lameter 	zone = page_zone(page);
2642244b95aSChristoph Lameter 	local_irq_save(flags);
265ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
2662244b95aSChristoph Lameter 	local_irq_restore(flags);
2672244b95aSChristoph Lameter }
2682244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
2692244b95aSChristoph Lameter 
2702244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
2712244b95aSChristoph Lameter {
2722244b95aSChristoph Lameter 	unsigned long flags;
2732244b95aSChristoph Lameter 
2742244b95aSChristoph Lameter 	local_irq_save(flags);
275a302eb4eSChristoph Lameter 	__dec_zone_page_state(page, item);
2762244b95aSChristoph Lameter 	local_irq_restore(flags);
2772244b95aSChristoph Lameter }
2782244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
2792244b95aSChristoph Lameter 
2802244b95aSChristoph Lameter /*
2812244b95aSChristoph Lameter  * Update the zone counters for one cpu.
2824037d452SChristoph Lameter  *
283a7f75e25SChristoph Lameter  * The cpu specified must be either the current cpu or a processor that
284a7f75e25SChristoph Lameter  * is not online. If it is the current cpu then the execution thread must
285a7f75e25SChristoph Lameter  * be pinned to the current cpu.
286a7f75e25SChristoph Lameter  *
2874037d452SChristoph Lameter  * Note that refresh_cpu_vm_stats strives to only access
2884037d452SChristoph Lameter  * node local memory. The per cpu pagesets on remote zones are placed
2894037d452SChristoph Lameter  * in the memory local to the processor using that pageset. So the
2904037d452SChristoph Lameter  * loop over all zones will access a series of cachelines local to
2914037d452SChristoph Lameter  * the processor.
2924037d452SChristoph Lameter  *
2934037d452SChristoph Lameter  * The call to zone_page_state_add updates the cachelines with the
2944037d452SChristoph Lameter  * statistics in the remote zone struct as well as the global cachelines
2954037d452SChristoph Lameter  * with the global counters. These could cause remote node cache line
2964037d452SChristoph Lameter  * bouncing and will have to be only done when necessary.
2972244b95aSChristoph Lameter  */
2982244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu)
2992244b95aSChristoph Lameter {
3002244b95aSChristoph Lameter 	struct zone *zone;
3012244b95aSChristoph Lameter 	int i;
302a7f75e25SChristoph Lameter 	int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3032244b95aSChristoph Lameter 
3042244b95aSChristoph Lameter 	for_each_zone(zone) {
3054037d452SChristoph Lameter 		struct per_cpu_pageset *p;
3062244b95aSChristoph Lameter 
30739bbcb8fSChristoph Lameter 		if (!populated_zone(zone))
30839bbcb8fSChristoph Lameter 			continue;
30939bbcb8fSChristoph Lameter 
3104037d452SChristoph Lameter 		p = zone_pcp(zone, cpu);
3112244b95aSChristoph Lameter 
3122244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
3134037d452SChristoph Lameter 			if (p->vm_stat_diff[i]) {
314a7f75e25SChristoph Lameter 				unsigned long flags;
315a7f75e25SChristoph Lameter 				int v;
316a7f75e25SChristoph Lameter 
3172244b95aSChristoph Lameter 				local_irq_save(flags);
318a7f75e25SChristoph Lameter 				v = p->vm_stat_diff[i];
3194037d452SChristoph Lameter 				p->vm_stat_diff[i] = 0;
320a7f75e25SChristoph Lameter 				local_irq_restore(flags);
321a7f75e25SChristoph Lameter 				atomic_long_add(v, &zone->vm_stat[i]);
322a7f75e25SChristoph Lameter 				global_diff[i] += v;
3234037d452SChristoph Lameter #ifdef CONFIG_NUMA
3244037d452SChristoph Lameter 				/* 3 seconds idle till flush */
3254037d452SChristoph Lameter 				p->expire = 3;
3264037d452SChristoph Lameter #endif
3272244b95aSChristoph Lameter 			}
328468fd62eSDimitri Sivanich 		cond_resched();
3294037d452SChristoph Lameter #ifdef CONFIG_NUMA
3304037d452SChristoph Lameter 		/*
3314037d452SChristoph Lameter 		 * Deal with draining the remote pageset of this
3324037d452SChristoph Lameter 		 * processor
3334037d452SChristoph Lameter 		 *
3344037d452SChristoph Lameter 		 * Check if there are pages remaining in this pageset
3354037d452SChristoph Lameter 		 * if not then there is nothing to expire.
3364037d452SChristoph Lameter 		 */
3373dfa5721SChristoph Lameter 		if (!p->expire || !p->pcp.count)
3384037d452SChristoph Lameter 			continue;
3394037d452SChristoph Lameter 
3404037d452SChristoph Lameter 		/*
3414037d452SChristoph Lameter 		 * We never drain zones local to this processor.
3424037d452SChristoph Lameter 		 */
3434037d452SChristoph Lameter 		if (zone_to_nid(zone) == numa_node_id()) {
3444037d452SChristoph Lameter 			p->expire = 0;
3454037d452SChristoph Lameter 			continue;
3464037d452SChristoph Lameter 		}
3474037d452SChristoph Lameter 
3484037d452SChristoph Lameter 		p->expire--;
3494037d452SChristoph Lameter 		if (p->expire)
3504037d452SChristoph Lameter 			continue;
3514037d452SChristoph Lameter 
3523dfa5721SChristoph Lameter 		if (p->pcp.count)
3533dfa5721SChristoph Lameter 			drain_zone_pages(zone, &p->pcp);
3544037d452SChristoph Lameter #endif
3552244b95aSChristoph Lameter 	}
356a7f75e25SChristoph Lameter 
357a7f75e25SChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
358a7f75e25SChristoph Lameter 		if (global_diff[i])
359a7f75e25SChristoph Lameter 			atomic_long_add(global_diff[i], &vm_stat[i]);
3602244b95aSChristoph Lameter }
3612244b95aSChristoph Lameter 
3622244b95aSChristoph Lameter #endif
3632244b95aSChristoph Lameter 
364ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
365ca889e6cSChristoph Lameter /*
366ca889e6cSChristoph Lameter  * zonelist = the list of zones passed to the allocator
367ca889e6cSChristoph Lameter  * z 	    = the zone from which the allocation occurred.
368ca889e6cSChristoph Lameter  *
369ca889e6cSChristoph Lameter  * Must be called with interrupts disabled.
370ca889e6cSChristoph Lameter  */
37118ea7e71SMel Gorman void zone_statistics(struct zone *preferred_zone, struct zone *z)
372ca889e6cSChristoph Lameter {
37318ea7e71SMel Gorman 	if (z->zone_pgdat == preferred_zone->zone_pgdat) {
374ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_HIT);
375ca889e6cSChristoph Lameter 	} else {
376ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_MISS);
37718ea7e71SMel Gorman 		__inc_zone_state(preferred_zone, NUMA_FOREIGN);
378ca889e6cSChristoph Lameter 	}
3795d292343SChristoph Lameter 	if (z->node == numa_node_id())
380ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_LOCAL);
381ca889e6cSChristoph Lameter 	else
382ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_OTHER);
383ca889e6cSChristoph Lameter }
384ca889e6cSChristoph Lameter #endif
385ca889e6cSChristoph Lameter 
386f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS
387*8f32f7e5SAlexey Dobriyan #include <linux/proc_fs.h>
388f6ac2354SChristoph Lameter #include <linux/seq_file.h>
389f6ac2354SChristoph Lameter 
390467c996cSMel Gorman static char * const migratetype_names[MIGRATE_TYPES] = {
391467c996cSMel Gorman 	"Unmovable",
392467c996cSMel Gorman 	"Reclaimable",
393467c996cSMel Gorman 	"Movable",
394467c996cSMel Gorman 	"Reserve",
39591446b06SKOSAKI Motohiro 	"Isolate",
396467c996cSMel Gorman };
397467c996cSMel Gorman 
398f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos)
399f6ac2354SChristoph Lameter {
400f6ac2354SChristoph Lameter 	pg_data_t *pgdat;
401f6ac2354SChristoph Lameter 	loff_t node = *pos;
402f6ac2354SChristoph Lameter 	for (pgdat = first_online_pgdat();
403f6ac2354SChristoph Lameter 	     pgdat && node;
404f6ac2354SChristoph Lameter 	     pgdat = next_online_pgdat(pgdat))
405f6ac2354SChristoph Lameter 		--node;
406f6ac2354SChristoph Lameter 
407f6ac2354SChristoph Lameter 	return pgdat;
408f6ac2354SChristoph Lameter }
409f6ac2354SChristoph Lameter 
410f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
411f6ac2354SChristoph Lameter {
412f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
413f6ac2354SChristoph Lameter 
414f6ac2354SChristoph Lameter 	(*pos)++;
415f6ac2354SChristoph Lameter 	return next_online_pgdat(pgdat);
416f6ac2354SChristoph Lameter }
417f6ac2354SChristoph Lameter 
418f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg)
419f6ac2354SChristoph Lameter {
420f6ac2354SChristoph Lameter }
421f6ac2354SChristoph Lameter 
422467c996cSMel Gorman /* Walk all the zones in a node and print using a callback */
423467c996cSMel Gorman static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
424467c996cSMel Gorman 		void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
425f6ac2354SChristoph Lameter {
426f6ac2354SChristoph Lameter 	struct zone *zone;
427f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
428f6ac2354SChristoph Lameter 	unsigned long flags;
429f6ac2354SChristoph Lameter 
430f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
431f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
432f6ac2354SChristoph Lameter 			continue;
433f6ac2354SChristoph Lameter 
434f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
435467c996cSMel Gorman 		print(m, pgdat, zone);
436467c996cSMel Gorman 		spin_unlock_irqrestore(&zone->lock, flags);
437467c996cSMel Gorman 	}
438467c996cSMel Gorman }
439467c996cSMel Gorman 
440467c996cSMel Gorman static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
441467c996cSMel Gorman 						struct zone *zone)
442467c996cSMel Gorman {
443467c996cSMel Gorman 	int order;
444467c996cSMel Gorman 
445f6ac2354SChristoph Lameter 	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
446f6ac2354SChristoph Lameter 	for (order = 0; order < MAX_ORDER; ++order)
447f6ac2354SChristoph Lameter 		seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
448f6ac2354SChristoph Lameter 	seq_putc(m, '\n');
449f6ac2354SChristoph Lameter }
450467c996cSMel Gorman 
451467c996cSMel Gorman /*
452467c996cSMel Gorman  * This walks the free areas for each zone.
453467c996cSMel Gorman  */
454467c996cSMel Gorman static int frag_show(struct seq_file *m, void *arg)
455467c996cSMel Gorman {
456467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
457467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, frag_show_print);
458467c996cSMel Gorman 	return 0;
459467c996cSMel Gorman }
460467c996cSMel Gorman 
461467c996cSMel Gorman static void pagetypeinfo_showfree_print(struct seq_file *m,
462467c996cSMel Gorman 					pg_data_t *pgdat, struct zone *zone)
463467c996cSMel Gorman {
464467c996cSMel Gorman 	int order, mtype;
465467c996cSMel Gorman 
466467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
467467c996cSMel Gorman 		seq_printf(m, "Node %4d, zone %8s, type %12s ",
468467c996cSMel Gorman 					pgdat->node_id,
469467c996cSMel Gorman 					zone->name,
470467c996cSMel Gorman 					migratetype_names[mtype]);
471467c996cSMel Gorman 		for (order = 0; order < MAX_ORDER; ++order) {
472467c996cSMel Gorman 			unsigned long freecount = 0;
473467c996cSMel Gorman 			struct free_area *area;
474467c996cSMel Gorman 			struct list_head *curr;
475467c996cSMel Gorman 
476467c996cSMel Gorman 			area = &(zone->free_area[order]);
477467c996cSMel Gorman 
478467c996cSMel Gorman 			list_for_each(curr, &area->free_list[mtype])
479467c996cSMel Gorman 				freecount++;
480467c996cSMel Gorman 			seq_printf(m, "%6lu ", freecount);
481467c996cSMel Gorman 		}
482467c996cSMel Gorman 		seq_putc(m, '\n');
483467c996cSMel Gorman 	}
484467c996cSMel Gorman }
485467c996cSMel Gorman 
486467c996cSMel Gorman /* Print out the free pages at each order for each migatetype */
487467c996cSMel Gorman static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
488467c996cSMel Gorman {
489467c996cSMel Gorman 	int order;
490467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
491467c996cSMel Gorman 
492467c996cSMel Gorman 	/* Print header */
493467c996cSMel Gorman 	seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
494467c996cSMel Gorman 	for (order = 0; order < MAX_ORDER; ++order)
495467c996cSMel Gorman 		seq_printf(m, "%6d ", order);
496467c996cSMel Gorman 	seq_putc(m, '\n');
497467c996cSMel Gorman 
498467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
499467c996cSMel Gorman 
500467c996cSMel Gorman 	return 0;
501467c996cSMel Gorman }
502467c996cSMel Gorman 
503467c996cSMel Gorman static void pagetypeinfo_showblockcount_print(struct seq_file *m,
504467c996cSMel Gorman 					pg_data_t *pgdat, struct zone *zone)
505467c996cSMel Gorman {
506467c996cSMel Gorman 	int mtype;
507467c996cSMel Gorman 	unsigned long pfn;
508467c996cSMel Gorman 	unsigned long start_pfn = zone->zone_start_pfn;
509467c996cSMel Gorman 	unsigned long end_pfn = start_pfn + zone->spanned_pages;
510467c996cSMel Gorman 	unsigned long count[MIGRATE_TYPES] = { 0, };
511467c996cSMel Gorman 
512467c996cSMel Gorman 	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
513467c996cSMel Gorman 		struct page *page;
514467c996cSMel Gorman 
515467c996cSMel Gorman 		if (!pfn_valid(pfn))
516467c996cSMel Gorman 			continue;
517467c996cSMel Gorman 
518467c996cSMel Gorman 		page = pfn_to_page(pfn);
519e80d6a24SMel Gorman #ifdef CONFIG_ARCH_FLATMEM_HAS_HOLES
520e80d6a24SMel Gorman 		/*
521e80d6a24SMel Gorman 		 * Ordinarily, memory holes in flatmem still have a valid
522e80d6a24SMel Gorman 		 * memmap for the PFN range. However, an architecture for
523e80d6a24SMel Gorman 		 * embedded systems (e.g. ARM) can free up the memmap backing
524e80d6a24SMel Gorman 		 * holes to save memory on the assumption the memmap is
525e80d6a24SMel Gorman 		 * never used. The page_zone linkages are then broken even
526e80d6a24SMel Gorman 		 * though pfn_valid() returns true. Skip the page if the
527e80d6a24SMel Gorman 		 * linkages are broken. Even if this test passed, the impact
528e80d6a24SMel Gorman 		 * is that the counters for the movable type are off but
529e80d6a24SMel Gorman 		 * fragmentation monitoring is likely meaningless on small
530e80d6a24SMel Gorman 		 * systems.
531e80d6a24SMel Gorman 		 */
532e80d6a24SMel Gorman 		if (page_zone(page) != zone)
533e80d6a24SMel Gorman 			continue;
534e80d6a24SMel Gorman #endif
535467c996cSMel Gorman 		mtype = get_pageblock_migratetype(page);
536467c996cSMel Gorman 
537e80d6a24SMel Gorman 		if (mtype < MIGRATE_TYPES)
538467c996cSMel Gorman 			count[mtype]++;
539467c996cSMel Gorman 	}
540467c996cSMel Gorman 
541467c996cSMel Gorman 	/* Print counts */
542467c996cSMel Gorman 	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
543467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
544467c996cSMel Gorman 		seq_printf(m, "%12lu ", count[mtype]);
545467c996cSMel Gorman 	seq_putc(m, '\n');
546467c996cSMel Gorman }
547467c996cSMel Gorman 
548467c996cSMel Gorman /* Print out the free pages at each order for each migratetype */
549467c996cSMel Gorman static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
550467c996cSMel Gorman {
551467c996cSMel Gorman 	int mtype;
552467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
553467c996cSMel Gorman 
554467c996cSMel Gorman 	seq_printf(m, "\n%-23s", "Number of blocks type ");
555467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
556467c996cSMel Gorman 		seq_printf(m, "%12s ", migratetype_names[mtype]);
557467c996cSMel Gorman 	seq_putc(m, '\n');
558467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
559467c996cSMel Gorman 
560467c996cSMel Gorman 	return 0;
561467c996cSMel Gorman }
562467c996cSMel Gorman 
563467c996cSMel Gorman /*
564467c996cSMel Gorman  * This prints out statistics in relation to grouping pages by mobility.
565467c996cSMel Gorman  * It is expensive to collect so do not constantly read the file.
566467c996cSMel Gorman  */
567467c996cSMel Gorman static int pagetypeinfo_show(struct seq_file *m, void *arg)
568467c996cSMel Gorman {
569467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
570467c996cSMel Gorman 
57141b25a37SKOSAKI Motohiro 	/* check memoryless node */
57241b25a37SKOSAKI Motohiro 	if (!node_state(pgdat->node_id, N_HIGH_MEMORY))
57341b25a37SKOSAKI Motohiro 		return 0;
57441b25a37SKOSAKI Motohiro 
575467c996cSMel Gorman 	seq_printf(m, "Page block order: %d\n", pageblock_order);
576467c996cSMel Gorman 	seq_printf(m, "Pages per block:  %lu\n", pageblock_nr_pages);
577467c996cSMel Gorman 	seq_putc(m, '\n');
578467c996cSMel Gorman 	pagetypeinfo_showfree(m, pgdat);
579467c996cSMel Gorman 	pagetypeinfo_showblockcount(m, pgdat);
580467c996cSMel Gorman 
581f6ac2354SChristoph Lameter 	return 0;
582f6ac2354SChristoph Lameter }
583f6ac2354SChristoph Lameter 
584*8f32f7e5SAlexey Dobriyan static const struct seq_operations fragmentation_op = {
585f6ac2354SChristoph Lameter 	.start	= frag_start,
586f6ac2354SChristoph Lameter 	.next	= frag_next,
587f6ac2354SChristoph Lameter 	.stop	= frag_stop,
588f6ac2354SChristoph Lameter 	.show	= frag_show,
589f6ac2354SChristoph Lameter };
590f6ac2354SChristoph Lameter 
591*8f32f7e5SAlexey Dobriyan static int fragmentation_open(struct inode *inode, struct file *file)
592*8f32f7e5SAlexey Dobriyan {
593*8f32f7e5SAlexey Dobriyan 	return seq_open(file, &fragmentation_op);
594*8f32f7e5SAlexey Dobriyan }
595*8f32f7e5SAlexey Dobriyan 
596*8f32f7e5SAlexey Dobriyan static const struct file_operations fragmentation_file_operations = {
597*8f32f7e5SAlexey Dobriyan 	.open		= fragmentation_open,
598*8f32f7e5SAlexey Dobriyan 	.read		= seq_read,
599*8f32f7e5SAlexey Dobriyan 	.llseek		= seq_lseek,
600*8f32f7e5SAlexey Dobriyan 	.release	= seq_release,
601*8f32f7e5SAlexey Dobriyan };
602*8f32f7e5SAlexey Dobriyan 
603467c996cSMel Gorman const struct seq_operations pagetypeinfo_op = {
604467c996cSMel Gorman 	.start	= frag_start,
605467c996cSMel Gorman 	.next	= frag_next,
606467c996cSMel Gorman 	.stop	= frag_stop,
607467c996cSMel Gorman 	.show	= pagetypeinfo_show,
608467c996cSMel Gorman };
609467c996cSMel Gorman 
6104b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA
6114b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma",
6124b51d669SChristoph Lameter #else
6134b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx)
6144b51d669SChristoph Lameter #endif
6154b51d669SChristoph Lameter 
61627bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32
61727bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32",
61827bf71c2SChristoph Lameter #else
61927bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx)
62027bf71c2SChristoph Lameter #endif
62127bf71c2SChristoph Lameter 
62227bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM
62327bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high",
62427bf71c2SChristoph Lameter #else
62527bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx)
62627bf71c2SChristoph Lameter #endif
62727bf71c2SChristoph Lameter 
6284b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
6292a1e274aSMel Gorman 					TEXT_FOR_HIGHMEM(xx) xx "_movable",
63027bf71c2SChristoph Lameter 
63115ad7cdcSHelge Deller static const char * const vmstat_text[] = {
6322244b95aSChristoph Lameter 	/* Zoned VM counters */
633d23ad423SChristoph Lameter 	"nr_free_pages",
6344f98a2feSRik van Riel 	"nr_inactive_anon",
6354f98a2feSRik van Riel 	"nr_active_anon",
6364f98a2feSRik van Riel 	"nr_inactive_file",
6374f98a2feSRik van Riel 	"nr_active_file",
6387b854121SLee Schermerhorn #ifdef CONFIG_UNEVICTABLE_LRU
6397b854121SLee Schermerhorn 	"nr_unevictable",
6405344b7e6SNick Piggin 	"nr_mlock",
6417b854121SLee Schermerhorn #endif
642f3dbd344SChristoph Lameter 	"nr_anon_pages",
64365ba55f5SChristoph Lameter 	"nr_mapped",
644347ce434SChristoph Lameter 	"nr_file_pages",
64551ed4491SChristoph Lameter 	"nr_dirty",
64651ed4491SChristoph Lameter 	"nr_writeback",
647972d1a7bSChristoph Lameter 	"nr_slab_reclaimable",
648972d1a7bSChristoph Lameter 	"nr_slab_unreclaimable",
649df849a15SChristoph Lameter 	"nr_page_table_pages",
650f6ac2354SChristoph Lameter 	"nr_unstable",
651d2c5e30cSChristoph Lameter 	"nr_bounce",
652e129b5c2SAndrew Morton 	"nr_vmscan_write",
653fc3ba692SMiklos Szeredi 	"nr_writeback_temp",
654f6ac2354SChristoph Lameter 
655ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
656ca889e6cSChristoph Lameter 	"numa_hit",
657ca889e6cSChristoph Lameter 	"numa_miss",
658ca889e6cSChristoph Lameter 	"numa_foreign",
659ca889e6cSChristoph Lameter 	"numa_interleave",
660ca889e6cSChristoph Lameter 	"numa_local",
661ca889e6cSChristoph Lameter 	"numa_other",
662ca889e6cSChristoph Lameter #endif
663ca889e6cSChristoph Lameter 
664f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
665f6ac2354SChristoph Lameter 	"pgpgin",
666f6ac2354SChristoph Lameter 	"pgpgout",
667f6ac2354SChristoph Lameter 	"pswpin",
668f6ac2354SChristoph Lameter 	"pswpout",
669f6ac2354SChristoph Lameter 
67027bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgalloc")
671f6ac2354SChristoph Lameter 
672f6ac2354SChristoph Lameter 	"pgfree",
673f6ac2354SChristoph Lameter 	"pgactivate",
674f6ac2354SChristoph Lameter 	"pgdeactivate",
675f6ac2354SChristoph Lameter 
676f6ac2354SChristoph Lameter 	"pgfault",
677f6ac2354SChristoph Lameter 	"pgmajfault",
678f6ac2354SChristoph Lameter 
67927bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgrefill")
68027bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgsteal")
68127bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_kswapd")
68227bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_direct")
683f6ac2354SChristoph Lameter 
684f6ac2354SChristoph Lameter 	"pginodesteal",
685f6ac2354SChristoph Lameter 	"slabs_scanned",
686f6ac2354SChristoph Lameter 	"kswapd_steal",
687f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
688f6ac2354SChristoph Lameter 	"pageoutrun",
689f6ac2354SChristoph Lameter 	"allocstall",
690f6ac2354SChristoph Lameter 
691f6ac2354SChristoph Lameter 	"pgrotated",
6923b116300SAdam Litke #ifdef CONFIG_HUGETLB_PAGE
6933b116300SAdam Litke 	"htlb_buddy_alloc_success",
6943b116300SAdam Litke 	"htlb_buddy_alloc_fail",
6953b116300SAdam Litke #endif
696bbfd28eeSLee Schermerhorn #ifdef CONFIG_UNEVICTABLE_LRU
697bbfd28eeSLee Schermerhorn 	"unevictable_pgs_culled",
698bbfd28eeSLee Schermerhorn 	"unevictable_pgs_scanned",
699bbfd28eeSLee Schermerhorn 	"unevictable_pgs_rescued",
7005344b7e6SNick Piggin 	"unevictable_pgs_mlocked",
7015344b7e6SNick Piggin 	"unevictable_pgs_munlocked",
7025344b7e6SNick Piggin 	"unevictable_pgs_cleared",
7035344b7e6SNick Piggin 	"unevictable_pgs_stranded",
704985737cfSLee Schermerhorn 	"unevictable_pgs_mlockfreed",
705bbfd28eeSLee Schermerhorn #endif
706f8891e5eSChristoph Lameter #endif
707f6ac2354SChristoph Lameter };
708f6ac2354SChristoph Lameter 
709467c996cSMel Gorman static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
710467c996cSMel Gorman 							struct zone *zone)
711f6ac2354SChristoph Lameter {
712f6ac2354SChristoph Lameter 	int i;
713f6ac2354SChristoph Lameter 	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
714f6ac2354SChristoph Lameter 	seq_printf(m,
715f6ac2354SChristoph Lameter 		   "\n  pages free     %lu"
716f6ac2354SChristoph Lameter 		   "\n        min      %lu"
717f6ac2354SChristoph Lameter 		   "\n        low      %lu"
718f6ac2354SChristoph Lameter 		   "\n        high     %lu"
7194f98a2feSRik van Riel 		   "\n        scanned  %lu (aa: %lu ia: %lu af: %lu if: %lu)"
720f6ac2354SChristoph Lameter 		   "\n        spanned  %lu"
721f6ac2354SChristoph Lameter 		   "\n        present  %lu",
722d23ad423SChristoph Lameter 		   zone_page_state(zone, NR_FREE_PAGES),
723f6ac2354SChristoph Lameter 		   zone->pages_min,
724f6ac2354SChristoph Lameter 		   zone->pages_low,
725f6ac2354SChristoph Lameter 		   zone->pages_high,
726f6ac2354SChristoph Lameter 		   zone->pages_scanned,
7274f98a2feSRik van Riel 		   zone->lru[LRU_ACTIVE_ANON].nr_scan,
7284f98a2feSRik van Riel 		   zone->lru[LRU_INACTIVE_ANON].nr_scan,
7294f98a2feSRik van Riel 		   zone->lru[LRU_ACTIVE_FILE].nr_scan,
7304f98a2feSRik van Riel 		   zone->lru[LRU_INACTIVE_FILE].nr_scan,
731f6ac2354SChristoph Lameter 		   zone->spanned_pages,
732f6ac2354SChristoph Lameter 		   zone->present_pages);
7332244b95aSChristoph Lameter 
7342244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
7352244b95aSChristoph Lameter 		seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
7362244b95aSChristoph Lameter 				zone_page_state(zone, i));
7372244b95aSChristoph Lameter 
738f6ac2354SChristoph Lameter 	seq_printf(m,
739f6ac2354SChristoph Lameter 		   "\n        protection: (%lu",
740f6ac2354SChristoph Lameter 		   zone->lowmem_reserve[0]);
741f6ac2354SChristoph Lameter 	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
742f6ac2354SChristoph Lameter 		seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
743f6ac2354SChristoph Lameter 	seq_printf(m,
744f6ac2354SChristoph Lameter 		   ")"
745f6ac2354SChristoph Lameter 		   "\n  pagesets");
746f6ac2354SChristoph Lameter 	for_each_online_cpu(i) {
747f6ac2354SChristoph Lameter 		struct per_cpu_pageset *pageset;
748f6ac2354SChristoph Lameter 
749f6ac2354SChristoph Lameter 		pageset = zone_pcp(zone, i);
750f6ac2354SChristoph Lameter 		seq_printf(m,
7513dfa5721SChristoph Lameter 			   "\n    cpu: %i"
752f6ac2354SChristoph Lameter 			   "\n              count: %i"
753f6ac2354SChristoph Lameter 			   "\n              high:  %i"
754f6ac2354SChristoph Lameter 			   "\n              batch: %i",
7553dfa5721SChristoph Lameter 			   i,
7563dfa5721SChristoph Lameter 			   pageset->pcp.count,
7573dfa5721SChristoph Lameter 			   pageset->pcp.high,
7583dfa5721SChristoph Lameter 			   pageset->pcp.batch);
759df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
760df9ecabaSChristoph Lameter 		seq_printf(m, "\n  vm stats threshold: %d",
761df9ecabaSChristoph Lameter 				pageset->stat_threshold);
762df9ecabaSChristoph Lameter #endif
763f6ac2354SChristoph Lameter 	}
764f6ac2354SChristoph Lameter 	seq_printf(m,
765f6ac2354SChristoph Lameter 		   "\n  all_unreclaimable: %u"
766f6ac2354SChristoph Lameter 		   "\n  prev_priority:     %i"
767556adecbSRik van Riel 		   "\n  start_pfn:         %lu"
768556adecbSRik van Riel 		   "\n  inactive_ratio:    %u",
769e815af95SDavid Rientjes 			   zone_is_all_unreclaimable(zone),
770f6ac2354SChristoph Lameter 		   zone->prev_priority,
771556adecbSRik van Riel 		   zone->zone_start_pfn,
772556adecbSRik van Riel 		   zone->inactive_ratio);
773f6ac2354SChristoph Lameter 	seq_putc(m, '\n');
774f6ac2354SChristoph Lameter }
775467c996cSMel Gorman 
776467c996cSMel Gorman /*
777467c996cSMel Gorman  * Output information about zones in @pgdat.
778467c996cSMel Gorman  */
779467c996cSMel Gorman static int zoneinfo_show(struct seq_file *m, void *arg)
780467c996cSMel Gorman {
781467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
782467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, zoneinfo_show_print);
783f6ac2354SChristoph Lameter 	return 0;
784f6ac2354SChristoph Lameter }
785f6ac2354SChristoph Lameter 
78615ad7cdcSHelge Deller const struct seq_operations zoneinfo_op = {
787f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
788f6ac2354SChristoph Lameter 			       * fragmentation. */
789f6ac2354SChristoph Lameter 	.next	= frag_next,
790f6ac2354SChristoph Lameter 	.stop	= frag_stop,
791f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
792f6ac2354SChristoph Lameter };
793f6ac2354SChristoph Lameter 
794f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
795f6ac2354SChristoph Lameter {
7962244b95aSChristoph Lameter 	unsigned long *v;
797f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
798f8891e5eSChristoph Lameter 	unsigned long *e;
799f8891e5eSChristoph Lameter #endif
8002244b95aSChristoph Lameter 	int i;
801f6ac2354SChristoph Lameter 
802f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
803f6ac2354SChristoph Lameter 		return NULL;
804f6ac2354SChristoph Lameter 
805f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
8062244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
807f8891e5eSChristoph Lameter 			+ sizeof(struct vm_event_state), GFP_KERNEL);
808f8891e5eSChristoph Lameter #else
809f8891e5eSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
810f8891e5eSChristoph Lameter 			GFP_KERNEL);
811f8891e5eSChristoph Lameter #endif
8122244b95aSChristoph Lameter 	m->private = v;
8132244b95aSChristoph Lameter 	if (!v)
814f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
8152244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
8162244b95aSChristoph Lameter 		v[i] = global_page_state(i);
817f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
818f8891e5eSChristoph Lameter 	e = v + NR_VM_ZONE_STAT_ITEMS;
819f8891e5eSChristoph Lameter 	all_vm_events(e);
820f8891e5eSChristoph Lameter 	e[PGPGIN] /= 2;		/* sectors -> kbytes */
821f8891e5eSChristoph Lameter 	e[PGPGOUT] /= 2;
822f8891e5eSChristoph Lameter #endif
8232244b95aSChristoph Lameter 	return v + *pos;
824f6ac2354SChristoph Lameter }
825f6ac2354SChristoph Lameter 
826f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
827f6ac2354SChristoph Lameter {
828f6ac2354SChristoph Lameter 	(*pos)++;
829f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
830f6ac2354SChristoph Lameter 		return NULL;
831f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
832f6ac2354SChristoph Lameter }
833f6ac2354SChristoph Lameter 
834f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
835f6ac2354SChristoph Lameter {
836f6ac2354SChristoph Lameter 	unsigned long *l = arg;
837f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
838f6ac2354SChristoph Lameter 
839f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
840f6ac2354SChristoph Lameter 	return 0;
841f6ac2354SChristoph Lameter }
842f6ac2354SChristoph Lameter 
843f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
844f6ac2354SChristoph Lameter {
845f6ac2354SChristoph Lameter 	kfree(m->private);
846f6ac2354SChristoph Lameter 	m->private = NULL;
847f6ac2354SChristoph Lameter }
848f6ac2354SChristoph Lameter 
84915ad7cdcSHelge Deller const struct seq_operations vmstat_op = {
850f6ac2354SChristoph Lameter 	.start	= vmstat_start,
851f6ac2354SChristoph Lameter 	.next	= vmstat_next,
852f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
853f6ac2354SChristoph Lameter 	.show	= vmstat_show,
854f6ac2354SChristoph Lameter };
855f6ac2354SChristoph Lameter 
856f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
857f6ac2354SChristoph Lameter 
858df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
859d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
86077461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
861d1187ed2SChristoph Lameter 
862d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
863d1187ed2SChristoph Lameter {
864d1187ed2SChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
86577461ab3SChristoph Lameter 	schedule_delayed_work(&__get_cpu_var(vmstat_work),
86677461ab3SChristoph Lameter 		sysctl_stat_interval);
867d1187ed2SChristoph Lameter }
868d1187ed2SChristoph Lameter 
86942614fcdSRandy Dunlap static void __cpuinit start_cpu_timer(int cpu)
870d1187ed2SChristoph Lameter {
871d1187ed2SChristoph Lameter 	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
872d1187ed2SChristoph Lameter 
87339bf6270SChristoph Lameter 	INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
874d1187ed2SChristoph Lameter 	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
875d1187ed2SChristoph Lameter }
876d1187ed2SChristoph Lameter 
877df9ecabaSChristoph Lameter /*
878df9ecabaSChristoph Lameter  * Use the cpu notifier to insure that the thresholds are recalculated
879df9ecabaSChristoph Lameter  * when necessary.
880df9ecabaSChristoph Lameter  */
881df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
882df9ecabaSChristoph Lameter 		unsigned long action,
883df9ecabaSChristoph Lameter 		void *hcpu)
884df9ecabaSChristoph Lameter {
885d1187ed2SChristoph Lameter 	long cpu = (long)hcpu;
886d1187ed2SChristoph Lameter 
887df9ecabaSChristoph Lameter 	switch (action) {
888d1187ed2SChristoph Lameter 	case CPU_ONLINE:
889d1187ed2SChristoph Lameter 	case CPU_ONLINE_FROZEN:
890d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
891d1187ed2SChristoph Lameter 		break;
892d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE:
893d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE_FROZEN:
894d1187ed2SChristoph Lameter 		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
895d1187ed2SChristoph Lameter 		per_cpu(vmstat_work, cpu).work.func = NULL;
896d1187ed2SChristoph Lameter 		break;
897d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED:
898d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED_FROZEN:
899d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
900d1187ed2SChristoph Lameter 		break;
901df9ecabaSChristoph Lameter 	case CPU_DEAD:
9028bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
903df9ecabaSChristoph Lameter 		refresh_zone_stat_thresholds();
904df9ecabaSChristoph Lameter 		break;
905df9ecabaSChristoph Lameter 	default:
906df9ecabaSChristoph Lameter 		break;
907df9ecabaSChristoph Lameter 	}
908df9ecabaSChristoph Lameter 	return NOTIFY_OK;
909df9ecabaSChristoph Lameter }
910df9ecabaSChristoph Lameter 
911df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier =
912df9ecabaSChristoph Lameter 	{ &vmstat_cpuup_callback, NULL, 0 };
913*8f32f7e5SAlexey Dobriyan #endif
914df9ecabaSChristoph Lameter 
915e2fc88d0SAdrian Bunk static int __init setup_vmstat(void)
916df9ecabaSChristoph Lameter {
917*8f32f7e5SAlexey Dobriyan #ifdef CONFIG_SMP
918d1187ed2SChristoph Lameter 	int cpu;
919d1187ed2SChristoph Lameter 
920df9ecabaSChristoph Lameter 	refresh_zone_stat_thresholds();
921df9ecabaSChristoph Lameter 	register_cpu_notifier(&vmstat_notifier);
922d1187ed2SChristoph Lameter 
923d1187ed2SChristoph Lameter 	for_each_online_cpu(cpu)
924d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
925*8f32f7e5SAlexey Dobriyan #endif
926*8f32f7e5SAlexey Dobriyan #ifdef CONFIG_PROC_FS
927*8f32f7e5SAlexey Dobriyan 	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
928*8f32f7e5SAlexey Dobriyan #endif
929df9ecabaSChristoph Lameter 	return 0;
930df9ecabaSChristoph Lameter }
931df9ecabaSChristoph Lameter module_init(setup_vmstat)
932