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