xref: /linux/mm/vmstat.c (revision b6aa44ab698c7df9d951d3eb45c4fcb8ba68fb25)
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  */
118f32f7e5SAlexey 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
3878f32f7e5SAlexey 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 
5848f32f7e5SAlexey 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 
5918f32f7e5SAlexey Dobriyan static int fragmentation_open(struct inode *inode, struct file *file)
5928f32f7e5SAlexey Dobriyan {
5938f32f7e5SAlexey Dobriyan 	return seq_open(file, &fragmentation_op);
5948f32f7e5SAlexey Dobriyan }
5958f32f7e5SAlexey Dobriyan 
5968f32f7e5SAlexey Dobriyan static const struct file_operations fragmentation_file_operations = {
5978f32f7e5SAlexey Dobriyan 	.open		= fragmentation_open,
5988f32f7e5SAlexey Dobriyan 	.read		= seq_read,
5998f32f7e5SAlexey Dobriyan 	.llseek		= seq_lseek,
6008f32f7e5SAlexey Dobriyan 	.release	= seq_release,
6018f32f7e5SAlexey Dobriyan };
6028f32f7e5SAlexey Dobriyan 
60374e2e8e8SAlexey Dobriyan static 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 
61074e2e8e8SAlexey Dobriyan static int pagetypeinfo_open(struct inode *inode, struct file *file)
61174e2e8e8SAlexey Dobriyan {
61274e2e8e8SAlexey Dobriyan 	return seq_open(file, &pagetypeinfo_op);
61374e2e8e8SAlexey Dobriyan }
61474e2e8e8SAlexey Dobriyan 
61574e2e8e8SAlexey Dobriyan static const struct file_operations pagetypeinfo_file_ops = {
61674e2e8e8SAlexey Dobriyan 	.open		= pagetypeinfo_open,
61774e2e8e8SAlexey Dobriyan 	.read		= seq_read,
61874e2e8e8SAlexey Dobriyan 	.llseek		= seq_lseek,
61974e2e8e8SAlexey Dobriyan 	.release	= seq_release,
62074e2e8e8SAlexey Dobriyan };
62174e2e8e8SAlexey Dobriyan 
6224b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA
6234b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma",
6244b51d669SChristoph Lameter #else
6254b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx)
6264b51d669SChristoph Lameter #endif
6274b51d669SChristoph Lameter 
62827bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32
62927bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32",
63027bf71c2SChristoph Lameter #else
63127bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx)
63227bf71c2SChristoph Lameter #endif
63327bf71c2SChristoph Lameter 
63427bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM
63527bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high",
63627bf71c2SChristoph Lameter #else
63727bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx)
63827bf71c2SChristoph Lameter #endif
63927bf71c2SChristoph Lameter 
6404b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
6412a1e274aSMel Gorman 					TEXT_FOR_HIGHMEM(xx) xx "_movable",
64227bf71c2SChristoph Lameter 
64315ad7cdcSHelge Deller static const char * const vmstat_text[] = {
6442244b95aSChristoph Lameter 	/* Zoned VM counters */
645d23ad423SChristoph Lameter 	"nr_free_pages",
6464f98a2feSRik van Riel 	"nr_inactive_anon",
6474f98a2feSRik van Riel 	"nr_active_anon",
6484f98a2feSRik van Riel 	"nr_inactive_file",
6494f98a2feSRik van Riel 	"nr_active_file",
6507b854121SLee Schermerhorn #ifdef CONFIG_UNEVICTABLE_LRU
6517b854121SLee Schermerhorn 	"nr_unevictable",
6525344b7e6SNick Piggin 	"nr_mlock",
6537b854121SLee Schermerhorn #endif
654f3dbd344SChristoph Lameter 	"nr_anon_pages",
65565ba55f5SChristoph Lameter 	"nr_mapped",
656347ce434SChristoph Lameter 	"nr_file_pages",
65751ed4491SChristoph Lameter 	"nr_dirty",
65851ed4491SChristoph Lameter 	"nr_writeback",
659972d1a7bSChristoph Lameter 	"nr_slab_reclaimable",
660972d1a7bSChristoph Lameter 	"nr_slab_unreclaimable",
661df849a15SChristoph Lameter 	"nr_page_table_pages",
662f6ac2354SChristoph Lameter 	"nr_unstable",
663d2c5e30cSChristoph Lameter 	"nr_bounce",
664e129b5c2SAndrew Morton 	"nr_vmscan_write",
665fc3ba692SMiklos Szeredi 	"nr_writeback_temp",
666f6ac2354SChristoph Lameter 
667ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
668ca889e6cSChristoph Lameter 	"numa_hit",
669ca889e6cSChristoph Lameter 	"numa_miss",
670ca889e6cSChristoph Lameter 	"numa_foreign",
671ca889e6cSChristoph Lameter 	"numa_interleave",
672ca889e6cSChristoph Lameter 	"numa_local",
673ca889e6cSChristoph Lameter 	"numa_other",
674ca889e6cSChristoph Lameter #endif
675ca889e6cSChristoph Lameter 
676f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
677f6ac2354SChristoph Lameter 	"pgpgin",
678f6ac2354SChristoph Lameter 	"pgpgout",
679f6ac2354SChristoph Lameter 	"pswpin",
680f6ac2354SChristoph Lameter 	"pswpout",
681f6ac2354SChristoph Lameter 
68227bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgalloc")
683f6ac2354SChristoph Lameter 
684f6ac2354SChristoph Lameter 	"pgfree",
685f6ac2354SChristoph Lameter 	"pgactivate",
686f6ac2354SChristoph Lameter 	"pgdeactivate",
687f6ac2354SChristoph Lameter 
688f6ac2354SChristoph Lameter 	"pgfault",
689f6ac2354SChristoph Lameter 	"pgmajfault",
690f6ac2354SChristoph Lameter 
69127bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgrefill")
69227bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgsteal")
69327bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_kswapd")
69427bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_direct")
695f6ac2354SChristoph Lameter 
696f6ac2354SChristoph Lameter 	"pginodesteal",
697f6ac2354SChristoph Lameter 	"slabs_scanned",
698f6ac2354SChristoph Lameter 	"kswapd_steal",
699f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
700f6ac2354SChristoph Lameter 	"pageoutrun",
701f6ac2354SChristoph Lameter 	"allocstall",
702f6ac2354SChristoph Lameter 
703f6ac2354SChristoph Lameter 	"pgrotated",
7043b116300SAdam Litke #ifdef CONFIG_HUGETLB_PAGE
7053b116300SAdam Litke 	"htlb_buddy_alloc_success",
7063b116300SAdam Litke 	"htlb_buddy_alloc_fail",
7073b116300SAdam Litke #endif
708bbfd28eeSLee Schermerhorn #ifdef CONFIG_UNEVICTABLE_LRU
709bbfd28eeSLee Schermerhorn 	"unevictable_pgs_culled",
710bbfd28eeSLee Schermerhorn 	"unevictable_pgs_scanned",
711bbfd28eeSLee Schermerhorn 	"unevictable_pgs_rescued",
7125344b7e6SNick Piggin 	"unevictable_pgs_mlocked",
7135344b7e6SNick Piggin 	"unevictable_pgs_munlocked",
7145344b7e6SNick Piggin 	"unevictable_pgs_cleared",
7155344b7e6SNick Piggin 	"unevictable_pgs_stranded",
716985737cfSLee Schermerhorn 	"unevictable_pgs_mlockfreed",
717bbfd28eeSLee Schermerhorn #endif
718f8891e5eSChristoph Lameter #endif
719f6ac2354SChristoph Lameter };
720f6ac2354SChristoph Lameter 
721467c996cSMel Gorman static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
722467c996cSMel Gorman 							struct zone *zone)
723f6ac2354SChristoph Lameter {
724f6ac2354SChristoph Lameter 	int i;
725f6ac2354SChristoph Lameter 	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
726f6ac2354SChristoph Lameter 	seq_printf(m,
727f6ac2354SChristoph Lameter 		   "\n  pages free     %lu"
728f6ac2354SChristoph Lameter 		   "\n        min      %lu"
729f6ac2354SChristoph Lameter 		   "\n        low      %lu"
730f6ac2354SChristoph Lameter 		   "\n        high     %lu"
7314f98a2feSRik van Riel 		   "\n        scanned  %lu (aa: %lu ia: %lu af: %lu if: %lu)"
732f6ac2354SChristoph Lameter 		   "\n        spanned  %lu"
733f6ac2354SChristoph Lameter 		   "\n        present  %lu",
734d23ad423SChristoph Lameter 		   zone_page_state(zone, NR_FREE_PAGES),
735f6ac2354SChristoph Lameter 		   zone->pages_min,
736f6ac2354SChristoph Lameter 		   zone->pages_low,
737f6ac2354SChristoph Lameter 		   zone->pages_high,
738f6ac2354SChristoph Lameter 		   zone->pages_scanned,
7394f98a2feSRik van Riel 		   zone->lru[LRU_ACTIVE_ANON].nr_scan,
7404f98a2feSRik van Riel 		   zone->lru[LRU_INACTIVE_ANON].nr_scan,
7414f98a2feSRik van Riel 		   zone->lru[LRU_ACTIVE_FILE].nr_scan,
7424f98a2feSRik van Riel 		   zone->lru[LRU_INACTIVE_FILE].nr_scan,
743f6ac2354SChristoph Lameter 		   zone->spanned_pages,
744f6ac2354SChristoph Lameter 		   zone->present_pages);
7452244b95aSChristoph Lameter 
7462244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
7472244b95aSChristoph Lameter 		seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
7482244b95aSChristoph Lameter 				zone_page_state(zone, i));
7492244b95aSChristoph Lameter 
750f6ac2354SChristoph Lameter 	seq_printf(m,
751f6ac2354SChristoph Lameter 		   "\n        protection: (%lu",
752f6ac2354SChristoph Lameter 		   zone->lowmem_reserve[0]);
753f6ac2354SChristoph Lameter 	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
754f6ac2354SChristoph Lameter 		seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
755f6ac2354SChristoph Lameter 	seq_printf(m,
756f6ac2354SChristoph Lameter 		   ")"
757f6ac2354SChristoph Lameter 		   "\n  pagesets");
758f6ac2354SChristoph Lameter 	for_each_online_cpu(i) {
759f6ac2354SChristoph Lameter 		struct per_cpu_pageset *pageset;
760f6ac2354SChristoph Lameter 
761f6ac2354SChristoph Lameter 		pageset = zone_pcp(zone, i);
762f6ac2354SChristoph Lameter 		seq_printf(m,
7633dfa5721SChristoph Lameter 			   "\n    cpu: %i"
764f6ac2354SChristoph Lameter 			   "\n              count: %i"
765f6ac2354SChristoph Lameter 			   "\n              high:  %i"
766f6ac2354SChristoph Lameter 			   "\n              batch: %i",
7673dfa5721SChristoph Lameter 			   i,
7683dfa5721SChristoph Lameter 			   pageset->pcp.count,
7693dfa5721SChristoph Lameter 			   pageset->pcp.high,
7703dfa5721SChristoph Lameter 			   pageset->pcp.batch);
771df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
772df9ecabaSChristoph Lameter 		seq_printf(m, "\n  vm stats threshold: %d",
773df9ecabaSChristoph Lameter 				pageset->stat_threshold);
774df9ecabaSChristoph Lameter #endif
775f6ac2354SChristoph Lameter 	}
776f6ac2354SChristoph Lameter 	seq_printf(m,
777f6ac2354SChristoph Lameter 		   "\n  all_unreclaimable: %u"
778f6ac2354SChristoph Lameter 		   "\n  prev_priority:     %i"
779556adecbSRik van Riel 		   "\n  start_pfn:         %lu"
780556adecbSRik van Riel 		   "\n  inactive_ratio:    %u",
781e815af95SDavid Rientjes 			   zone_is_all_unreclaimable(zone),
782f6ac2354SChristoph Lameter 		   zone->prev_priority,
783556adecbSRik van Riel 		   zone->zone_start_pfn,
784556adecbSRik van Riel 		   zone->inactive_ratio);
785f6ac2354SChristoph Lameter 	seq_putc(m, '\n');
786f6ac2354SChristoph Lameter }
787467c996cSMel Gorman 
788467c996cSMel Gorman /*
789467c996cSMel Gorman  * Output information about zones in @pgdat.
790467c996cSMel Gorman  */
791467c996cSMel Gorman static int zoneinfo_show(struct seq_file *m, void *arg)
792467c996cSMel Gorman {
793467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
794467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, zoneinfo_show_print);
795f6ac2354SChristoph Lameter 	return 0;
796f6ac2354SChristoph Lameter }
797f6ac2354SChristoph Lameter 
79815ad7cdcSHelge Deller const struct seq_operations zoneinfo_op = {
799f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
800f6ac2354SChristoph Lameter 			       * fragmentation. */
801f6ac2354SChristoph Lameter 	.next	= frag_next,
802f6ac2354SChristoph Lameter 	.stop	= frag_stop,
803f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
804f6ac2354SChristoph Lameter };
805f6ac2354SChristoph Lameter 
806f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
807f6ac2354SChristoph Lameter {
8082244b95aSChristoph Lameter 	unsigned long *v;
809f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
810f8891e5eSChristoph Lameter 	unsigned long *e;
811f8891e5eSChristoph Lameter #endif
8122244b95aSChristoph Lameter 	int i;
813f6ac2354SChristoph Lameter 
814f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
815f6ac2354SChristoph Lameter 		return NULL;
816f6ac2354SChristoph Lameter 
817f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
8182244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
819f8891e5eSChristoph Lameter 			+ sizeof(struct vm_event_state), GFP_KERNEL);
820f8891e5eSChristoph Lameter #else
821f8891e5eSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
822f8891e5eSChristoph Lameter 			GFP_KERNEL);
823f8891e5eSChristoph Lameter #endif
8242244b95aSChristoph Lameter 	m->private = v;
8252244b95aSChristoph Lameter 	if (!v)
826f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
8272244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
8282244b95aSChristoph Lameter 		v[i] = global_page_state(i);
829f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
830f8891e5eSChristoph Lameter 	e = v + NR_VM_ZONE_STAT_ITEMS;
831f8891e5eSChristoph Lameter 	all_vm_events(e);
832f8891e5eSChristoph Lameter 	e[PGPGIN] /= 2;		/* sectors -> kbytes */
833f8891e5eSChristoph Lameter 	e[PGPGOUT] /= 2;
834f8891e5eSChristoph Lameter #endif
8352244b95aSChristoph Lameter 	return v + *pos;
836f6ac2354SChristoph Lameter }
837f6ac2354SChristoph Lameter 
838f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
839f6ac2354SChristoph Lameter {
840f6ac2354SChristoph Lameter 	(*pos)++;
841f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
842f6ac2354SChristoph Lameter 		return NULL;
843f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
844f6ac2354SChristoph Lameter }
845f6ac2354SChristoph Lameter 
846f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
847f6ac2354SChristoph Lameter {
848f6ac2354SChristoph Lameter 	unsigned long *l = arg;
849f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
850f6ac2354SChristoph Lameter 
851f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
852f6ac2354SChristoph Lameter 	return 0;
853f6ac2354SChristoph Lameter }
854f6ac2354SChristoph Lameter 
855f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
856f6ac2354SChristoph Lameter {
857f6ac2354SChristoph Lameter 	kfree(m->private);
858f6ac2354SChristoph Lameter 	m->private = NULL;
859f6ac2354SChristoph Lameter }
860f6ac2354SChristoph Lameter 
861*b6aa44abSAlexey Dobriyan static const struct seq_operations vmstat_op = {
862f6ac2354SChristoph Lameter 	.start	= vmstat_start,
863f6ac2354SChristoph Lameter 	.next	= vmstat_next,
864f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
865f6ac2354SChristoph Lameter 	.show	= vmstat_show,
866f6ac2354SChristoph Lameter };
867f6ac2354SChristoph Lameter 
868*b6aa44abSAlexey Dobriyan static int vmstat_open(struct inode *inode, struct file *file)
869*b6aa44abSAlexey Dobriyan {
870*b6aa44abSAlexey Dobriyan 	return seq_open(file, &vmstat_op);
871*b6aa44abSAlexey Dobriyan }
872*b6aa44abSAlexey Dobriyan 
873*b6aa44abSAlexey Dobriyan static const struct file_operations proc_vmstat_file_operations = {
874*b6aa44abSAlexey Dobriyan 	.open		= vmstat_open,
875*b6aa44abSAlexey Dobriyan 	.read		= seq_read,
876*b6aa44abSAlexey Dobriyan 	.llseek		= seq_lseek,
877*b6aa44abSAlexey Dobriyan 	.release	= seq_release,
878*b6aa44abSAlexey Dobriyan };
879f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
880f6ac2354SChristoph Lameter 
881df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
882d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
88377461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
884d1187ed2SChristoph Lameter 
885d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
886d1187ed2SChristoph Lameter {
887d1187ed2SChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
88877461ab3SChristoph Lameter 	schedule_delayed_work(&__get_cpu_var(vmstat_work),
88977461ab3SChristoph Lameter 		sysctl_stat_interval);
890d1187ed2SChristoph Lameter }
891d1187ed2SChristoph Lameter 
89242614fcdSRandy Dunlap static void __cpuinit start_cpu_timer(int cpu)
893d1187ed2SChristoph Lameter {
894d1187ed2SChristoph Lameter 	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
895d1187ed2SChristoph Lameter 
89639bf6270SChristoph Lameter 	INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
897d1187ed2SChristoph Lameter 	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
898d1187ed2SChristoph Lameter }
899d1187ed2SChristoph Lameter 
900df9ecabaSChristoph Lameter /*
901df9ecabaSChristoph Lameter  * Use the cpu notifier to insure that the thresholds are recalculated
902df9ecabaSChristoph Lameter  * when necessary.
903df9ecabaSChristoph Lameter  */
904df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
905df9ecabaSChristoph Lameter 		unsigned long action,
906df9ecabaSChristoph Lameter 		void *hcpu)
907df9ecabaSChristoph Lameter {
908d1187ed2SChristoph Lameter 	long cpu = (long)hcpu;
909d1187ed2SChristoph Lameter 
910df9ecabaSChristoph Lameter 	switch (action) {
911d1187ed2SChristoph Lameter 	case CPU_ONLINE:
912d1187ed2SChristoph Lameter 	case CPU_ONLINE_FROZEN:
913d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
914d1187ed2SChristoph Lameter 		break;
915d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE:
916d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE_FROZEN:
917d1187ed2SChristoph Lameter 		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
918d1187ed2SChristoph Lameter 		per_cpu(vmstat_work, cpu).work.func = NULL;
919d1187ed2SChristoph Lameter 		break;
920d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED:
921d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED_FROZEN:
922d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
923d1187ed2SChristoph Lameter 		break;
924df9ecabaSChristoph Lameter 	case CPU_DEAD:
9258bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
926df9ecabaSChristoph Lameter 		refresh_zone_stat_thresholds();
927df9ecabaSChristoph Lameter 		break;
928df9ecabaSChristoph Lameter 	default:
929df9ecabaSChristoph Lameter 		break;
930df9ecabaSChristoph Lameter 	}
931df9ecabaSChristoph Lameter 	return NOTIFY_OK;
932df9ecabaSChristoph Lameter }
933df9ecabaSChristoph Lameter 
934df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier =
935df9ecabaSChristoph Lameter 	{ &vmstat_cpuup_callback, NULL, 0 };
9368f32f7e5SAlexey Dobriyan #endif
937df9ecabaSChristoph Lameter 
938e2fc88d0SAdrian Bunk static int __init setup_vmstat(void)
939df9ecabaSChristoph Lameter {
9408f32f7e5SAlexey Dobriyan #ifdef CONFIG_SMP
941d1187ed2SChristoph Lameter 	int cpu;
942d1187ed2SChristoph Lameter 
943df9ecabaSChristoph Lameter 	refresh_zone_stat_thresholds();
944df9ecabaSChristoph Lameter 	register_cpu_notifier(&vmstat_notifier);
945d1187ed2SChristoph Lameter 
946d1187ed2SChristoph Lameter 	for_each_online_cpu(cpu)
947d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
9488f32f7e5SAlexey Dobriyan #endif
9498f32f7e5SAlexey Dobriyan #ifdef CONFIG_PROC_FS
9508f32f7e5SAlexey Dobriyan 	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
95174e2e8e8SAlexey Dobriyan 	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
952*b6aa44abSAlexey Dobriyan 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
9538f32f7e5SAlexey Dobriyan #endif
954df9ecabaSChristoph Lameter 	return 0;
955df9ecabaSChristoph Lameter }
956df9ecabaSChristoph Lameter module_init(setup_vmstat)
957