[PATCH] mm: add /proc/zoneinfo
Add /proc/zoneinfo file to display information about memory zones. Useful to analyze VM behaviour. Signed-off-by: Nikita Danilov <nikita@clusterfs.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
05b7438475
commit
295ab93497
|
@ -219,6 +219,19 @@ static struct file_operations fragmentation_file_operations = {
|
|||
.release = seq_release,
|
||||
};
|
||||
|
||||
extern struct seq_operations zoneinfo_op;
|
||||
static int zoneinfo_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &zoneinfo_op);
|
||||
}
|
||||
|
||||
static struct file_operations proc_zoneinfo_file_operations = {
|
||||
.open = zoneinfo_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int version_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
|
@ -589,6 +602,7 @@ void __init proc_misc_init(void)
|
|||
create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
|
||||
create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
|
||||
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
|
||||
create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
|
||||
create_seq_entry("diskstats", 0, &proc_diskstats_operations);
|
||||
#ifdef CONFIG_MODULES
|
||||
create_seq_entry("modules", 0, &proc_modules_operations);
|
||||
|
|
113
mm/page_alloc.c
113
mm/page_alloc.c
|
@ -1853,6 +1853,115 @@ struct seq_operations fragmentation_op = {
|
|||
.show = frag_show,
|
||||
};
|
||||
|
||||
/*
|
||||
* Output information about zones in @pgdat.
|
||||
*/
|
||||
static int zoneinfo_show(struct seq_file *m, void *arg)
|
||||
{
|
||||
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 (!zone->present_pages)
|
||||
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 active %lu"
|
||||
"\n inactive %lu"
|
||||
"\n scanned %lu (a: %lu i: %lu)"
|
||||
"\n spanned %lu"
|
||||
"\n present %lu",
|
||||
zone->free_pages,
|
||||
zone->pages_min,
|
||||
zone->pages_low,
|
||||
zone->pages_high,
|
||||
zone->nr_active,
|
||||
zone->nr_inactive,
|
||||
zone->pages_scanned,
|
||||
zone->nr_scan_active, zone->nr_scan_inactive,
|
||||
zone->spanned_pages,
|
||||
zone->present_pages);
|
||||
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 (i = 0; i < ARRAY_SIZE(zone->pageset); i++) {
|
||||
struct per_cpu_pageset *pageset;
|
||||
int j;
|
||||
|
||||
pageset = &zone->pageset[i];
|
||||
for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
|
||||
if (pageset->pcp[j].count)
|
||||
break;
|
||||
}
|
||||
if (j == ARRAY_SIZE(pageset->pcp))
|
||||
continue;
|
||||
for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
|
||||
seq_printf(m,
|
||||
"\n cpu: %i pcp: %i"
|
||||
"\n count: %i"
|
||||
"\n low: %i"
|
||||
"\n high: %i"
|
||||
"\n batch: %i",
|
||||
i, j,
|
||||
pageset->pcp[j].count,
|
||||
pageset->pcp[j].low,
|
||||
pageset->pcp[j].high,
|
||||
pageset->pcp[j].batch);
|
||||
}
|
||||
#ifdef CONFIG_NUMA
|
||||
seq_printf(m,
|
||||
"\n numa_hit: %lu"
|
||||
"\n numa_miss: %lu"
|
||||
"\n numa_foreign: %lu"
|
||||
"\n interleave_hit: %lu"
|
||||
"\n local_node: %lu"
|
||||
"\n other_node: %lu",
|
||||
pageset->numa_hit,
|
||||
pageset->numa_miss,
|
||||
pageset->numa_foreign,
|
||||
pageset->interleave_hit,
|
||||
pageset->local_node,
|
||||
pageset->other_node);
|
||||
#endif
|
||||
}
|
||||
seq_printf(m,
|
||||
"\n all_unreclaimable: %u"
|
||||
"\n prev_priority: %i"
|
||||
"\n temp_priority: %i"
|
||||
"\n start_pfn: %lu",
|
||||
zone->all_unreclaimable,
|
||||
zone->prev_priority,
|
||||
zone->temp_priority,
|
||||
zone->zone_start_pfn);
|
||||
spin_unlock_irqrestore(&zone->lock, flags);
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct seq_operations zoneinfo_op = {
|
||||
.start = frag_start, /* iterate over all zones. The same as in
|
||||
* fragmentation. */
|
||||
.next = frag_next,
|
||||
.stop = frag_stop,
|
||||
.show = zoneinfo_show,
|
||||
};
|
||||
|
||||
static char *vmstat_text[] = {
|
||||
"nr_dirty",
|
||||
"nr_writeback",
|
||||
|
@ -2058,10 +2167,10 @@ static void setup_per_zone_pages_min(void)
|
|||
min_pages = 128;
|
||||
zone->pages_min = min_pages;
|
||||
} else {
|
||||
/* if it's a lowmem zone, reserve a number of pages
|
||||
/* if it's a lowmem zone, reserve a number of pages
|
||||
* proportionate to the zone's size.
|
||||
*/
|
||||
zone->pages_min = (pages_min * zone->present_pages) /
|
||||
zone->pages_min = (pages_min * zone->present_pages) /
|
||||
lowmem_pages;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue