Commit 6633401d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] numa api: Add statistics

From: Andi Kleen <ak@suse.de>

Add NUMA hit/miss statistics to page allocation and display them in sysfs.

This is not 100% required for NUMA API, but without this it is very

The overhead is quite low because all counters are per CPU and only happens
when CONFIG_NUMA is defined.
parent e52c02f7
...@@ -52,6 +52,14 @@ struct per_cpu_pages { ...@@ -52,6 +52,14 @@ struct per_cpu_pages {
struct per_cpu_pageset { struct per_cpu_pageset {
struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */ struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */
#ifdef CONFIG_NUMA
unsigned long numa_hit; /* allocated in intended node */
unsigned long numa_miss; /* allocated in non intended node */
unsigned long numa_foreign; /* was intended here, hit elsewhere */
unsigned long interleave_hit; /* interleaver prefered this zone */
unsigned long local_node; /* allocation from local node */
unsigned long other_node; /* allocation from other node */
#endif
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
#define ZONE_DMA 0 #define ZONE_DMA 0
......
...@@ -460,6 +460,32 @@ void drain_local_pages(void) ...@@ -460,6 +460,32 @@ void drain_local_pages(void)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static void zone_statistics(struct zonelist *zonelist, struct zone *z)
{
#ifdef CONFIG_NUMA
unsigned long flags;
int cpu;
pg_data_t *pg = z->zone_pgdat;
pg_data_t *orig = zonelist->zones[0]->zone_pgdat;
struct per_cpu_pageset *p;
local_irq_save(flags);
cpu = smp_processor_id();
p = &z->pageset[cpu];
if (pg == orig) {
z->pageset[cpu].numa_hit++;
} else {
p->numa_miss++;
zonelist->zones[0]->pageset[cpu].numa_foreign++;
}
if (pg == NODE_DATA(numa_node_id()))
p->local_node++;
else
p->other_node++;
local_irq_restore(flags);
#endif
}
/* /*
* Free a 0-order page * Free a 0-order page
*/ */
...@@ -593,8 +619,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, ...@@ -593,8 +619,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
if (z->free_pages >= min || if (z->free_pages >= min ||
(!wait && z->free_pages >= z->pages_high)) { (!wait && z->free_pages >= z->pages_high)) {
page = buffered_rmqueue(z, order, gfp_mask); page = buffered_rmqueue(z, order, gfp_mask);
if (page) if (page) {
zone_statistics(zonelist, z);
goto got_pg; goto got_pg;
}
} }
} }
...@@ -616,8 +644,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, ...@@ -616,8 +644,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
if (z->free_pages >= min || if (z->free_pages >= min ||
(!wait && z->free_pages >= z->pages_high)) { (!wait && z->free_pages >= z->pages_high)) {
page = buffered_rmqueue(z, order, gfp_mask); page = buffered_rmqueue(z, order, gfp_mask);
if (page) if (page) {
zone_statistics(zonelist, z);
goto got_pg; goto got_pg;
}
} }
} }
...@@ -630,8 +660,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, ...@@ -630,8 +660,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
struct zone *z = zones[i]; struct zone *z = zones[i];
page = buffered_rmqueue(z, order, gfp_mask); page = buffered_rmqueue(z, order, gfp_mask);
if (page) if (page) {
zone_statistics(zonelist, z);
goto got_pg; goto got_pg;
}
} }
goto nopage; goto nopage;
} }
...@@ -658,8 +690,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, ...@@ -658,8 +690,10 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
if (z->free_pages >= min || if (z->free_pages >= min ||
(!wait && z->free_pages >= z->pages_high)) { (!wait && z->free_pages >= z->pages_high)) {
page = buffered_rmqueue(z, order, gfp_mask); page = buffered_rmqueue(z, order, gfp_mask);
if (page) if (page) {
zone_statistics(zonelist, z);
goto got_pg; goto got_pg;
}
} }
} }
......
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