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 23174596a0SRusty Russell static void sum_vm_events(unsigned long *ret, const struct cpumask *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 30aa85ea5bSRusty Russell for_each_cpu(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(); 46174596a0SRusty Russell sum_vm_events(ret, cpu_online_mask); 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 138ee99c71cSKOSAKI Motohiro for_each_populated_zone(zone) { 139df9ecabaSChristoph Lameter threshold = calculate_threshold(zone); 140df9ecabaSChristoph Lameter 141df9ecabaSChristoph Lameter for_each_online_cpu(cpu) 14299dcc3e5SChristoph Lameter per_cpu_ptr(zone->pageset, cpu)->stat_threshold 14399dcc3e5SChristoph Lameter = threshold; 144df9ecabaSChristoph Lameter } 1452244b95aSChristoph Lameter } 1462244b95aSChristoph Lameter 1472244b95aSChristoph Lameter /* 1482244b95aSChristoph Lameter * For use when we know that interrupts are disabled. 1492244b95aSChristoph Lameter */ 1502244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item, 1512244b95aSChristoph Lameter int delta) 1522244b95aSChristoph Lameter { 15399dcc3e5SChristoph Lameter struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset); 15499dcc3e5SChristoph Lameter 155df9ecabaSChristoph Lameter s8 *p = pcp->vm_stat_diff + item; 1562244b95aSChristoph Lameter long x; 1572244b95aSChristoph Lameter 1582244b95aSChristoph Lameter x = delta + *p; 1592244b95aSChristoph Lameter 160df9ecabaSChristoph Lameter if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) { 1612244b95aSChristoph Lameter zone_page_state_add(x, zone, item); 1622244b95aSChristoph Lameter x = 0; 1632244b95aSChristoph Lameter } 1642244b95aSChristoph Lameter *p = x; 1652244b95aSChristoph Lameter } 1662244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state); 1672244b95aSChristoph Lameter 1682244b95aSChristoph Lameter /* 1692244b95aSChristoph Lameter * For an unknown interrupt state 1702244b95aSChristoph Lameter */ 1712244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item, 1722244b95aSChristoph Lameter int delta) 1732244b95aSChristoph Lameter { 1742244b95aSChristoph Lameter unsigned long flags; 1752244b95aSChristoph Lameter 1762244b95aSChristoph Lameter local_irq_save(flags); 1772244b95aSChristoph Lameter __mod_zone_page_state(zone, item, delta); 1782244b95aSChristoph Lameter local_irq_restore(flags); 1792244b95aSChristoph Lameter } 1802244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state); 1812244b95aSChristoph Lameter 1822244b95aSChristoph Lameter /* 1832244b95aSChristoph Lameter * Optimized increment and decrement functions. 1842244b95aSChristoph Lameter * 1852244b95aSChristoph Lameter * These are only for a single page and therefore can take a struct page * 1862244b95aSChristoph Lameter * argument instead of struct zone *. This allows the inclusion of the code 1872244b95aSChristoph Lameter * generated for page_zone(page) into the optimized functions. 1882244b95aSChristoph Lameter * 1892244b95aSChristoph Lameter * No overflow check is necessary and therefore the differential can be 1902244b95aSChristoph Lameter * incremented or decremented in place which may allow the compilers to 1912244b95aSChristoph Lameter * generate better code. 1922244b95aSChristoph Lameter * The increment or decrement is known and therefore one boundary check can 1932244b95aSChristoph Lameter * be omitted. 1942244b95aSChristoph Lameter * 195df9ecabaSChristoph Lameter * NOTE: These functions are very performance sensitive. Change only 196df9ecabaSChristoph Lameter * with care. 197df9ecabaSChristoph Lameter * 1982244b95aSChristoph Lameter * Some processors have inc/dec instructions that are atomic vs an interrupt. 1992244b95aSChristoph Lameter * However, the code must first determine the differential location in a zone 2002244b95aSChristoph Lameter * based on the processor number and then inc/dec the counter. There is no 2012244b95aSChristoph Lameter * guarantee without disabling preemption that the processor will not change 2022244b95aSChristoph Lameter * in between and therefore the atomicity vs. interrupt cannot be exploited 2032244b95aSChristoph Lameter * in a useful way here. 2042244b95aSChristoph Lameter */ 205c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item) 2062244b95aSChristoph Lameter { 20799dcc3e5SChristoph Lameter struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset); 208df9ecabaSChristoph Lameter s8 *p = pcp->vm_stat_diff + item; 2092244b95aSChristoph Lameter 2102244b95aSChristoph Lameter (*p)++; 2112244b95aSChristoph Lameter 212df9ecabaSChristoph Lameter if (unlikely(*p > pcp->stat_threshold)) { 213df9ecabaSChristoph Lameter int overstep = pcp->stat_threshold / 2; 214df9ecabaSChristoph Lameter 215df9ecabaSChristoph Lameter zone_page_state_add(*p + overstep, zone, item); 216df9ecabaSChristoph Lameter *p = -overstep; 2172244b95aSChristoph Lameter } 2182244b95aSChristoph Lameter } 219ca889e6cSChristoph Lameter 220ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item) 221ca889e6cSChristoph Lameter { 222ca889e6cSChristoph Lameter __inc_zone_state(page_zone(page), item); 223ca889e6cSChristoph Lameter } 2242244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state); 2252244b95aSChristoph Lameter 226c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item) 2272244b95aSChristoph Lameter { 22899dcc3e5SChristoph Lameter struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset); 229df9ecabaSChristoph Lameter s8 *p = pcp->vm_stat_diff + item; 2302244b95aSChristoph Lameter 2312244b95aSChristoph Lameter (*p)--; 2322244b95aSChristoph Lameter 233df9ecabaSChristoph Lameter if (unlikely(*p < - pcp->stat_threshold)) { 234df9ecabaSChristoph Lameter int overstep = pcp->stat_threshold / 2; 235df9ecabaSChristoph Lameter 236df9ecabaSChristoph Lameter zone_page_state_add(*p - overstep, zone, item); 237df9ecabaSChristoph Lameter *p = overstep; 2382244b95aSChristoph Lameter } 2392244b95aSChristoph Lameter } 240c8785385SChristoph Lameter 241c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item) 242c8785385SChristoph Lameter { 243c8785385SChristoph Lameter __dec_zone_state(page_zone(page), item); 244c8785385SChristoph Lameter } 2452244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state); 2462244b95aSChristoph Lameter 247ca889e6cSChristoph Lameter void inc_zone_state(struct zone *zone, enum zone_stat_item item) 248ca889e6cSChristoph Lameter { 249ca889e6cSChristoph Lameter unsigned long flags; 250ca889e6cSChristoph Lameter 251ca889e6cSChristoph Lameter local_irq_save(flags); 252ca889e6cSChristoph Lameter __inc_zone_state(zone, item); 253ca889e6cSChristoph Lameter local_irq_restore(flags); 254ca889e6cSChristoph Lameter } 255ca889e6cSChristoph Lameter 2562244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item) 2572244b95aSChristoph Lameter { 2582244b95aSChristoph Lameter unsigned long flags; 2592244b95aSChristoph Lameter struct zone *zone; 2602244b95aSChristoph Lameter 2612244b95aSChristoph Lameter zone = page_zone(page); 2622244b95aSChristoph Lameter local_irq_save(flags); 263ca889e6cSChristoph Lameter __inc_zone_state(zone, item); 2642244b95aSChristoph Lameter local_irq_restore(flags); 2652244b95aSChristoph Lameter } 2662244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state); 2672244b95aSChristoph Lameter 2682244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item) 2692244b95aSChristoph Lameter { 2702244b95aSChristoph Lameter unsigned long flags; 2712244b95aSChristoph Lameter 2722244b95aSChristoph Lameter local_irq_save(flags); 273a302eb4eSChristoph Lameter __dec_zone_page_state(page, item); 2742244b95aSChristoph Lameter local_irq_restore(flags); 2752244b95aSChristoph Lameter } 2762244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state); 2772244b95aSChristoph Lameter 2782244b95aSChristoph Lameter /* 2792244b95aSChristoph Lameter * Update the zone counters for one cpu. 2804037d452SChristoph Lameter * 281a7f75e25SChristoph Lameter * The cpu specified must be either the current cpu or a processor that 282a7f75e25SChristoph Lameter * is not online. If it is the current cpu then the execution thread must 283a7f75e25SChristoph Lameter * be pinned to the current cpu. 284a7f75e25SChristoph Lameter * 2854037d452SChristoph Lameter * Note that refresh_cpu_vm_stats strives to only access 2864037d452SChristoph Lameter * node local memory. The per cpu pagesets on remote zones are placed 2874037d452SChristoph Lameter * in the memory local to the processor using that pageset. So the 2884037d452SChristoph Lameter * loop over all zones will access a series of cachelines local to 2894037d452SChristoph Lameter * the processor. 2904037d452SChristoph Lameter * 2914037d452SChristoph Lameter * The call to zone_page_state_add updates the cachelines with the 2924037d452SChristoph Lameter * statistics in the remote zone struct as well as the global cachelines 2934037d452SChristoph Lameter * with the global counters. These could cause remote node cache line 2944037d452SChristoph Lameter * bouncing and will have to be only done when necessary. 2952244b95aSChristoph Lameter */ 2962244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu) 2972244b95aSChristoph Lameter { 2982244b95aSChristoph Lameter struct zone *zone; 2992244b95aSChristoph Lameter int i; 300a7f75e25SChristoph Lameter int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, }; 3012244b95aSChristoph Lameter 302ee99c71cSKOSAKI Motohiro for_each_populated_zone(zone) { 3034037d452SChristoph Lameter struct per_cpu_pageset *p; 3042244b95aSChristoph Lameter 30599dcc3e5SChristoph Lameter p = per_cpu_ptr(zone->pageset, cpu); 3062244b95aSChristoph Lameter 3072244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 3084037d452SChristoph Lameter if (p->vm_stat_diff[i]) { 309a7f75e25SChristoph Lameter unsigned long flags; 310a7f75e25SChristoph Lameter int v; 311a7f75e25SChristoph Lameter 3122244b95aSChristoph Lameter local_irq_save(flags); 313a7f75e25SChristoph Lameter v = p->vm_stat_diff[i]; 3144037d452SChristoph Lameter p->vm_stat_diff[i] = 0; 315a7f75e25SChristoph Lameter local_irq_restore(flags); 316a7f75e25SChristoph Lameter atomic_long_add(v, &zone->vm_stat[i]); 317a7f75e25SChristoph Lameter global_diff[i] += v; 3184037d452SChristoph Lameter #ifdef CONFIG_NUMA 3194037d452SChristoph Lameter /* 3 seconds idle till flush */ 3204037d452SChristoph Lameter p->expire = 3; 3214037d452SChristoph Lameter #endif 3222244b95aSChristoph Lameter } 323468fd62eSDimitri Sivanich cond_resched(); 3244037d452SChristoph Lameter #ifdef CONFIG_NUMA 3254037d452SChristoph Lameter /* 3264037d452SChristoph Lameter * Deal with draining the remote pageset of this 3274037d452SChristoph Lameter * processor 3284037d452SChristoph Lameter * 3294037d452SChristoph Lameter * Check if there are pages remaining in this pageset 3304037d452SChristoph Lameter * if not then there is nothing to expire. 3314037d452SChristoph Lameter */ 3323dfa5721SChristoph Lameter if (!p->expire || !p->pcp.count) 3334037d452SChristoph Lameter continue; 3344037d452SChristoph Lameter 3354037d452SChristoph Lameter /* 3364037d452SChristoph Lameter * We never drain zones local to this processor. 3374037d452SChristoph Lameter */ 3384037d452SChristoph Lameter if (zone_to_nid(zone) == numa_node_id()) { 3394037d452SChristoph Lameter p->expire = 0; 3404037d452SChristoph Lameter continue; 3414037d452SChristoph Lameter } 3424037d452SChristoph Lameter 3434037d452SChristoph Lameter p->expire--; 3444037d452SChristoph Lameter if (p->expire) 3454037d452SChristoph Lameter continue; 3464037d452SChristoph Lameter 3473dfa5721SChristoph Lameter if (p->pcp.count) 3483dfa5721SChristoph Lameter drain_zone_pages(zone, &p->pcp); 3494037d452SChristoph Lameter #endif 3502244b95aSChristoph Lameter } 351a7f75e25SChristoph Lameter 352a7f75e25SChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 353a7f75e25SChristoph Lameter if (global_diff[i]) 354a7f75e25SChristoph Lameter atomic_long_add(global_diff[i], &vm_stat[i]); 3552244b95aSChristoph Lameter } 3562244b95aSChristoph Lameter 3572244b95aSChristoph Lameter #endif 3582244b95aSChristoph Lameter 359ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA 360ca889e6cSChristoph Lameter /* 361ca889e6cSChristoph Lameter * zonelist = the list of zones passed to the allocator 362ca889e6cSChristoph Lameter * z = the zone from which the allocation occurred. 363ca889e6cSChristoph Lameter * 364ca889e6cSChristoph Lameter * Must be called with interrupts disabled. 365ca889e6cSChristoph Lameter */ 36618ea7e71SMel Gorman void zone_statistics(struct zone *preferred_zone, struct zone *z) 367ca889e6cSChristoph Lameter { 36818ea7e71SMel Gorman if (z->zone_pgdat == preferred_zone->zone_pgdat) { 369ca889e6cSChristoph Lameter __inc_zone_state(z, NUMA_HIT); 370ca889e6cSChristoph Lameter } else { 371ca889e6cSChristoph Lameter __inc_zone_state(z, NUMA_MISS); 37218ea7e71SMel Gorman __inc_zone_state(preferred_zone, NUMA_FOREIGN); 373ca889e6cSChristoph Lameter } 3745d292343SChristoph Lameter if (z->node == numa_node_id()) 375ca889e6cSChristoph Lameter __inc_zone_state(z, NUMA_LOCAL); 376ca889e6cSChristoph Lameter else 377ca889e6cSChristoph Lameter __inc_zone_state(z, NUMA_OTHER); 378ca889e6cSChristoph Lameter } 379ca889e6cSChristoph Lameter #endif 380ca889e6cSChristoph Lameter 381f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS 3828f32f7e5SAlexey Dobriyan #include <linux/proc_fs.h> 383f6ac2354SChristoph Lameter #include <linux/seq_file.h> 384f6ac2354SChristoph Lameter 385467c996cSMel Gorman static char * const migratetype_names[MIGRATE_TYPES] = { 386467c996cSMel Gorman "Unmovable", 387467c996cSMel Gorman "Reclaimable", 388467c996cSMel Gorman "Movable", 389467c996cSMel Gorman "Reserve", 39091446b06SKOSAKI Motohiro "Isolate", 391467c996cSMel Gorman }; 392467c996cSMel Gorman 393f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos) 394f6ac2354SChristoph Lameter { 395f6ac2354SChristoph Lameter pg_data_t *pgdat; 396f6ac2354SChristoph Lameter loff_t node = *pos; 397f6ac2354SChristoph Lameter for (pgdat = first_online_pgdat(); 398f6ac2354SChristoph Lameter pgdat && node; 399f6ac2354SChristoph Lameter pgdat = next_online_pgdat(pgdat)) 400f6ac2354SChristoph Lameter --node; 401f6ac2354SChristoph Lameter 402f6ac2354SChristoph Lameter return pgdat; 403f6ac2354SChristoph Lameter } 404f6ac2354SChristoph Lameter 405f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos) 406f6ac2354SChristoph Lameter { 407f6ac2354SChristoph Lameter pg_data_t *pgdat = (pg_data_t *)arg; 408f6ac2354SChristoph Lameter 409f6ac2354SChristoph Lameter (*pos)++; 410f6ac2354SChristoph Lameter return next_online_pgdat(pgdat); 411f6ac2354SChristoph Lameter } 412f6ac2354SChristoph Lameter 413f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg) 414f6ac2354SChristoph Lameter { 415f6ac2354SChristoph Lameter } 416f6ac2354SChristoph Lameter 417467c996cSMel Gorman /* Walk all the zones in a node and print using a callback */ 418467c996cSMel Gorman static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, 419467c996cSMel Gorman void (*print)(struct seq_file *m, pg_data_t *, struct zone *)) 420f6ac2354SChristoph Lameter { 421f6ac2354SChristoph Lameter struct zone *zone; 422f6ac2354SChristoph Lameter struct zone *node_zones = pgdat->node_zones; 423f6ac2354SChristoph Lameter unsigned long flags; 424f6ac2354SChristoph Lameter 425f6ac2354SChristoph Lameter for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { 426f6ac2354SChristoph Lameter if (!populated_zone(zone)) 427f6ac2354SChristoph Lameter continue; 428f6ac2354SChristoph Lameter 429f6ac2354SChristoph Lameter spin_lock_irqsave(&zone->lock, flags); 430467c996cSMel Gorman print(m, pgdat, zone); 431467c996cSMel Gorman spin_unlock_irqrestore(&zone->lock, flags); 432467c996cSMel Gorman } 433467c996cSMel Gorman } 434467c996cSMel Gorman 435467c996cSMel Gorman static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, 436467c996cSMel Gorman struct zone *zone) 437467c996cSMel Gorman { 438467c996cSMel Gorman int order; 439467c996cSMel Gorman 440f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); 441f6ac2354SChristoph Lameter for (order = 0; order < MAX_ORDER; ++order) 442f6ac2354SChristoph Lameter seq_printf(m, "%6lu ", zone->free_area[order].nr_free); 443f6ac2354SChristoph Lameter seq_putc(m, '\n'); 444f6ac2354SChristoph Lameter } 445467c996cSMel Gorman 446467c996cSMel Gorman /* 447467c996cSMel Gorman * This walks the free areas for each zone. 448467c996cSMel Gorman */ 449467c996cSMel Gorman static int frag_show(struct seq_file *m, void *arg) 450467c996cSMel Gorman { 451467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg; 452467c996cSMel Gorman walk_zones_in_node(m, pgdat, frag_show_print); 453467c996cSMel Gorman return 0; 454467c996cSMel Gorman } 455467c996cSMel Gorman 456467c996cSMel Gorman static void pagetypeinfo_showfree_print(struct seq_file *m, 457467c996cSMel Gorman pg_data_t *pgdat, struct zone *zone) 458467c996cSMel Gorman { 459467c996cSMel Gorman int order, mtype; 460467c996cSMel Gorman 461467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) { 462467c996cSMel Gorman seq_printf(m, "Node %4d, zone %8s, type %12s ", 463467c996cSMel Gorman pgdat->node_id, 464467c996cSMel Gorman zone->name, 465467c996cSMel Gorman migratetype_names[mtype]); 466467c996cSMel Gorman for (order = 0; order < MAX_ORDER; ++order) { 467467c996cSMel Gorman unsigned long freecount = 0; 468467c996cSMel Gorman struct free_area *area; 469467c996cSMel Gorman struct list_head *curr; 470467c996cSMel Gorman 471467c996cSMel Gorman area = &(zone->free_area[order]); 472467c996cSMel Gorman 473467c996cSMel Gorman list_for_each(curr, &area->free_list[mtype]) 474467c996cSMel Gorman freecount++; 475467c996cSMel Gorman seq_printf(m, "%6lu ", freecount); 476467c996cSMel Gorman } 477467c996cSMel Gorman seq_putc(m, '\n'); 478467c996cSMel Gorman } 479467c996cSMel Gorman } 480467c996cSMel Gorman 481467c996cSMel Gorman /* Print out the free pages at each order for each migatetype */ 482467c996cSMel Gorman static int pagetypeinfo_showfree(struct seq_file *m, void *arg) 483467c996cSMel Gorman { 484467c996cSMel Gorman int order; 485467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg; 486467c996cSMel Gorman 487467c996cSMel Gorman /* Print header */ 488467c996cSMel Gorman seq_printf(m, "%-43s ", "Free pages count per migrate type at order"); 489467c996cSMel Gorman for (order = 0; order < MAX_ORDER; ++order) 490467c996cSMel Gorman seq_printf(m, "%6d ", order); 491467c996cSMel Gorman seq_putc(m, '\n'); 492467c996cSMel Gorman 493467c996cSMel Gorman walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print); 494467c996cSMel Gorman 495467c996cSMel Gorman return 0; 496467c996cSMel Gorman } 497467c996cSMel Gorman 498467c996cSMel Gorman static void pagetypeinfo_showblockcount_print(struct seq_file *m, 499467c996cSMel Gorman pg_data_t *pgdat, struct zone *zone) 500467c996cSMel Gorman { 501467c996cSMel Gorman int mtype; 502467c996cSMel Gorman unsigned long pfn; 503467c996cSMel Gorman unsigned long start_pfn = zone->zone_start_pfn; 504467c996cSMel Gorman unsigned long end_pfn = start_pfn + zone->spanned_pages; 505467c996cSMel Gorman unsigned long count[MIGRATE_TYPES] = { 0, }; 506467c996cSMel Gorman 507467c996cSMel Gorman for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { 508467c996cSMel Gorman struct page *page; 509467c996cSMel Gorman 510467c996cSMel Gorman if (!pfn_valid(pfn)) 511467c996cSMel Gorman continue; 512467c996cSMel Gorman 513467c996cSMel Gorman page = pfn_to_page(pfn); 514eb33575cSMel Gorman 515eb33575cSMel Gorman /* Watch for unexpected holes punched in the memmap */ 516eb33575cSMel Gorman if (!memmap_valid_within(pfn, page, zone)) 517e80d6a24SMel Gorman continue; 518eb33575cSMel Gorman 519467c996cSMel Gorman mtype = get_pageblock_migratetype(page); 520467c996cSMel Gorman 521e80d6a24SMel Gorman if (mtype < MIGRATE_TYPES) 522467c996cSMel Gorman count[mtype]++; 523467c996cSMel Gorman } 524467c996cSMel Gorman 525467c996cSMel Gorman /* Print counts */ 526467c996cSMel Gorman seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); 527467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) 528467c996cSMel Gorman seq_printf(m, "%12lu ", count[mtype]); 529467c996cSMel Gorman seq_putc(m, '\n'); 530467c996cSMel Gorman } 531467c996cSMel Gorman 532467c996cSMel Gorman /* Print out the free pages at each order for each migratetype */ 533467c996cSMel Gorman static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg) 534467c996cSMel Gorman { 535467c996cSMel Gorman int mtype; 536467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg; 537467c996cSMel Gorman 538467c996cSMel Gorman seq_printf(m, "\n%-23s", "Number of blocks type "); 539467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) 540467c996cSMel Gorman seq_printf(m, "%12s ", migratetype_names[mtype]); 541467c996cSMel Gorman seq_putc(m, '\n'); 542467c996cSMel Gorman walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print); 543467c996cSMel Gorman 544467c996cSMel Gorman return 0; 545467c996cSMel Gorman } 546467c996cSMel Gorman 547467c996cSMel Gorman /* 548467c996cSMel Gorman * This prints out statistics in relation to grouping pages by mobility. 549467c996cSMel Gorman * It is expensive to collect so do not constantly read the file. 550467c996cSMel Gorman */ 551467c996cSMel Gorman static int pagetypeinfo_show(struct seq_file *m, void *arg) 552467c996cSMel Gorman { 553467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg; 554467c996cSMel Gorman 55541b25a37SKOSAKI Motohiro /* check memoryless node */ 55641b25a37SKOSAKI Motohiro if (!node_state(pgdat->node_id, N_HIGH_MEMORY)) 55741b25a37SKOSAKI Motohiro return 0; 55841b25a37SKOSAKI Motohiro 559467c996cSMel Gorman seq_printf(m, "Page block order: %d\n", pageblock_order); 560467c996cSMel Gorman seq_printf(m, "Pages per block: %lu\n", pageblock_nr_pages); 561467c996cSMel Gorman seq_putc(m, '\n'); 562467c996cSMel Gorman pagetypeinfo_showfree(m, pgdat); 563467c996cSMel Gorman pagetypeinfo_showblockcount(m, pgdat); 564467c996cSMel Gorman 565f6ac2354SChristoph Lameter return 0; 566f6ac2354SChristoph Lameter } 567f6ac2354SChristoph Lameter 5688f32f7e5SAlexey Dobriyan static const struct seq_operations fragmentation_op = { 569f6ac2354SChristoph Lameter .start = frag_start, 570f6ac2354SChristoph Lameter .next = frag_next, 571f6ac2354SChristoph Lameter .stop = frag_stop, 572f6ac2354SChristoph Lameter .show = frag_show, 573f6ac2354SChristoph Lameter }; 574f6ac2354SChristoph Lameter 5758f32f7e5SAlexey Dobriyan static int fragmentation_open(struct inode *inode, struct file *file) 5768f32f7e5SAlexey Dobriyan { 5778f32f7e5SAlexey Dobriyan return seq_open(file, &fragmentation_op); 5788f32f7e5SAlexey Dobriyan } 5798f32f7e5SAlexey Dobriyan 5808f32f7e5SAlexey Dobriyan static const struct file_operations fragmentation_file_operations = { 5818f32f7e5SAlexey Dobriyan .open = fragmentation_open, 5828f32f7e5SAlexey Dobriyan .read = seq_read, 5838f32f7e5SAlexey Dobriyan .llseek = seq_lseek, 5848f32f7e5SAlexey Dobriyan .release = seq_release, 5858f32f7e5SAlexey Dobriyan }; 5868f32f7e5SAlexey Dobriyan 58774e2e8e8SAlexey Dobriyan static const struct seq_operations pagetypeinfo_op = { 588467c996cSMel Gorman .start = frag_start, 589467c996cSMel Gorman .next = frag_next, 590467c996cSMel Gorman .stop = frag_stop, 591467c996cSMel Gorman .show = pagetypeinfo_show, 592467c996cSMel Gorman }; 593467c996cSMel Gorman 59474e2e8e8SAlexey Dobriyan static int pagetypeinfo_open(struct inode *inode, struct file *file) 59574e2e8e8SAlexey Dobriyan { 59674e2e8e8SAlexey Dobriyan return seq_open(file, &pagetypeinfo_op); 59774e2e8e8SAlexey Dobriyan } 59874e2e8e8SAlexey Dobriyan 59974e2e8e8SAlexey Dobriyan static const struct file_operations pagetypeinfo_file_ops = { 60074e2e8e8SAlexey Dobriyan .open = pagetypeinfo_open, 60174e2e8e8SAlexey Dobriyan .read = seq_read, 60274e2e8e8SAlexey Dobriyan .llseek = seq_lseek, 60374e2e8e8SAlexey Dobriyan .release = seq_release, 60474e2e8e8SAlexey Dobriyan }; 60574e2e8e8SAlexey Dobriyan 6064b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA 6074b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma", 6084b51d669SChristoph Lameter #else 6094b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) 6104b51d669SChristoph Lameter #endif 6114b51d669SChristoph Lameter 61227bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32 61327bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32", 61427bf71c2SChristoph Lameter #else 61527bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) 61627bf71c2SChristoph Lameter #endif 61727bf71c2SChristoph Lameter 61827bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM 61927bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high", 62027bf71c2SChristoph Lameter #else 62127bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) 62227bf71c2SChristoph Lameter #endif 62327bf71c2SChristoph Lameter 6244b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \ 6252a1e274aSMel Gorman TEXT_FOR_HIGHMEM(xx) xx "_movable", 62627bf71c2SChristoph Lameter 62715ad7cdcSHelge Deller static const char * const vmstat_text[] = { 6282244b95aSChristoph Lameter /* Zoned VM counters */ 629d23ad423SChristoph Lameter "nr_free_pages", 6304f98a2feSRik van Riel "nr_inactive_anon", 6314f98a2feSRik van Riel "nr_active_anon", 6324f98a2feSRik van Riel "nr_inactive_file", 6334f98a2feSRik van Riel "nr_active_file", 6347b854121SLee Schermerhorn "nr_unevictable", 6355344b7e6SNick Piggin "nr_mlock", 636f3dbd344SChristoph Lameter "nr_anon_pages", 63765ba55f5SChristoph Lameter "nr_mapped", 638347ce434SChristoph Lameter "nr_file_pages", 63951ed4491SChristoph Lameter "nr_dirty", 64051ed4491SChristoph Lameter "nr_writeback", 641972d1a7bSChristoph Lameter "nr_slab_reclaimable", 642972d1a7bSChristoph Lameter "nr_slab_unreclaimable", 643df849a15SChristoph Lameter "nr_page_table_pages", 644c6a7f572SKOSAKI Motohiro "nr_kernel_stack", 645f6ac2354SChristoph Lameter "nr_unstable", 646d2c5e30cSChristoph Lameter "nr_bounce", 647e129b5c2SAndrew Morton "nr_vmscan_write", 648fc3ba692SMiklos Szeredi "nr_writeback_temp", 649a731286dSKOSAKI Motohiro "nr_isolated_anon", 650a731286dSKOSAKI Motohiro "nr_isolated_file", 6514b02108aSKOSAKI Motohiro "nr_shmem", 652ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA 653ca889e6cSChristoph Lameter "numa_hit", 654ca889e6cSChristoph Lameter "numa_miss", 655ca889e6cSChristoph Lameter "numa_foreign", 656ca889e6cSChristoph Lameter "numa_interleave", 657ca889e6cSChristoph Lameter "numa_local", 658ca889e6cSChristoph Lameter "numa_other", 659ca889e6cSChristoph Lameter #endif 660ca889e6cSChristoph Lameter 661f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS 662f6ac2354SChristoph Lameter "pgpgin", 663f6ac2354SChristoph Lameter "pgpgout", 664f6ac2354SChristoph Lameter "pswpin", 665f6ac2354SChristoph Lameter "pswpout", 666f6ac2354SChristoph Lameter 66727bf71c2SChristoph Lameter TEXTS_FOR_ZONES("pgalloc") 668f6ac2354SChristoph Lameter 669f6ac2354SChristoph Lameter "pgfree", 670f6ac2354SChristoph Lameter "pgactivate", 671f6ac2354SChristoph Lameter "pgdeactivate", 672f6ac2354SChristoph Lameter 673f6ac2354SChristoph Lameter "pgfault", 674f6ac2354SChristoph Lameter "pgmajfault", 675f6ac2354SChristoph Lameter 67627bf71c2SChristoph Lameter TEXTS_FOR_ZONES("pgrefill") 67727bf71c2SChristoph Lameter TEXTS_FOR_ZONES("pgsteal") 67827bf71c2SChristoph Lameter TEXTS_FOR_ZONES("pgscan_kswapd") 67927bf71c2SChristoph Lameter TEXTS_FOR_ZONES("pgscan_direct") 680f6ac2354SChristoph Lameter 68124cf7251SMel Gorman #ifdef CONFIG_NUMA 68224cf7251SMel Gorman "zone_reclaim_failed", 68324cf7251SMel Gorman #endif 684f6ac2354SChristoph Lameter "pginodesteal", 685f6ac2354SChristoph Lameter "slabs_scanned", 686f6ac2354SChristoph Lameter "kswapd_steal", 687f6ac2354SChristoph Lameter "kswapd_inodesteal", 688bb3ab596SKOSAKI Motohiro "kswapd_low_wmark_hit_quickly", 689bb3ab596SKOSAKI Motohiro "kswapd_high_wmark_hit_quickly", 690bb3ab596SKOSAKI Motohiro "kswapd_skip_congestion_wait", 691f6ac2354SChristoph Lameter "pageoutrun", 692f6ac2354SChristoph Lameter "allocstall", 693f6ac2354SChristoph Lameter 694f6ac2354SChristoph Lameter "pgrotated", 6953b116300SAdam Litke #ifdef CONFIG_HUGETLB_PAGE 6963b116300SAdam Litke "htlb_buddy_alloc_success", 6973b116300SAdam Litke "htlb_buddy_alloc_fail", 6983b116300SAdam Litke #endif 699bbfd28eeSLee Schermerhorn "unevictable_pgs_culled", 700bbfd28eeSLee Schermerhorn "unevictable_pgs_scanned", 701bbfd28eeSLee Schermerhorn "unevictable_pgs_rescued", 7025344b7e6SNick Piggin "unevictable_pgs_mlocked", 7035344b7e6SNick Piggin "unevictable_pgs_munlocked", 7045344b7e6SNick Piggin "unevictable_pgs_cleared", 7055344b7e6SNick Piggin "unevictable_pgs_stranded", 706985737cfSLee Schermerhorn "unevictable_pgs_mlockfreed", 707bbfd28eeSLee Schermerhorn #endif 708f6ac2354SChristoph Lameter }; 709f6ac2354SChristoph Lameter 710467c996cSMel Gorman static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, 711467c996cSMel Gorman struct zone *zone) 712f6ac2354SChristoph Lameter { 713f6ac2354SChristoph Lameter int i; 714f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); 715f6ac2354SChristoph Lameter seq_printf(m, 716f6ac2354SChristoph Lameter "\n pages free %lu" 717f6ac2354SChristoph Lameter "\n min %lu" 718f6ac2354SChristoph Lameter "\n low %lu" 719f6ac2354SChristoph Lameter "\n high %lu" 72008d9ae7cSWu Fengguang "\n scanned %lu" 721f6ac2354SChristoph Lameter "\n spanned %lu" 722f6ac2354SChristoph Lameter "\n present %lu", 723d23ad423SChristoph Lameter zone_page_state(zone, NR_FREE_PAGES), 72441858966SMel Gorman min_wmark_pages(zone), 72541858966SMel Gorman low_wmark_pages(zone), 72641858966SMel Gorman high_wmark_pages(zone), 727f6ac2354SChristoph Lameter zone->pages_scanned, 728f6ac2354SChristoph Lameter zone->spanned_pages, 729f6ac2354SChristoph Lameter zone->present_pages); 7302244b95aSChristoph Lameter 7312244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 7322244b95aSChristoph Lameter seq_printf(m, "\n %-12s %lu", vmstat_text[i], 7332244b95aSChristoph Lameter zone_page_state(zone, i)); 7342244b95aSChristoph Lameter 735f6ac2354SChristoph Lameter seq_printf(m, 736f6ac2354SChristoph Lameter "\n protection: (%lu", 737f6ac2354SChristoph Lameter zone->lowmem_reserve[0]); 738f6ac2354SChristoph Lameter for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) 739f6ac2354SChristoph Lameter seq_printf(m, ", %lu", zone->lowmem_reserve[i]); 740f6ac2354SChristoph Lameter seq_printf(m, 741f6ac2354SChristoph Lameter ")" 742f6ac2354SChristoph Lameter "\n pagesets"); 743f6ac2354SChristoph Lameter for_each_online_cpu(i) { 744f6ac2354SChristoph Lameter struct per_cpu_pageset *pageset; 745f6ac2354SChristoph Lameter 74699dcc3e5SChristoph Lameter pageset = per_cpu_ptr(zone->pageset, i); 747f6ac2354SChristoph Lameter seq_printf(m, 7483dfa5721SChristoph Lameter "\n cpu: %i" 749f6ac2354SChristoph Lameter "\n count: %i" 750f6ac2354SChristoph Lameter "\n high: %i" 751f6ac2354SChristoph Lameter "\n batch: %i", 7523dfa5721SChristoph Lameter i, 7533dfa5721SChristoph Lameter pageset->pcp.count, 7543dfa5721SChristoph Lameter pageset->pcp.high, 7553dfa5721SChristoph Lameter pageset->pcp.batch); 756df9ecabaSChristoph Lameter #ifdef CONFIG_SMP 757df9ecabaSChristoph Lameter seq_printf(m, "\n vm stats threshold: %d", 758df9ecabaSChristoph Lameter pageset->stat_threshold); 759df9ecabaSChristoph Lameter #endif 760f6ac2354SChristoph Lameter } 761f6ac2354SChristoph Lameter seq_printf(m, 762f6ac2354SChristoph Lameter "\n all_unreclaimable: %u" 763f6ac2354SChristoph Lameter "\n prev_priority: %i" 764556adecbSRik van Riel "\n start_pfn: %lu" 765556adecbSRik van Riel "\n inactive_ratio: %u", 766e815af95SDavid Rientjes zone_is_all_unreclaimable(zone), 767f6ac2354SChristoph Lameter zone->prev_priority, 768556adecbSRik van Riel zone->zone_start_pfn, 769556adecbSRik van Riel zone->inactive_ratio); 770f6ac2354SChristoph Lameter seq_putc(m, '\n'); 771f6ac2354SChristoph Lameter } 772467c996cSMel Gorman 773467c996cSMel Gorman /* 774467c996cSMel Gorman * Output information about zones in @pgdat. 775467c996cSMel Gorman */ 776467c996cSMel Gorman static int zoneinfo_show(struct seq_file *m, void *arg) 777467c996cSMel Gorman { 778467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg; 779467c996cSMel Gorman walk_zones_in_node(m, pgdat, zoneinfo_show_print); 780f6ac2354SChristoph Lameter return 0; 781f6ac2354SChristoph Lameter } 782f6ac2354SChristoph Lameter 7835c9fe628SAlexey Dobriyan static const struct seq_operations zoneinfo_op = { 784f6ac2354SChristoph Lameter .start = frag_start, /* iterate over all zones. The same as in 785f6ac2354SChristoph Lameter * fragmentation. */ 786f6ac2354SChristoph Lameter .next = frag_next, 787f6ac2354SChristoph Lameter .stop = frag_stop, 788f6ac2354SChristoph Lameter .show = zoneinfo_show, 789f6ac2354SChristoph Lameter }; 790f6ac2354SChristoph Lameter 7915c9fe628SAlexey Dobriyan static int zoneinfo_open(struct inode *inode, struct file *file) 7925c9fe628SAlexey Dobriyan { 7935c9fe628SAlexey Dobriyan return seq_open(file, &zoneinfo_op); 7945c9fe628SAlexey Dobriyan } 7955c9fe628SAlexey Dobriyan 7965c9fe628SAlexey Dobriyan static const struct file_operations proc_zoneinfo_file_operations = { 7975c9fe628SAlexey Dobriyan .open = zoneinfo_open, 7985c9fe628SAlexey Dobriyan .read = seq_read, 7995c9fe628SAlexey Dobriyan .llseek = seq_lseek, 8005c9fe628SAlexey Dobriyan .release = seq_release, 8015c9fe628SAlexey Dobriyan }; 8025c9fe628SAlexey Dobriyan 803f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos) 804f6ac2354SChristoph Lameter { 8052244b95aSChristoph Lameter unsigned long *v; 806f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS 807f8891e5eSChristoph Lameter unsigned long *e; 808f8891e5eSChristoph Lameter #endif 8092244b95aSChristoph Lameter int i; 810f6ac2354SChristoph Lameter 811f6ac2354SChristoph Lameter if (*pos >= ARRAY_SIZE(vmstat_text)) 812f6ac2354SChristoph Lameter return NULL; 813f6ac2354SChristoph Lameter 814f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS 8152244b95aSChristoph Lameter v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) 816f8891e5eSChristoph Lameter + sizeof(struct vm_event_state), GFP_KERNEL); 817f8891e5eSChristoph Lameter #else 818f8891e5eSChristoph Lameter v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long), 819f8891e5eSChristoph Lameter GFP_KERNEL); 820f8891e5eSChristoph Lameter #endif 8212244b95aSChristoph Lameter m->private = v; 8222244b95aSChristoph Lameter if (!v) 823f6ac2354SChristoph Lameter return ERR_PTR(-ENOMEM); 8242244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 8252244b95aSChristoph Lameter v[i] = global_page_state(i); 826f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS 827f8891e5eSChristoph Lameter e = v + NR_VM_ZONE_STAT_ITEMS; 828f8891e5eSChristoph Lameter all_vm_events(e); 829f8891e5eSChristoph Lameter e[PGPGIN] /= 2; /* sectors -> kbytes */ 830f8891e5eSChristoph Lameter e[PGPGOUT] /= 2; 831f8891e5eSChristoph Lameter #endif 8322244b95aSChristoph Lameter return v + *pos; 833f6ac2354SChristoph Lameter } 834f6ac2354SChristoph Lameter 835f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos) 836f6ac2354SChristoph Lameter { 837f6ac2354SChristoph Lameter (*pos)++; 838f6ac2354SChristoph Lameter if (*pos >= ARRAY_SIZE(vmstat_text)) 839f6ac2354SChristoph Lameter return NULL; 840f6ac2354SChristoph Lameter return (unsigned long *)m->private + *pos; 841f6ac2354SChristoph Lameter } 842f6ac2354SChristoph Lameter 843f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg) 844f6ac2354SChristoph Lameter { 845f6ac2354SChristoph Lameter unsigned long *l = arg; 846f6ac2354SChristoph Lameter unsigned long off = l - (unsigned long *)m->private; 847f6ac2354SChristoph Lameter 848f6ac2354SChristoph Lameter seq_printf(m, "%s %lu\n", vmstat_text[off], *l); 849f6ac2354SChristoph Lameter return 0; 850f6ac2354SChristoph Lameter } 851f6ac2354SChristoph Lameter 852f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg) 853f6ac2354SChristoph Lameter { 854f6ac2354SChristoph Lameter kfree(m->private); 855f6ac2354SChristoph Lameter m->private = NULL; 856f6ac2354SChristoph Lameter } 857f6ac2354SChristoph Lameter 858b6aa44abSAlexey Dobriyan static const struct seq_operations vmstat_op = { 859f6ac2354SChristoph Lameter .start = vmstat_start, 860f6ac2354SChristoph Lameter .next = vmstat_next, 861f6ac2354SChristoph Lameter .stop = vmstat_stop, 862f6ac2354SChristoph Lameter .show = vmstat_show, 863f6ac2354SChristoph Lameter }; 864f6ac2354SChristoph Lameter 865b6aa44abSAlexey Dobriyan static int vmstat_open(struct inode *inode, struct file *file) 866b6aa44abSAlexey Dobriyan { 867b6aa44abSAlexey Dobriyan return seq_open(file, &vmstat_op); 868b6aa44abSAlexey Dobriyan } 869b6aa44abSAlexey Dobriyan 870b6aa44abSAlexey Dobriyan static const struct file_operations proc_vmstat_file_operations = { 871b6aa44abSAlexey Dobriyan .open = vmstat_open, 872b6aa44abSAlexey Dobriyan .read = seq_read, 873b6aa44abSAlexey Dobriyan .llseek = seq_lseek, 874b6aa44abSAlexey Dobriyan .release = seq_release, 875b6aa44abSAlexey Dobriyan }; 876f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */ 877f6ac2354SChristoph Lameter 878df9ecabaSChristoph Lameter #ifdef CONFIG_SMP 879d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work); 88077461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ; 881d1187ed2SChristoph Lameter 882d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w) 883d1187ed2SChristoph Lameter { 884d1187ed2SChristoph Lameter refresh_cpu_vm_stats(smp_processor_id()); 88577461ab3SChristoph Lameter schedule_delayed_work(&__get_cpu_var(vmstat_work), 88698f4ebb2SAnton Blanchard round_jiffies_relative(sysctl_stat_interval)); 887d1187ed2SChristoph Lameter } 888d1187ed2SChristoph Lameter 88942614fcdSRandy Dunlap static void __cpuinit start_cpu_timer(int cpu) 890d1187ed2SChristoph Lameter { 8911871e52cSTejun Heo struct delayed_work *work = &per_cpu(vmstat_work, cpu); 892d1187ed2SChristoph Lameter 8931871e52cSTejun Heo INIT_DELAYED_WORK_DEFERRABLE(work, vmstat_update); 8941871e52cSTejun Heo schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu)); 895d1187ed2SChristoph Lameter } 896d1187ed2SChristoph Lameter 897df9ecabaSChristoph Lameter /* 898df9ecabaSChristoph Lameter * Use the cpu notifier to insure that the thresholds are recalculated 899df9ecabaSChristoph Lameter * when necessary. 900df9ecabaSChristoph Lameter */ 901df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb, 902df9ecabaSChristoph Lameter unsigned long action, 903df9ecabaSChristoph Lameter void *hcpu) 904df9ecabaSChristoph Lameter { 905d1187ed2SChristoph Lameter long cpu = (long)hcpu; 906d1187ed2SChristoph Lameter 907df9ecabaSChristoph Lameter switch (action) { 908d1187ed2SChristoph Lameter case CPU_ONLINE: 909d1187ed2SChristoph Lameter case CPU_ONLINE_FROZEN: 910d1187ed2SChristoph Lameter start_cpu_timer(cpu); 911*ad596925SChristoph Lameter node_set_state(cpu_to_node(cpu), N_CPU); 912d1187ed2SChristoph Lameter break; 913d1187ed2SChristoph Lameter case CPU_DOWN_PREPARE: 914d1187ed2SChristoph Lameter case CPU_DOWN_PREPARE_FROZEN: 915d1187ed2SChristoph Lameter cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu)); 916d1187ed2SChristoph Lameter per_cpu(vmstat_work, cpu).work.func = NULL; 917d1187ed2SChristoph Lameter break; 918d1187ed2SChristoph Lameter case CPU_DOWN_FAILED: 919d1187ed2SChristoph Lameter case CPU_DOWN_FAILED_FROZEN: 920d1187ed2SChristoph Lameter start_cpu_timer(cpu); 921d1187ed2SChristoph Lameter break; 922df9ecabaSChristoph Lameter case CPU_DEAD: 9238bb78442SRafael J. Wysocki case CPU_DEAD_FROZEN: 924df9ecabaSChristoph Lameter refresh_zone_stat_thresholds(); 925df9ecabaSChristoph Lameter break; 926df9ecabaSChristoph Lameter default: 927df9ecabaSChristoph Lameter break; 928df9ecabaSChristoph Lameter } 929df9ecabaSChristoph Lameter return NOTIFY_OK; 930df9ecabaSChristoph Lameter } 931df9ecabaSChristoph Lameter 932df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier = 933df9ecabaSChristoph Lameter { &vmstat_cpuup_callback, NULL, 0 }; 9348f32f7e5SAlexey Dobriyan #endif 935df9ecabaSChristoph Lameter 936e2fc88d0SAdrian Bunk static int __init setup_vmstat(void) 937df9ecabaSChristoph Lameter { 9388f32f7e5SAlexey Dobriyan #ifdef CONFIG_SMP 939d1187ed2SChristoph Lameter int cpu; 940d1187ed2SChristoph Lameter 941df9ecabaSChristoph Lameter refresh_zone_stat_thresholds(); 942df9ecabaSChristoph Lameter register_cpu_notifier(&vmstat_notifier); 943d1187ed2SChristoph Lameter 944d1187ed2SChristoph Lameter for_each_online_cpu(cpu) 945d1187ed2SChristoph Lameter start_cpu_timer(cpu); 9468f32f7e5SAlexey Dobriyan #endif 9478f32f7e5SAlexey Dobriyan #ifdef CONFIG_PROC_FS 9488f32f7e5SAlexey Dobriyan proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); 94974e2e8e8SAlexey Dobriyan proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); 950b6aa44abSAlexey Dobriyan proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); 9515c9fe628SAlexey Dobriyan proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); 9528f32f7e5SAlexey Dobriyan #endif 953df9ecabaSChristoph Lameter return 0; 954df9ecabaSChristoph Lameter } 955df9ecabaSChristoph Lameter module_init(setup_vmstat) 956