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