xref: /linux/mm/vmstat.c (revision 77461ab33229d48614402decfb1b2eaa6d446861)
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  */
11f6ac2354SChristoph Lameter 
12f6ac2354SChristoph Lameter #include <linux/mm.h>
132244b95aSChristoph Lameter #include <linux/module.h>
14df9ecabaSChristoph Lameter #include <linux/cpu.h>
15f6ac2354SChristoph Lameter 
16f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
17f8891e5eSChristoph Lameter DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
18f8891e5eSChristoph Lameter EXPORT_PER_CPU_SYMBOL(vm_event_states);
19f8891e5eSChristoph Lameter 
20f8891e5eSChristoph Lameter static void sum_vm_events(unsigned long *ret, cpumask_t *cpumask)
21f8891e5eSChristoph Lameter {
22f8891e5eSChristoph Lameter 	int cpu = 0;
23f8891e5eSChristoph Lameter 	int i;
24f8891e5eSChristoph Lameter 
25f8891e5eSChristoph Lameter 	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
26f8891e5eSChristoph Lameter 
27f8891e5eSChristoph Lameter 	cpu = first_cpu(*cpumask);
28f8891e5eSChristoph Lameter 	while (cpu < NR_CPUS) {
29f8891e5eSChristoph Lameter 		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
30f8891e5eSChristoph Lameter 
31f8891e5eSChristoph Lameter 		cpu = next_cpu(cpu, *cpumask);
32f8891e5eSChristoph Lameter 
33f8891e5eSChristoph Lameter 		if (cpu < NR_CPUS)
34f8891e5eSChristoph Lameter 			prefetch(&per_cpu(vm_event_states, cpu));
35f8891e5eSChristoph Lameter 
36f8891e5eSChristoph Lameter 
37f8891e5eSChristoph Lameter 		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
38f8891e5eSChristoph Lameter 			ret[i] += this->event[i];
39f8891e5eSChristoph Lameter 	}
40f8891e5eSChristoph Lameter }
41f8891e5eSChristoph Lameter 
42f8891e5eSChristoph Lameter /*
43f8891e5eSChristoph Lameter  * Accumulate the vm event counters across all CPUs.
44f8891e5eSChristoph Lameter  * The result is unavoidably approximate - it can change
45f8891e5eSChristoph Lameter  * during and after execution of this function.
46f8891e5eSChristoph Lameter */
47f8891e5eSChristoph Lameter void all_vm_events(unsigned long *ret)
48f8891e5eSChristoph Lameter {
49f8891e5eSChristoph Lameter 	sum_vm_events(ret, &cpu_online_map);
50f8891e5eSChristoph Lameter }
5132dd66fcSHeiko Carstens EXPORT_SYMBOL_GPL(all_vm_events);
52f8891e5eSChristoph Lameter 
53f8891e5eSChristoph Lameter #ifdef CONFIG_HOTPLUG
54f8891e5eSChristoph Lameter /*
55f8891e5eSChristoph Lameter  * Fold the foreign cpu events into our own.
56f8891e5eSChristoph Lameter  *
57f8891e5eSChristoph Lameter  * This is adding to the events on one processor
58f8891e5eSChristoph Lameter  * but keeps the global counts constant.
59f8891e5eSChristoph Lameter  */
60f8891e5eSChristoph Lameter void vm_events_fold_cpu(int cpu)
61f8891e5eSChristoph Lameter {
62f8891e5eSChristoph Lameter 	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
63f8891e5eSChristoph Lameter 	int i;
64f8891e5eSChristoph Lameter 
65f8891e5eSChristoph Lameter 	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
66f8891e5eSChristoph Lameter 		count_vm_events(i, fold_state->event[i]);
67f8891e5eSChristoph Lameter 		fold_state->event[i] = 0;
68f8891e5eSChristoph Lameter 	}
69f8891e5eSChristoph Lameter }
70f8891e5eSChristoph Lameter #endif /* CONFIG_HOTPLUG */
71f8891e5eSChristoph Lameter 
72f8891e5eSChristoph Lameter #endif /* CONFIG_VM_EVENT_COUNTERS */
73f8891e5eSChristoph Lameter 
742244b95aSChristoph Lameter /*
752244b95aSChristoph Lameter  * Manage combined zone based / global counters
762244b95aSChristoph Lameter  *
772244b95aSChristoph Lameter  * vm_stat contains the global counters
782244b95aSChristoph Lameter  */
792244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
802244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat);
812244b95aSChristoph Lameter 
822244b95aSChristoph Lameter #ifdef CONFIG_SMP
832244b95aSChristoph Lameter 
84df9ecabaSChristoph Lameter static int calculate_threshold(struct zone *zone)
85df9ecabaSChristoph Lameter {
86df9ecabaSChristoph Lameter 	int threshold;
87df9ecabaSChristoph Lameter 	int mem;	/* memory in 128 MB units */
882244b95aSChristoph Lameter 
892244b95aSChristoph Lameter 	/*
90df9ecabaSChristoph Lameter 	 * The threshold scales with the number of processors and the amount
91df9ecabaSChristoph Lameter 	 * of memory per zone. More memory means that we can defer updates for
92df9ecabaSChristoph Lameter 	 * longer, more processors could lead to more contention.
93df9ecabaSChristoph Lameter  	 * fls() is used to have a cheap way of logarithmic scaling.
942244b95aSChristoph Lameter 	 *
95df9ecabaSChristoph Lameter 	 * Some sample thresholds:
96df9ecabaSChristoph Lameter 	 *
97df9ecabaSChristoph Lameter 	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
98df9ecabaSChristoph Lameter 	 * ------------------------------------------------------------------
99df9ecabaSChristoph Lameter 	 * 8		1		1	0.9-1 GB	4
100df9ecabaSChristoph Lameter 	 * 16		2		2	0.9-1 GB	4
101df9ecabaSChristoph Lameter 	 * 20 		2		2	1-2 GB		5
102df9ecabaSChristoph Lameter 	 * 24		2		2	2-4 GB		6
103df9ecabaSChristoph Lameter 	 * 28		2		2	4-8 GB		7
104df9ecabaSChristoph Lameter 	 * 32		2		2	8-16 GB		8
105df9ecabaSChristoph Lameter 	 * 4		2		2	<128M		1
106df9ecabaSChristoph Lameter 	 * 30		4		3	2-4 GB		5
107df9ecabaSChristoph Lameter 	 * 48		4		3	8-16 GB		8
108df9ecabaSChristoph Lameter 	 * 32		8		4	1-2 GB		4
109df9ecabaSChristoph Lameter 	 * 32		8		4	0.9-1GB		4
110df9ecabaSChristoph Lameter 	 * 10		16		5	<128M		1
111df9ecabaSChristoph Lameter 	 * 40		16		5	900M		4
112df9ecabaSChristoph Lameter 	 * 70		64		7	2-4 GB		5
113df9ecabaSChristoph Lameter 	 * 84		64		7	4-8 GB		6
114df9ecabaSChristoph Lameter 	 * 108		512		9	4-8 GB		6
115df9ecabaSChristoph Lameter 	 * 125		1024		10	8-16 GB		8
116df9ecabaSChristoph Lameter 	 * 125		1024		10	16-32 GB	9
1172244b95aSChristoph Lameter 	 */
118df9ecabaSChristoph Lameter 
119df9ecabaSChristoph Lameter 	mem = zone->present_pages >> (27 - PAGE_SHIFT);
120df9ecabaSChristoph Lameter 
121df9ecabaSChristoph Lameter 	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
122df9ecabaSChristoph Lameter 
123df9ecabaSChristoph Lameter 	/*
124df9ecabaSChristoph Lameter 	 * Maximum threshold is 125
125df9ecabaSChristoph Lameter 	 */
126df9ecabaSChristoph Lameter 	threshold = min(125, threshold);
127df9ecabaSChristoph Lameter 
128df9ecabaSChristoph Lameter 	return threshold;
129df9ecabaSChristoph Lameter }
130df9ecabaSChristoph Lameter 
131df9ecabaSChristoph Lameter /*
132df9ecabaSChristoph Lameter  * Refresh the thresholds for each zone.
133df9ecabaSChristoph Lameter  */
134df9ecabaSChristoph Lameter static void refresh_zone_stat_thresholds(void)
1352244b95aSChristoph Lameter {
136df9ecabaSChristoph Lameter 	struct zone *zone;
137df9ecabaSChristoph Lameter 	int cpu;
138df9ecabaSChristoph Lameter 	int threshold;
139df9ecabaSChristoph Lameter 
140df9ecabaSChristoph Lameter 	for_each_zone(zone) {
141df9ecabaSChristoph Lameter 
142df9ecabaSChristoph Lameter 		if (!zone->present_pages)
143df9ecabaSChristoph Lameter 			continue;
144df9ecabaSChristoph Lameter 
145df9ecabaSChristoph Lameter 		threshold = calculate_threshold(zone);
146df9ecabaSChristoph Lameter 
147df9ecabaSChristoph Lameter 		for_each_online_cpu(cpu)
148df9ecabaSChristoph Lameter 			zone_pcp(zone, cpu)->stat_threshold = threshold;
149df9ecabaSChristoph Lameter 	}
1502244b95aSChristoph Lameter }
1512244b95aSChristoph Lameter 
1522244b95aSChristoph Lameter /*
1532244b95aSChristoph Lameter  * For use when we know that interrupts are disabled.
1542244b95aSChristoph Lameter  */
1552244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1562244b95aSChristoph Lameter 				int delta)
1572244b95aSChristoph Lameter {
158df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
159df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
1602244b95aSChristoph Lameter 	long x;
1612244b95aSChristoph Lameter 
1622244b95aSChristoph Lameter 	x = delta + *p;
1632244b95aSChristoph Lameter 
164df9ecabaSChristoph Lameter 	if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) {
1652244b95aSChristoph Lameter 		zone_page_state_add(x, zone, item);
1662244b95aSChristoph Lameter 		x = 0;
1672244b95aSChristoph Lameter 	}
1682244b95aSChristoph Lameter 	*p = x;
1692244b95aSChristoph Lameter }
1702244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
1712244b95aSChristoph Lameter 
1722244b95aSChristoph Lameter /*
1732244b95aSChristoph Lameter  * For an unknown interrupt state
1742244b95aSChristoph Lameter  */
1752244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1762244b95aSChristoph Lameter 					int delta)
1772244b95aSChristoph Lameter {
1782244b95aSChristoph Lameter 	unsigned long flags;
1792244b95aSChristoph Lameter 
1802244b95aSChristoph Lameter 	local_irq_save(flags);
1812244b95aSChristoph Lameter 	__mod_zone_page_state(zone, item, delta);
1822244b95aSChristoph Lameter 	local_irq_restore(flags);
1832244b95aSChristoph Lameter }
1842244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
1852244b95aSChristoph Lameter 
1862244b95aSChristoph Lameter /*
1872244b95aSChristoph Lameter  * Optimized increment and decrement functions.
1882244b95aSChristoph Lameter  *
1892244b95aSChristoph Lameter  * These are only for a single page and therefore can take a struct page *
1902244b95aSChristoph Lameter  * argument instead of struct zone *. This allows the inclusion of the code
1912244b95aSChristoph Lameter  * generated for page_zone(page) into the optimized functions.
1922244b95aSChristoph Lameter  *
1932244b95aSChristoph Lameter  * No overflow check is necessary and therefore the differential can be
1942244b95aSChristoph Lameter  * incremented or decremented in place which may allow the compilers to
1952244b95aSChristoph Lameter  * generate better code.
1962244b95aSChristoph Lameter  * The increment or decrement is known and therefore one boundary check can
1972244b95aSChristoph Lameter  * be omitted.
1982244b95aSChristoph Lameter  *
199df9ecabaSChristoph Lameter  * NOTE: These functions are very performance sensitive. Change only
200df9ecabaSChristoph Lameter  * with care.
201df9ecabaSChristoph Lameter  *
2022244b95aSChristoph Lameter  * Some processors have inc/dec instructions that are atomic vs an interrupt.
2032244b95aSChristoph Lameter  * However, the code must first determine the differential location in a zone
2042244b95aSChristoph Lameter  * based on the processor number and then inc/dec the counter. There is no
2052244b95aSChristoph Lameter  * guarantee without disabling preemption that the processor will not change
2062244b95aSChristoph Lameter  * in between and therefore the atomicity vs. interrupt cannot be exploited
2072244b95aSChristoph Lameter  * in a useful way here.
2082244b95aSChristoph Lameter  */
209c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2102244b95aSChristoph Lameter {
211df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
212df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2132244b95aSChristoph Lameter 
2142244b95aSChristoph Lameter 	(*p)++;
2152244b95aSChristoph Lameter 
216df9ecabaSChristoph Lameter 	if (unlikely(*p > pcp->stat_threshold)) {
217df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
218df9ecabaSChristoph Lameter 
219df9ecabaSChristoph Lameter 		zone_page_state_add(*p + overstep, zone, item);
220df9ecabaSChristoph Lameter 		*p = -overstep;
2212244b95aSChristoph Lameter 	}
2222244b95aSChristoph Lameter }
223ca889e6cSChristoph Lameter 
224ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
225ca889e6cSChristoph Lameter {
226ca889e6cSChristoph Lameter 	__inc_zone_state(page_zone(page), item);
227ca889e6cSChristoph Lameter }
2282244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
2292244b95aSChristoph Lameter 
230c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2312244b95aSChristoph Lameter {
232df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
233df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2342244b95aSChristoph Lameter 
2352244b95aSChristoph Lameter 	(*p)--;
2362244b95aSChristoph Lameter 
237df9ecabaSChristoph Lameter 	if (unlikely(*p < - pcp->stat_threshold)) {
238df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
239df9ecabaSChristoph Lameter 
240df9ecabaSChristoph Lameter 		zone_page_state_add(*p - overstep, zone, item);
241df9ecabaSChristoph Lameter 		*p = overstep;
2422244b95aSChristoph Lameter 	}
2432244b95aSChristoph Lameter }
244c8785385SChristoph Lameter 
245c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
246c8785385SChristoph Lameter {
247c8785385SChristoph Lameter 	__dec_zone_state(page_zone(page), item);
248c8785385SChristoph Lameter }
2492244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
2502244b95aSChristoph Lameter 
251ca889e6cSChristoph Lameter void inc_zone_state(struct zone *zone, enum zone_stat_item item)
252ca889e6cSChristoph Lameter {
253ca889e6cSChristoph Lameter 	unsigned long flags;
254ca889e6cSChristoph Lameter 
255ca889e6cSChristoph Lameter 	local_irq_save(flags);
256ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
257ca889e6cSChristoph Lameter 	local_irq_restore(flags);
258ca889e6cSChristoph Lameter }
259ca889e6cSChristoph Lameter 
2602244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
2612244b95aSChristoph Lameter {
2622244b95aSChristoph Lameter 	unsigned long flags;
2632244b95aSChristoph Lameter 	struct zone *zone;
2642244b95aSChristoph Lameter 
2652244b95aSChristoph Lameter 	zone = page_zone(page);
2662244b95aSChristoph Lameter 	local_irq_save(flags);
267ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
2682244b95aSChristoph Lameter 	local_irq_restore(flags);
2692244b95aSChristoph Lameter }
2702244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
2712244b95aSChristoph Lameter 
2722244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
2732244b95aSChristoph Lameter {
2742244b95aSChristoph Lameter 	unsigned long flags;
2752244b95aSChristoph Lameter 
2762244b95aSChristoph Lameter 	local_irq_save(flags);
277a302eb4eSChristoph Lameter 	__dec_zone_page_state(page, item);
2782244b95aSChristoph Lameter 	local_irq_restore(flags);
2792244b95aSChristoph Lameter }
2802244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
2812244b95aSChristoph Lameter 
2822244b95aSChristoph Lameter /*
2832244b95aSChristoph Lameter  * Update the zone counters for one cpu.
2842244b95aSChristoph Lameter  */
2852244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu)
2862244b95aSChristoph Lameter {
2872244b95aSChristoph Lameter 	struct zone *zone;
2882244b95aSChristoph Lameter 	int i;
2892244b95aSChristoph Lameter 	unsigned long flags;
2902244b95aSChristoph Lameter 
2912244b95aSChristoph Lameter 	for_each_zone(zone) {
2922244b95aSChristoph Lameter 		struct per_cpu_pageset *pcp;
2932244b95aSChristoph Lameter 
29439bbcb8fSChristoph Lameter 		if (!populated_zone(zone))
29539bbcb8fSChristoph Lameter 			continue;
29639bbcb8fSChristoph Lameter 
2972244b95aSChristoph Lameter 		pcp = zone_pcp(zone, cpu);
2982244b95aSChristoph Lameter 
2992244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
3002244b95aSChristoph Lameter 			if (pcp->vm_stat_diff[i]) {
3012244b95aSChristoph Lameter 				local_irq_save(flags);
3022244b95aSChristoph Lameter 				zone_page_state_add(pcp->vm_stat_diff[i],
3032244b95aSChristoph Lameter 					zone, i);
3042244b95aSChristoph Lameter 				pcp->vm_stat_diff[i] = 0;
3052244b95aSChristoph Lameter 				local_irq_restore(flags);
3062244b95aSChristoph Lameter 			}
3072244b95aSChristoph Lameter 	}
3082244b95aSChristoph Lameter }
3092244b95aSChristoph Lameter 
3102244b95aSChristoph Lameter static void __refresh_cpu_vm_stats(void *dummy)
3112244b95aSChristoph Lameter {
3122244b95aSChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
3132244b95aSChristoph Lameter }
3142244b95aSChristoph Lameter 
3152244b95aSChristoph Lameter /*
3162244b95aSChristoph Lameter  * Consolidate all counters.
3172244b95aSChristoph Lameter  *
3182244b95aSChristoph Lameter  * Note that the result is less inaccurate but still inaccurate
3192244b95aSChristoph Lameter  * if concurrent processes are allowed to run.
3202244b95aSChristoph Lameter  */
3212244b95aSChristoph Lameter void refresh_vm_stats(void)
3222244b95aSChristoph Lameter {
3232244b95aSChristoph Lameter 	on_each_cpu(__refresh_cpu_vm_stats, NULL, 0, 1);
3242244b95aSChristoph Lameter }
3252244b95aSChristoph Lameter EXPORT_SYMBOL(refresh_vm_stats);
3262244b95aSChristoph Lameter 
3272244b95aSChristoph Lameter #endif
3282244b95aSChristoph Lameter 
329ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
330ca889e6cSChristoph Lameter /*
331ca889e6cSChristoph Lameter  * zonelist = the list of zones passed to the allocator
332ca889e6cSChristoph Lameter  * z 	    = the zone from which the allocation occurred.
333ca889e6cSChristoph Lameter  *
334ca889e6cSChristoph Lameter  * Must be called with interrupts disabled.
335ca889e6cSChristoph Lameter  */
336ca889e6cSChristoph Lameter void zone_statistics(struct zonelist *zonelist, struct zone *z)
337ca889e6cSChristoph Lameter {
338ca889e6cSChristoph Lameter 	if (z->zone_pgdat == zonelist->zones[0]->zone_pgdat) {
339ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_HIT);
340ca889e6cSChristoph Lameter 	} else {
341ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_MISS);
342ca889e6cSChristoph Lameter 		__inc_zone_state(zonelist->zones[0], NUMA_FOREIGN);
343ca889e6cSChristoph Lameter 	}
3445d292343SChristoph Lameter 	if (z->node == numa_node_id())
345ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_LOCAL);
346ca889e6cSChristoph Lameter 	else
347ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_OTHER);
348ca889e6cSChristoph Lameter }
349ca889e6cSChristoph Lameter #endif
350ca889e6cSChristoph Lameter 
351f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS
352f6ac2354SChristoph Lameter 
353f6ac2354SChristoph Lameter #include <linux/seq_file.h>
354f6ac2354SChristoph Lameter 
355f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos)
356f6ac2354SChristoph Lameter {
357f6ac2354SChristoph Lameter 	pg_data_t *pgdat;
358f6ac2354SChristoph Lameter 	loff_t node = *pos;
359f6ac2354SChristoph Lameter 	for (pgdat = first_online_pgdat();
360f6ac2354SChristoph Lameter 	     pgdat && node;
361f6ac2354SChristoph Lameter 	     pgdat = next_online_pgdat(pgdat))
362f6ac2354SChristoph Lameter 		--node;
363f6ac2354SChristoph Lameter 
364f6ac2354SChristoph Lameter 	return pgdat;
365f6ac2354SChristoph Lameter }
366f6ac2354SChristoph Lameter 
367f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
368f6ac2354SChristoph Lameter {
369f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
370f6ac2354SChristoph Lameter 
371f6ac2354SChristoph Lameter 	(*pos)++;
372f6ac2354SChristoph Lameter 	return next_online_pgdat(pgdat);
373f6ac2354SChristoph Lameter }
374f6ac2354SChristoph Lameter 
375f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg)
376f6ac2354SChristoph Lameter {
377f6ac2354SChristoph Lameter }
378f6ac2354SChristoph Lameter 
379f6ac2354SChristoph Lameter /*
380f6ac2354SChristoph Lameter  * This walks the free areas for each zone.
381f6ac2354SChristoph Lameter  */
382f6ac2354SChristoph Lameter static int frag_show(struct seq_file *m, void *arg)
383f6ac2354SChristoph Lameter {
384f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
385f6ac2354SChristoph Lameter 	struct zone *zone;
386f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
387f6ac2354SChristoph Lameter 	unsigned long flags;
388f6ac2354SChristoph Lameter 	int order;
389f6ac2354SChristoph Lameter 
390f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
391f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
392f6ac2354SChristoph Lameter 			continue;
393f6ac2354SChristoph Lameter 
394f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
395f6ac2354SChristoph Lameter 		seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
396f6ac2354SChristoph Lameter 		for (order = 0; order < MAX_ORDER; ++order)
397f6ac2354SChristoph Lameter 			seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
398f6ac2354SChristoph Lameter 		spin_unlock_irqrestore(&zone->lock, flags);
399f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
400f6ac2354SChristoph Lameter 	}
401f6ac2354SChristoph Lameter 	return 0;
402f6ac2354SChristoph Lameter }
403f6ac2354SChristoph Lameter 
40415ad7cdcSHelge Deller const struct seq_operations fragmentation_op = {
405f6ac2354SChristoph Lameter 	.start	= frag_start,
406f6ac2354SChristoph Lameter 	.next	= frag_next,
407f6ac2354SChristoph Lameter 	.stop	= frag_stop,
408f6ac2354SChristoph Lameter 	.show	= frag_show,
409f6ac2354SChristoph Lameter };
410f6ac2354SChristoph Lameter 
4114b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA
4124b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma",
4134b51d669SChristoph Lameter #else
4144b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx)
4154b51d669SChristoph Lameter #endif
4164b51d669SChristoph Lameter 
41727bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32
41827bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32",
41927bf71c2SChristoph Lameter #else
42027bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx)
42127bf71c2SChristoph Lameter #endif
42227bf71c2SChristoph Lameter 
42327bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM
42427bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high",
42527bf71c2SChristoph Lameter #else
42627bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx)
42727bf71c2SChristoph Lameter #endif
42827bf71c2SChristoph Lameter 
4294b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
43027bf71c2SChristoph Lameter 					TEXT_FOR_HIGHMEM(xx)
43127bf71c2SChristoph Lameter 
43215ad7cdcSHelge Deller static const char * const vmstat_text[] = {
4332244b95aSChristoph Lameter 	/* Zoned VM counters */
434d23ad423SChristoph Lameter 	"nr_free_pages",
435c8785385SChristoph Lameter 	"nr_active",
436c8785385SChristoph Lameter 	"nr_inactive",
437f3dbd344SChristoph Lameter 	"nr_anon_pages",
43865ba55f5SChristoph Lameter 	"nr_mapped",
439347ce434SChristoph Lameter 	"nr_file_pages",
44051ed4491SChristoph Lameter 	"nr_dirty",
44151ed4491SChristoph Lameter 	"nr_writeback",
442972d1a7bSChristoph Lameter 	"nr_slab_reclaimable",
443972d1a7bSChristoph Lameter 	"nr_slab_unreclaimable",
444df849a15SChristoph Lameter 	"nr_page_table_pages",
445f6ac2354SChristoph Lameter 	"nr_unstable",
446d2c5e30cSChristoph Lameter 	"nr_bounce",
447e129b5c2SAndrew Morton 	"nr_vmscan_write",
448f6ac2354SChristoph Lameter 
449ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
450ca889e6cSChristoph Lameter 	"numa_hit",
451ca889e6cSChristoph Lameter 	"numa_miss",
452ca889e6cSChristoph Lameter 	"numa_foreign",
453ca889e6cSChristoph Lameter 	"numa_interleave",
454ca889e6cSChristoph Lameter 	"numa_local",
455ca889e6cSChristoph Lameter 	"numa_other",
456ca889e6cSChristoph Lameter #endif
457ca889e6cSChristoph Lameter 
458f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
459f6ac2354SChristoph Lameter 	"pgpgin",
460f6ac2354SChristoph Lameter 	"pgpgout",
461f6ac2354SChristoph Lameter 	"pswpin",
462f6ac2354SChristoph Lameter 	"pswpout",
463f6ac2354SChristoph Lameter 
46427bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgalloc")
465f6ac2354SChristoph Lameter 
466f6ac2354SChristoph Lameter 	"pgfree",
467f6ac2354SChristoph Lameter 	"pgactivate",
468f6ac2354SChristoph Lameter 	"pgdeactivate",
469f6ac2354SChristoph Lameter 
470f6ac2354SChristoph Lameter 	"pgfault",
471f6ac2354SChristoph Lameter 	"pgmajfault",
472f6ac2354SChristoph Lameter 
47327bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgrefill")
47427bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgsteal")
47527bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_kswapd")
47627bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_direct")
477f6ac2354SChristoph Lameter 
478f6ac2354SChristoph Lameter 	"pginodesteal",
479f6ac2354SChristoph Lameter 	"slabs_scanned",
480f6ac2354SChristoph Lameter 	"kswapd_steal",
481f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
482f6ac2354SChristoph Lameter 	"pageoutrun",
483f6ac2354SChristoph Lameter 	"allocstall",
484f6ac2354SChristoph Lameter 
485f6ac2354SChristoph Lameter 	"pgrotated",
486f8891e5eSChristoph Lameter #endif
487f6ac2354SChristoph Lameter };
488f6ac2354SChristoph Lameter 
489f6ac2354SChristoph Lameter /*
490f6ac2354SChristoph Lameter  * Output information about zones in @pgdat.
491f6ac2354SChristoph Lameter  */
492f6ac2354SChristoph Lameter static int zoneinfo_show(struct seq_file *m, void *arg)
493f6ac2354SChristoph Lameter {
494f6ac2354SChristoph Lameter 	pg_data_t *pgdat = arg;
495f6ac2354SChristoph Lameter 	struct zone *zone;
496f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
497f6ac2354SChristoph Lameter 	unsigned long flags;
498f6ac2354SChristoph Lameter 
499f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
500f6ac2354SChristoph Lameter 		int i;
501f6ac2354SChristoph Lameter 
502f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
503f6ac2354SChristoph Lameter 			continue;
504f6ac2354SChristoph Lameter 
505f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
506f6ac2354SChristoph Lameter 		seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
507f6ac2354SChristoph Lameter 		seq_printf(m,
508f6ac2354SChristoph Lameter 			   "\n  pages free     %lu"
509f6ac2354SChristoph Lameter 			   "\n        min      %lu"
510f6ac2354SChristoph Lameter 			   "\n        low      %lu"
511f6ac2354SChristoph Lameter 			   "\n        high     %lu"
512f6ac2354SChristoph Lameter 			   "\n        scanned  %lu (a: %lu i: %lu)"
513f6ac2354SChristoph Lameter 			   "\n        spanned  %lu"
514f6ac2354SChristoph Lameter 			   "\n        present  %lu",
515d23ad423SChristoph Lameter 			   zone_page_state(zone, NR_FREE_PAGES),
516f6ac2354SChristoph Lameter 			   zone->pages_min,
517f6ac2354SChristoph Lameter 			   zone->pages_low,
518f6ac2354SChristoph Lameter 			   zone->pages_high,
519f6ac2354SChristoph Lameter 			   zone->pages_scanned,
520f6ac2354SChristoph Lameter 			   zone->nr_scan_active, zone->nr_scan_inactive,
521f6ac2354SChristoph Lameter 			   zone->spanned_pages,
522f6ac2354SChristoph Lameter 			   zone->present_pages);
5232244b95aSChristoph Lameter 
5242244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
5252244b95aSChristoph Lameter 			seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
5262244b95aSChristoph Lameter 					zone_page_state(zone, i));
5272244b95aSChristoph Lameter 
528f6ac2354SChristoph Lameter 		seq_printf(m,
529f6ac2354SChristoph Lameter 			   "\n        protection: (%lu",
530f6ac2354SChristoph Lameter 			   zone->lowmem_reserve[0]);
531f6ac2354SChristoph Lameter 		for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
532f6ac2354SChristoph Lameter 			seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
533f6ac2354SChristoph Lameter 		seq_printf(m,
534f6ac2354SChristoph Lameter 			   ")"
535f6ac2354SChristoph Lameter 			   "\n  pagesets");
536f6ac2354SChristoph Lameter 		for_each_online_cpu(i) {
537f6ac2354SChristoph Lameter 			struct per_cpu_pageset *pageset;
538f6ac2354SChristoph Lameter 			int j;
539f6ac2354SChristoph Lameter 
540f6ac2354SChristoph Lameter 			pageset = zone_pcp(zone, i);
541f6ac2354SChristoph Lameter 			for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
542f6ac2354SChristoph Lameter 				seq_printf(m,
543f6ac2354SChristoph Lameter 					   "\n    cpu: %i pcp: %i"
544f6ac2354SChristoph Lameter 					   "\n              count: %i"
545f6ac2354SChristoph Lameter 					   "\n              high:  %i"
546f6ac2354SChristoph Lameter 					   "\n              batch: %i",
547f6ac2354SChristoph Lameter 					   i, j,
548f6ac2354SChristoph Lameter 					   pageset->pcp[j].count,
549f6ac2354SChristoph Lameter 					   pageset->pcp[j].high,
550f6ac2354SChristoph Lameter 					   pageset->pcp[j].batch);
551f6ac2354SChristoph Lameter 			}
552df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
553df9ecabaSChristoph Lameter 			seq_printf(m, "\n  vm stats threshold: %d",
554df9ecabaSChristoph Lameter 					pageset->stat_threshold);
555df9ecabaSChristoph Lameter #endif
556f6ac2354SChristoph Lameter 		}
557f6ac2354SChristoph Lameter 		seq_printf(m,
558f6ac2354SChristoph Lameter 			   "\n  all_unreclaimable: %u"
559f6ac2354SChristoph Lameter 			   "\n  prev_priority:     %i"
560f6ac2354SChristoph Lameter 			   "\n  start_pfn:         %lu",
561f6ac2354SChristoph Lameter 			   zone->all_unreclaimable,
562f6ac2354SChristoph Lameter 			   zone->prev_priority,
563f6ac2354SChristoph Lameter 			   zone->zone_start_pfn);
564f6ac2354SChristoph Lameter 		spin_unlock_irqrestore(&zone->lock, flags);
565f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
566f6ac2354SChristoph Lameter 	}
567f6ac2354SChristoph Lameter 	return 0;
568f6ac2354SChristoph Lameter }
569f6ac2354SChristoph Lameter 
57015ad7cdcSHelge Deller const struct seq_operations zoneinfo_op = {
571f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
572f6ac2354SChristoph Lameter 			       * fragmentation. */
573f6ac2354SChristoph Lameter 	.next	= frag_next,
574f6ac2354SChristoph Lameter 	.stop	= frag_stop,
575f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
576f6ac2354SChristoph Lameter };
577f6ac2354SChristoph Lameter 
578f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
579f6ac2354SChristoph Lameter {
5802244b95aSChristoph Lameter 	unsigned long *v;
581f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
582f8891e5eSChristoph Lameter 	unsigned long *e;
583f8891e5eSChristoph Lameter #endif
5842244b95aSChristoph Lameter 	int i;
585f6ac2354SChristoph Lameter 
586f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
587f6ac2354SChristoph Lameter 		return NULL;
588f6ac2354SChristoph Lameter 
589f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
5902244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
591f8891e5eSChristoph Lameter 			+ sizeof(struct vm_event_state), GFP_KERNEL);
592f8891e5eSChristoph Lameter #else
593f8891e5eSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
594f8891e5eSChristoph Lameter 			GFP_KERNEL);
595f8891e5eSChristoph Lameter #endif
5962244b95aSChristoph Lameter 	m->private = v;
5972244b95aSChristoph Lameter 	if (!v)
598f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
5992244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
6002244b95aSChristoph Lameter 		v[i] = global_page_state(i);
601f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
602f8891e5eSChristoph Lameter 	e = v + NR_VM_ZONE_STAT_ITEMS;
603f8891e5eSChristoph Lameter 	all_vm_events(e);
604f8891e5eSChristoph Lameter 	e[PGPGIN] /= 2;		/* sectors -> kbytes */
605f8891e5eSChristoph Lameter 	e[PGPGOUT] /= 2;
606f8891e5eSChristoph Lameter #endif
6072244b95aSChristoph Lameter 	return v + *pos;
608f6ac2354SChristoph Lameter }
609f6ac2354SChristoph Lameter 
610f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
611f6ac2354SChristoph Lameter {
612f6ac2354SChristoph Lameter 	(*pos)++;
613f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
614f6ac2354SChristoph Lameter 		return NULL;
615f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
616f6ac2354SChristoph Lameter }
617f6ac2354SChristoph Lameter 
618f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
619f6ac2354SChristoph Lameter {
620f6ac2354SChristoph Lameter 	unsigned long *l = arg;
621f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
622f6ac2354SChristoph Lameter 
623f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
624f6ac2354SChristoph Lameter 	return 0;
625f6ac2354SChristoph Lameter }
626f6ac2354SChristoph Lameter 
627f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
628f6ac2354SChristoph Lameter {
629f6ac2354SChristoph Lameter 	kfree(m->private);
630f6ac2354SChristoph Lameter 	m->private = NULL;
631f6ac2354SChristoph Lameter }
632f6ac2354SChristoph Lameter 
63315ad7cdcSHelge Deller const struct seq_operations vmstat_op = {
634f6ac2354SChristoph Lameter 	.start	= vmstat_start,
635f6ac2354SChristoph Lameter 	.next	= vmstat_next,
636f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
637f6ac2354SChristoph Lameter 	.show	= vmstat_show,
638f6ac2354SChristoph Lameter };
639f6ac2354SChristoph Lameter 
640f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
641f6ac2354SChristoph Lameter 
642df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
643d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
644*77461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
645d1187ed2SChristoph Lameter 
646d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
647d1187ed2SChristoph Lameter {
648d1187ed2SChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
649*77461ab3SChristoph Lameter 	schedule_delayed_work(&__get_cpu_var(vmstat_work),
650*77461ab3SChristoph Lameter 		sysctl_stat_interval);
651d1187ed2SChristoph Lameter }
652d1187ed2SChristoph Lameter 
653d1187ed2SChristoph Lameter static void __devinit start_cpu_timer(int cpu)
654d1187ed2SChristoph Lameter {
655d1187ed2SChristoph Lameter 	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
656d1187ed2SChristoph Lameter 
657d1187ed2SChristoph Lameter 	INIT_DELAYED_WORK(vmstat_work, vmstat_update);
658d1187ed2SChristoph Lameter 	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
659d1187ed2SChristoph Lameter }
660d1187ed2SChristoph Lameter 
661df9ecabaSChristoph Lameter /*
662df9ecabaSChristoph Lameter  * Use the cpu notifier to insure that the thresholds are recalculated
663df9ecabaSChristoph Lameter  * when necessary.
664df9ecabaSChristoph Lameter  */
665df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
666df9ecabaSChristoph Lameter 		unsigned long action,
667df9ecabaSChristoph Lameter 		void *hcpu)
668df9ecabaSChristoph Lameter {
669d1187ed2SChristoph Lameter 	long cpu = (long)hcpu;
670d1187ed2SChristoph Lameter 
671df9ecabaSChristoph Lameter 	switch (action) {
672d1187ed2SChristoph Lameter 	case CPU_ONLINE:
673d1187ed2SChristoph Lameter 	case CPU_ONLINE_FROZEN:
674d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
675d1187ed2SChristoph Lameter 		break;
676d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE:
677d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE_FROZEN:
678d1187ed2SChristoph Lameter 		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
679d1187ed2SChristoph Lameter 		per_cpu(vmstat_work, cpu).work.func = NULL;
680d1187ed2SChristoph Lameter 		break;
681d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED:
682d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED_FROZEN:
683d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
684d1187ed2SChristoph Lameter 		break;
685df9ecabaSChristoph Lameter 	case CPU_DEAD:
6868bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
687df9ecabaSChristoph Lameter 		refresh_zone_stat_thresholds();
688df9ecabaSChristoph Lameter 		break;
689df9ecabaSChristoph Lameter 	default:
690df9ecabaSChristoph Lameter 		break;
691df9ecabaSChristoph Lameter 	}
692df9ecabaSChristoph Lameter 	return NOTIFY_OK;
693df9ecabaSChristoph Lameter }
694df9ecabaSChristoph Lameter 
695df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier =
696df9ecabaSChristoph Lameter 	{ &vmstat_cpuup_callback, NULL, 0 };
697df9ecabaSChristoph Lameter 
698df9ecabaSChristoph Lameter int __init setup_vmstat(void)
699df9ecabaSChristoph Lameter {
700d1187ed2SChristoph Lameter 	int cpu;
701d1187ed2SChristoph Lameter 
702df9ecabaSChristoph Lameter 	refresh_zone_stat_thresholds();
703df9ecabaSChristoph Lameter 	register_cpu_notifier(&vmstat_notifier);
704d1187ed2SChristoph Lameter 
705d1187ed2SChristoph Lameter 	for_each_online_cpu(cpu)
706d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
707df9ecabaSChristoph Lameter 	return 0;
708df9ecabaSChristoph Lameter }
709df9ecabaSChristoph Lameter module_init(setup_vmstat)
710df9ecabaSChristoph Lameter #endif
711