perf kmem: Collect cross node allocation statistics
Show cross node memory allocations: # ./perf kmem SUMMARY ======= ... Cross node allocations: 0/3633 Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: linux-mm@kvack.org <linux-mm@kvack.org> LKML-Reference: <4B0B6E87.10906@cn.fujitsu.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Родитель
29b3e15289
Коммит
7d0d39459d
|
@ -36,6 +36,9 @@ static char default_sort_order[] = "frag,hit,bytes";
|
||||||
static char *cwd;
|
static char *cwd;
|
||||||
static int cwdlen;
|
static int cwdlen;
|
||||||
|
|
||||||
|
static int *cpunode_map;
|
||||||
|
static int max_cpu_num;
|
||||||
|
|
||||||
struct alloc_stat {
|
struct alloc_stat {
|
||||||
union {
|
union {
|
||||||
u64 call_site;
|
u64 call_site;
|
||||||
|
@ -54,12 +57,74 @@ static struct rb_root root_caller_stat;
|
||||||
static struct rb_root root_caller_sorted;
|
static struct rb_root root_caller_sorted;
|
||||||
|
|
||||||
static unsigned long total_requested, total_allocated;
|
static unsigned long total_requested, total_allocated;
|
||||||
|
static unsigned long nr_allocs, nr_cross_allocs;
|
||||||
|
|
||||||
struct raw_event_sample {
|
struct raw_event_sample {
|
||||||
u32 size;
|
u32 size;
|
||||||
char data[0];
|
char data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PATH_SYS_NODE "/sys/devices/system/node"
|
||||||
|
|
||||||
|
static void init_cpunode_map(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
|
||||||
|
if (!fp) {
|
||||||
|
max_cpu_num = 4096;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fscanf(fp, "%d", &max_cpu_num) < 1)
|
||||||
|
die("Failed to read 'kernel_max' from sysfs");
|
||||||
|
max_cpu_num++;
|
||||||
|
|
||||||
|
cpunode_map = calloc(max_cpu_num, sizeof(int));
|
||||||
|
if (!cpunode_map)
|
||||||
|
die("calloc");
|
||||||
|
for (i = 0; i < max_cpu_num; i++)
|
||||||
|
cpunode_map[i] = -1;
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_cpunode_map(void)
|
||||||
|
{
|
||||||
|
struct dirent *dent1, *dent2;
|
||||||
|
DIR *dir1, *dir2;
|
||||||
|
unsigned int cpu, mem;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
init_cpunode_map();
|
||||||
|
|
||||||
|
dir1 = opendir(PATH_SYS_NODE);
|
||||||
|
if (!dir1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
dent1 = readdir(dir1);
|
||||||
|
if (!dent1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (sscanf(dent1->d_name, "node%u", &mem) < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
|
||||||
|
dir2 = opendir(buf);
|
||||||
|
if (!dir2)
|
||||||
|
continue;
|
||||||
|
while (true) {
|
||||||
|
dent2 = readdir(dir2);
|
||||||
|
if (!dent2)
|
||||||
|
break;
|
||||||
|
if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
|
||||||
|
continue;
|
||||||
|
cpunode_map[cpu] = mem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
|
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
{
|
{
|
||||||
|
@ -157,15 +222,16 @@ static void insert_caller_stat(unsigned long call_site,
|
||||||
|
|
||||||
static void process_alloc_event(struct raw_event_sample *raw,
|
static void process_alloc_event(struct raw_event_sample *raw,
|
||||||
struct event *event,
|
struct event *event,
|
||||||
int cpu __used,
|
int cpu,
|
||||||
u64 timestamp __used,
|
u64 timestamp __used,
|
||||||
struct thread *thread __used,
|
struct thread *thread __used,
|
||||||
int node __used)
|
int node)
|
||||||
{
|
{
|
||||||
unsigned long call_site;
|
unsigned long call_site;
|
||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
int bytes_req;
|
int bytes_req;
|
||||||
int bytes_alloc;
|
int bytes_alloc;
|
||||||
|
int node1, node2;
|
||||||
|
|
||||||
ptr = raw_field_value(event, "ptr", raw->data);
|
ptr = raw_field_value(event, "ptr", raw->data);
|
||||||
call_site = raw_field_value(event, "call_site", raw->data);
|
call_site = raw_field_value(event, "call_site", raw->data);
|
||||||
|
@ -177,6 +243,14 @@ static void process_alloc_event(struct raw_event_sample *raw,
|
||||||
|
|
||||||
total_requested += bytes_req;
|
total_requested += bytes_req;
|
||||||
total_allocated += bytes_alloc;
|
total_allocated += bytes_alloc;
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
node1 = cpunode_map[cpu];
|
||||||
|
node2 = raw_field_value(event, "node", raw->data);
|
||||||
|
if (node1 != node2)
|
||||||
|
nr_cross_allocs++;
|
||||||
|
}
|
||||||
|
nr_allocs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_free_event(struct raw_event_sample *raw __used,
|
static void process_free_event(struct raw_event_sample *raw __used,
|
||||||
|
@ -359,6 +433,7 @@ static void print_summary(void)
|
||||||
total_allocated - total_requested);
|
total_allocated - total_requested);
|
||||||
printf("Internal fragmentation: %f%%\n",
|
printf("Internal fragmentation: %f%%\n",
|
||||||
fragmentation(total_requested, total_allocated));
|
fragmentation(total_requested, total_allocated));
|
||||||
|
printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_result(void)
|
static void print_result(void)
|
||||||
|
@ -685,6 +760,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used)
|
||||||
if (list_empty(&alloc_sort))
|
if (list_empty(&alloc_sort))
|
||||||
setup_sorting(&alloc_sort, default_sort_order);
|
setup_sorting(&alloc_sort, default_sort_order);
|
||||||
|
|
||||||
|
setup_cpunode_map();
|
||||||
|
|
||||||
return __cmd_kmem();
|
return __cmd_kmem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче