Commit b7fdef78 authored by Andrew Morton's avatar Andrew Morton Committed by Jaroslav Kysela

[PATCH] show_free_areas extensions

Ancient patch From Bill Irwin

The patch is intended to show improved information about where the
memory went during OOM-killing events.

- when the OOM killer fails and the system panics, calls
  show_free_areas()

- reorganize show_free_areas() to use for_each_zone()

- add per-cpu stats to show_free_areas()

- tags output from show_free_areas() with node and zone information
parent 3e9afe4c
...@@ -172,8 +172,10 @@ static void oom_kill(void) ...@@ -172,8 +172,10 @@ static void oom_kill(void)
p = select_bad_process(); p = select_bad_process();
/* Found nothing?!?! Either we hang forever, or we panic. */ /* Found nothing?!?! Either we hang forever, or we panic. */
if (p == NULL) if (!p) {
show_free_areas();
panic("Out of memory and no killable processes...\n"); panic("Out of memory and no killable processes...\n");
}
oom_kill_task(p); oom_kill_task(p);
/* /*
......
...@@ -694,6 +694,15 @@ unsigned int nr_free_highpages (void) ...@@ -694,6 +694,15 @@ unsigned int nr_free_highpages (void)
} }
#endif #endif
#ifdef CONFIG_NUMA
static void show_node(struct zone *zone)
{
printk("Node %d ", zone->zone_pgdat->node_id);
}
#else
#define show_node(zone) do { } while (0)
#endif
/* /*
* Accumulate the page_state information across all CPUs. * Accumulate the page_state information across all CPUs.
* The result is unavoidably approximate - it can change * The result is unavoidably approximate - it can change
...@@ -793,68 +802,91 @@ void si_meminfo_node(struct sysinfo *val, int nid) ...@@ -793,68 +802,91 @@ void si_meminfo_node(struct sysinfo *val, int nid)
*/ */
void show_free_areas(void) void show_free_areas(void)
{ {
pg_data_t *pgdat;
struct page_state ps; struct page_state ps;
int type; int cpu, temperature;
unsigned long active; unsigned long active;
unsigned long inactive; unsigned long inactive;
struct zone *zone;
for_each_zone(zone) {
show_node(zone);
printk("%s per-cpu:", zone->name);
if (!zone->present_pages) {
printk(" empty\n");
continue;
} else
printk("\n");
for (cpu = 0; cpu < NR_CPUS; ++cpu) {
struct per_cpu_pageset *pageset = zone->pageset + cpu;
for (temperature = 0; temperature < 2; temperature++)
printk("cpu %d %s: low %d, high %d, batch %d\n",
cpu,
temperature ? "cold" : "hot",
pageset->pcp[temperature].low,
pageset->pcp[temperature].high,
pageset->pcp[temperature].batch);
}
}
get_page_state(&ps); get_page_state(&ps);
get_zone_counts(&active, &inactive); get_zone_counts(&active, &inactive);
printk("Free pages: %6dkB (%6dkB HighMem)\n", printk("\nFree pages: %11ukB (%ukB HighMem)\n",
K(nr_free_pages()), K(nr_free_pages()),
K(nr_free_highpages())); K(nr_free_highpages()));
for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next) printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu free:%u\n",
for (type = 0; type < MAX_NR_ZONES; ++type) {
struct zone *zone = &pgdat->node_zones[type];
printk("Zone:%s"
" freepages:%6lukB"
" min:%6lukB"
" low:%6lukB"
" high:%6lukB"
" active:%6lukB"
" inactive:%6lukB"
"\n",
zone->name,
K(zone->free_pages),
K(zone->pages_min),
K(zone->pages_low),
K(zone->pages_high),
K(zone->nr_active),
K(zone->nr_inactive)
);
}
printk("( Active:%lu inactive:%lu dirty:%lu writeback:%lu free:%u )\n",
active, active,
inactive, inactive,
ps.nr_dirty, ps.nr_dirty,
ps.nr_writeback, ps.nr_writeback,
nr_free_pages()); nr_free_pages());
for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next) for_each_zone(zone) {
for (type = 0; type < MAX_NR_ZONES; type++) { show_node(zone);
struct list_head *elem; printk("%s"
struct zone *zone = &pgdat->node_zones[type]; " free:%lukB"
unsigned long nr, flags, order, total = 0; " min:%lukB"
" low:%lukB"
if (!zone->present_pages) " high:%lukB"
continue; " active:%lukB"
" inactive:%lukB"
spin_lock_irqsave(&zone->lock, flags); "\n",
for (order = 0; order < MAX_ORDER; order++) { zone->name,
nr = 0; K(zone->free_pages),
list_for_each(elem, &zone->free_area[order].free_list) K(zone->pages_min),
++nr; K(zone->pages_low),
total += nr << order; K(zone->pages_high),
printk("%lu*%lukB ", nr, K(1UL) << order); K(zone->nr_active),
} K(zone->nr_inactive)
spin_unlock_irqrestore(&zone->lock, flags); );
printk("= %lukB)\n", K(total)); }
for_each_zone(zone) {
struct list_head *elem;
unsigned long nr, flags, order, total = 0;
show_node(zone);
printk("%s: ", zone->name);
if (!zone->present_pages) {
printk("empty\n");
continue;
} }
spin_lock_irqsave(&zone->lock, flags);
for (order = 0; order < MAX_ORDER; order++) {
nr = 0;
list_for_each(elem, &zone->free_area[order].free_list)
++nr;
total += nr << order;
printk("%lu*%lukB ", nr, K(1UL) << order);
}
spin_unlock_irqrestore(&zone->lock, flags);
printk("= %lukB\n", K(total));
}
show_swap_cache_info(); show_swap_cache_info();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment