Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24 /mm/vmstat.c

Filename:/mm/vmstat.c
Lines Added:207
Lines Deleted:100
Also changed in: (Previous) 2.6.24-rc8  2.6.24-rc7  2.6.24-rc6  2.6.24-rc5  2.6.24-rc4  2.6.24-rc3 
(Following) 2.6.24-git15  2.6.24-git16  2.6.24-git17  2.6.24-git18  2.6.24-git19  2.6.24-git20 

Location
[  2.6.24
  [  mm
     o  vmstat.c

Patch

diff --git a/mm/vmstat.c b/mm/vmstat.c
index c64d169..e8d846f 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -353,23 +353,6 @@ void refresh_cpu_vm_stats(int cpu)
    }
 }
 
-static void __refresh_cpu_vm_stats(void *dummy)
-{
-   refresh_cpu_vm_stats(smp_processor_id());
-}
-
-/*
- * Consolidate all counters.
- *
- * Note that the result is less inaccurate but still inaccurate
- * if concurrent processes are allowed to run.
- */
-void refresh_vm_stats(void)
-{
-   on_each_cpu(__refresh_cpu_vm_stats, NULL, 0, 1);
-}
-EXPORT_SYMBOL(refresh_vm_stats);
-
 #endif
 
 #ifdef CONFIG_NUMA
@@ -398,6 +381,13 @@ void zone_statistics(struct zonelist *zonelist, struct zone *z)
 
 #include <linux/seq_file.h>
 
+static char * const migratetype_names[MIGRATE_TYPES] = {
+   "Unmovable",
+   "Reclaimable",
+   "Movable",
+   "Reserve",
+};
+
 static void *frag_start(struct seq_file *m, loff_t *pos)
 {
    pg_data_t *pgdat;
@@ -422,28 +412,144 @@ static void frag_stop(struct seq_file *m, void *arg)
 {
 }
 
-/*
- * This walks the free areas for each zone.
- */
-static int frag_show(struct seq_file *m, void *arg)
+/* Walk all the zones in a node and print using a callback */
+static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
+      void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
 {
-   pg_data_t *pgdat = (pg_data_t *)arg;
    struct zone *zone;
    struct zone *node_zones = pgdat->node_zones;
    unsigned long flags;
-   int order;
 
    for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
       if (!populated_zone(zone))
          continue;
 
       spin_lock_irqsave(&zone->lock, flags);
-      seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
-      for (order = 0; order < MAX_ORDER; ++order)
-         seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
+      print(m, pgdat, zone);
       spin_unlock_irqrestore(&zone->lock, flags);
+   }
+}
+
+static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
+                  struct zone *zone)
+{
+   int order;
+
+   seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
+   for (order = 0; order < MAX_ORDER; ++order)
+      seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
+   seq_putc(m, '\n');
+}
+
+/*
+ * This walks the free areas for each zone.
+ */
+static int frag_show(struct seq_file *m, void *arg)
+{
+   pg_data_t *pgdat = (pg_data_t *)arg;
+   walk_zones_in_node(m, pgdat, frag_show_print);
+   return 0;
+}
+
+static void pagetypeinfo_showfree_print(struct seq_file *m,
+               pg_data_t *pgdat, struct zone *zone)
+{
+   int order, mtype;
+
+   for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
+      seq_printf(m, "Node %4d, zone %8s, type %12s ",
+               pgdat->node_id,
+               zone->name,
+               migratetype_names[mtype]);
+      for (order = 0; order < MAX_ORDER; ++order) {
+         unsigned long freecount = 0;
+         struct free_area *area;
+         struct list_head *curr;
+
+         area = &(zone->free_area[order]);
+
+         list_for_each(curr, &area->free_list[mtype])
+            freecount++;
+         seq_printf(m, "%6lu ", freecount);
+      }
       seq_putc(m, '\n');
    }
+}
+
+/* Print out the free pages at each order for each migatetype */
+static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
+{
+   int order;
+   pg_data_t *pgdat = (pg_data_t *)arg;
+
+   /* Print header */
+   seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
+   for (order = 0; order < MAX_ORDER; ++order)
+      seq_printf(m, "%6d ", order);
+   seq_putc(m, '\n');
+
+   walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
+
+   return 0;
+}
+
+static void pagetypeinfo_showblockcount_print(struct seq_file *m,
+               pg_data_t *pgdat, struct zone *zone)
+{
+   int mtype;
+   unsigned long pfn;
+   unsigned long start_pfn = zone->zone_start_pfn;
+   unsigned long end_pfn = start_pfn + zone->spanned_pages;
+   unsigned long count[MIGRATE_TYPES] = { 0, };
+
+   for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
+      struct page *page;
+
+      if (!pfn_valid(pfn))
+         continue;
+
+      page = pfn_to_page(pfn);
+      mtype = get_pageblock_migratetype(page);
+
+      count[mtype]++;
+   }
+
+   /* Print counts */
+   seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
+   for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
+      seq_printf(m, "%12lu ", count[mtype]);
+   seq_putc(m, '\n');
+}
+
+/* Print out the free pages at each order for each migratetype */
+static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
+{
+   int mtype;
+   pg_data_t *pgdat = (pg_data_t *)arg;
+
+   seq_printf(m, "\n%-23s", "Number of blocks type ");
+   for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
+      seq_printf(m, "%12s ", migratetype_names[mtype]);
+   seq_putc(m, '\n');
+   walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
+
+   return 0;
+}
+
+/*
+ * This prints out statistics in relation to grouping pages by mobility.
+ * It is expensive to collect so do not constantly read the file.
+ */
+static int pagetypeinfo_show(struct seq_file *m, void *arg)
+{
+   pg_data_t *pgdat = (pg_data_t *)arg;
+
+   seq_printf(m, "Page block order: %d\n", pageblock_order);
+   seq_printf(m, "Pages per block:  %lu\n", pageblock_nr_pages);
+   seq_putc(m, '\n');
+   pagetypeinfo_showfree(m, pgdat);
+   pagetypeinfo_showblockcount(m, pgdat);
+
    return 0;
 }
 
@@ -454,6 +560,13 @@ const struct seq_operations fragmentation_op = {
    .show   = frag_show,
 };
 
+const struct seq_operations pagetypeinfo_op = {
+   .start   = frag_start,
+   .next   = frag_next,
+   .stop   = frag_stop,
+   .show   = pagetypeinfo_show,
+};
+
 #ifdef CONFIG_ZONE_DMA
 #define TEXT_FOR_DMA(xx) xx "_dma",
 #else
@@ -532,84 +645,78 @@ static const char * const vmstat_text[] = {
 #endif
 };
 
-/*
- * Output information about zones in @pgdat.
- */
-static int zoneinfo_show(struct seq_file *m, void *arg)
+static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
+                     struct zone *zone)
 {
-   pg_data_t *pgdat = arg;
-   struct zone *zone;
-   struct zone *node_zones = pgdat->node_zones;
-   unsigned long flags;
-
-   for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
-      int i;
-
-      if (!populated_zone(zone))
-         continue;
-
-      spin_lock_irqsave(&zone->lock, flags);
-      seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
-      seq_printf(m,
-            "\n  pages free     %lu"
-            "\n        min      %lu"
-            "\n        low      %lu"
-            "\n        high     %lu"
-            "\n        scanned  %lu (a: %lu i: %lu)"
-            "\n        spanned  %lu"
-            "\n        present  %lu",
-            zone_page_state(zone, NR_FREE_PAGES),
-            zone->pages_min,
-            zone->pages_low,
-            zone->pages_high,
-            zone->pages_scanned,
-            zone->nr_scan_active, zone->nr_scan_inactive,
-            zone->spanned_pages,
-            zone->present_pages);
+   int i;
+   seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
+   seq_printf(m,
+         "\n  pages free     %lu"
+         "\n        min      %lu"
+         "\n        low      %lu"
+         "\n        high     %lu"
+         "\n        scanned  %lu (a: %lu i: %lu)"
+         "\n        spanned  %lu"
+         "\n        present  %lu",
+         zone_page_state(zone, NR_FREE_PAGES),
+         zone->pages_min,
+         zone->pages_low,
+         zone->pages_high,
+         zone->pages_scanned,
+         zone->nr_scan_active, zone->nr_scan_inactive,
+         zone->spanned_pages,
+         zone->present_pages);
 
-      for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-         seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
-               zone_page_state(zone, i));
-
-      seq_printf(m,
-            "\n        protection: (%lu",
-            zone->lowmem_reserve[0]);
-      for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
-         seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
-      seq_printf(m,
-            ")"
-            "\n  pagesets");
-      for_each_online_cpu(i) {
-         struct per_cpu_pageset *pageset;
-         int j;
-
-         pageset = zone_pcp(zone, i);
-         for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
-            seq_printf(m,
-                  "\n    cpu: %i pcp: %i"
-                  "\n              count: %i"
-                  "\n              high:  %i"
-                  "\n              batch: %i",
-                  i, j,
-                  pageset->pcp[j].count,
-                  pageset->pcp[j].high,
-                  pageset->pcp[j].batch);
+   for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+      seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
+            zone_page_state(zone, i));
+
+   seq_printf(m,
+         "\n        protection: (%lu",
+         zone->lowmem_reserve[0]);
+   for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
+      seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
+   seq_printf(m,
+         ")"
+         "\n  pagesets");
+   for_each_online_cpu(i) {
+      struct per_cpu_pageset *pageset;
+      int j;
+
+      pageset = zone_pcp(zone, i);
+      for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
+         seq_printf(m,
+               "\n    cpu: %i pcp: %i"
+               "\n              count: %i"
+               "\n              high:  %i"
+               "\n              batch: %i",
+               i, j,
+               pageset->pcp[j].count,
+               pageset->pcp[j].high,
+               pageset->pcp[j].batch);
          }
 #ifdef CONFIG_SMP
-         seq_printf(m, "\n  vm stats threshold: %d",
-               pageset->stat_threshold);
+      seq_printf(m, "\n  vm stats threshold: %d",
+            pageset->stat_threshold);
 #endif
-      }
-      seq_printf(m,
-            "\n  all_unreclaimable: %u"
-            "\n  prev_priority:     %i"
-            "\n  start_pfn:         %lu",
-            zone->all_unreclaimable,
-            zone->prev_priority,
-            zone->zone_start_pfn);
-      spin_unlock_irqrestore(&zone->lock, flags);
-      seq_putc(m, '\n');
    }
+   seq_printf(m,
+         "\n  all_unreclaimable: %u"
+         "\n  prev_priority:     %i"
+         "\n  start_pfn:         %lu",
+            zone_is_all_unreclaimable(zone),
+         zone->prev_priority,
+         zone->zone_start_pfn);
+   seq_putc(m, '\n');
+}
+
+/*
+ * Output information about zones in @pgdat.
+ */
+static int zoneinfo_show(struct seq_file *m, void *arg)
+{
+   pg_data_t *pgdat = (pg_data_t *)arg;
+   walk_zones_in_node(m, pgdat, zoneinfo_show_print);
    return 0;
 }
 
@@ -696,7 +803,7 @@ static void vmstat_update(struct work_struct *w)
       sysctl_stat_interval);
 }
 
-static void __devinit start_cpu_timer(int cpu)
+static void __cpuinit start_cpu_timer(int cpu)
 {
    struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
 
@@ -741,7 +848,7 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
 static struct notifier_block __cpuinitdata vmstat_notifier =
    { &vmstat_cpuup_callback, NULL, 0 };
 
-int __init setup_vmstat(void)
+static int __init setup_vmstat(void)
 {
    int cpu;
 


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.