[tip:perf/core] perf kmem: Add --live option for current allocation stat

From: tip-bot for Namhyung Kim
Date: Tue May 05 2015 - 23:15:37 EST


Commit-ID: 2a7ef02c9ca0172cd48945407893f38c2438e754
Gitweb: http://git.kernel.org/tip/2a7ef02c9ca0172cd48945407893f38c2438e754
Author: Namhyung Kim <namhyung@xxxxxxxxxx>
AuthorDate: Tue, 21 Apr 2015 13:55:04 +0900
Committer: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
CommitDate: Mon, 4 May 2015 13:34:47 -0300

perf kmem: Add --live option for current allocation stat

Currently 'perf kmem stat --page' shows total (page) allocation stat by
default, but sometimes one might want to see live (total alloc-only)
requests/pages only. The new --live option does this by subtracting freed
allocation from the stat.

E.g.:

# perf kmem stat --page

SUMMARY (page allocator)
========================
Total allocation requests : 988,858 [ 4,045,368 KB ]
Total free requests : 886,484 [ 3,624,996 KB ]

Total alloc+freed requests : 885,969 [ 3,622,628 KB ]
Total alloc-only requests : 102,889 [ 422,740 KB ]
Total free-only requests : 515 [ 2,368 KB ]

Total allocation failures : 0 [ 0 KB ]

Order Unmovable Reclaimable Movable Reserved CMA/Isolated
----- ------------ ------------ ------------ ------------ ------------
0 172,173 3,083 806,686 . .
1 284 . . . .
2 6,124 58 . . .
3 114 335 . . .
4 . . . . .
5 . . . . .
6 . . . . .
7 . . . . .
8 . . . . .
9 . . 1 . .
10 . . . . .
# perf kmem stat --page --live

SUMMARY (page allocator)
========================
Total allocation requests : 988,858 [ 4,045,368 KB ]
Total free requests : 886,484 [ 3,624,996 KB ]

Total alloc+freed requests : 885,969 [ 3,622,628 KB ]
Total alloc-only requests : 102,889 [ 422,740 KB ]
Total free-only requests : 515 [ 2,368 KB ]

Total allocation failures : 0 [ 0 KB ]

Order Unmovable Reclaimable Movable Reserved CMA/Isolated
----- ------------ ------------ ------------ ------------ ------------
0 2,214 3,025 97,156 . .
1 59 . . . .
2 19 58 . . .
3 23 335 . . .
4 . . . . .
5 . . . . .
6 . . . . .
7 . . . . .
8 . . . . .
9 . . . . .
10 . . . . .
#

Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
Acked-by: Pekka Enberg <penberg@xxxxxxxxxx>
Tested-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: David Ahern <dsahern@xxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Joonsoo Kim <js1304@xxxxxxxxx>
Cc: Minchan Kim <minchan@xxxxxxxxxx>
Cc: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Cc: linux-mm@xxxxxxxxx
Link: http://lkml.kernel.org/r/1429592107-1807-4-git-send-email-namhyung@xxxxxxxxxx
[ Added examples to the changeset log ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/perf/Documentation/perf-kmem.txt | 5 ++
tools/perf/builtin-kmem.c | 110 ++++++++++++++++++++-------------
2 files changed, 73 insertions(+), 42 deletions(-)

diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 69e1812..ff0f433 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -56,6 +56,11 @@ OPTIONS
--page::
Analyze page allocator events

+--live::
+ Show live page stat. The perf kmem shows total allocation stat by
+ default, but this option shows live (currently allocated) pages
+ instead. (This option works with --page option only)
+
SEE ALSO
--------
linkperf:perf-record[1]
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0393a7f..7ead942 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -244,6 +244,7 @@ static unsigned long nr_page_fails;
static unsigned long nr_page_nomatch;

static bool use_pfn;
+static bool live_page;
static struct perf_session *kmem_session;

#define MAX_MIGRATE_TYPES 6
@@ -264,7 +265,7 @@ struct page_stat {
int nr_free;
};

-static struct rb_root page_tree;
+static struct rb_root page_live_tree;
static struct rb_root page_alloc_tree;
static struct rb_root page_alloc_sorted;
static struct rb_root page_caller_tree;
@@ -403,10 +404,19 @@ out:
return sample->ip;
}

+struct sort_dimension {
+ const char name[20];
+ sort_fn_t cmp;
+ struct list_head list;
+};
+
+static LIST_HEAD(page_alloc_sort_input);
+static LIST_HEAD(page_caller_sort_input);
+
static struct page_stat *
-__page_stat__findnew_page(u64 page, bool create)
+__page_stat__findnew_page(struct page_stat *pstat, bool create)
{
- struct rb_node **node = &page_tree.rb_node;
+ struct rb_node **node = &page_live_tree.rb_node;
struct rb_node *parent = NULL;
struct page_stat *data;

@@ -416,7 +426,7 @@ __page_stat__findnew_page(u64 page, bool create)
parent = *node;
data = rb_entry(*node, struct page_stat, node);

- cmp = data->page - page;
+ cmp = data->page - pstat->page;
if (cmp < 0)
node = &parent->rb_left;
else if (cmp > 0)
@@ -430,34 +440,28 @@ __page_stat__findnew_page(u64 page, bool create)

data = zalloc(sizeof(*data));
if (data != NULL) {
- data->page = page;
+ data->page = pstat->page;
+ data->order = pstat->order;
+ data->gfp_flags = pstat->gfp_flags;
+ data->migrate_type = pstat->migrate_type;

rb_link_node(&data->node, parent, node);
- rb_insert_color(&data->node, &page_tree);
+ rb_insert_color(&data->node, &page_live_tree);
}

return data;
}

-static struct page_stat *page_stat__find_page(u64 page)
+static struct page_stat *page_stat__find_page(struct page_stat *pstat)
{
- return __page_stat__findnew_page(page, false);
+ return __page_stat__findnew_page(pstat, false);
}

-static struct page_stat *page_stat__findnew_page(u64 page)
+static struct page_stat *page_stat__findnew_page(struct page_stat *pstat)
{
- return __page_stat__findnew_page(page, true);
+ return __page_stat__findnew_page(pstat, true);
}

-struct sort_dimension {
- const char name[20];
- sort_fn_t cmp;
- struct list_head list;
-};
-
-static LIST_HEAD(page_alloc_sort_input);
-static LIST_HEAD(page_caller_sort_input);
-
static struct page_stat *
__page_stat__findnew_alloc(struct page_stat *pstat, bool create)
{
@@ -615,17 +619,8 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
* This is to find the current page (with correct gfp flags and
* migrate type) at free event.
*/
- pstat = page_stat__findnew_page(page);
- if (pstat == NULL)
- return -ENOMEM;
-
- pstat->order = order;
- pstat->gfp_flags = gfp_flags;
- pstat->migrate_type = migrate_type;
- pstat->callsite = callsite;
-
this.page = page;
- pstat = page_stat__findnew_alloc(&this);
+ pstat = page_stat__findnew_page(&this);
if (pstat == NULL)
return -ENOMEM;

@@ -633,6 +628,16 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
pstat->alloc_bytes += bytes;
pstat->callsite = callsite;

+ if (!live_page) {
+ pstat = page_stat__findnew_alloc(&this);
+ if (pstat == NULL)
+ return -ENOMEM;
+
+ pstat->nr_alloc++;
+ pstat->alloc_bytes += bytes;
+ pstat->callsite = callsite;
+ }
+
this.callsite = callsite;
pstat = page_stat__findnew_caller(&this);
if (pstat == NULL)
@@ -665,7 +670,8 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
nr_page_frees++;
total_page_free_bytes += bytes;

- pstat = page_stat__find_page(page);
+ this.page = page;
+ pstat = page_stat__find_page(&this);
if (pstat == NULL) {
pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
page, order);
@@ -676,20 +682,23 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
return 0;
}

- this.page = page;
this.gfp_flags = pstat->gfp_flags;
this.migrate_type = pstat->migrate_type;
this.callsite = pstat->callsite;

- rb_erase(&pstat->node, &page_tree);
+ rb_erase(&pstat->node, &page_live_tree);
free(pstat);

- pstat = page_stat__find_alloc(&this);
- if (pstat == NULL)
- return -ENOENT;
+ if (live_page) {
+ order_stats[this.order][this.migrate_type]--;
+ } else {
+ pstat = page_stat__find_alloc(&this);
+ if (pstat == NULL)
+ return -ENOMEM;

- pstat->nr_free++;
- pstat->free_bytes += bytes;
+ pstat->nr_free++;
+ pstat->free_bytes += bytes;
+ }

pstat = page_stat__find_caller(&this);
if (pstat == NULL)
@@ -698,6 +707,16 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
pstat->nr_free++;
pstat->free_bytes += bytes;

+ if (live_page) {
+ pstat->nr_alloc--;
+ pstat->alloc_bytes -= bytes;
+
+ if (pstat->nr_alloc == 0) {
+ rb_erase(&pstat->node, &page_caller_tree);
+ free(pstat);
+ }
+ }
+
return 0;
}

@@ -815,8 +834,8 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
const char *format;

printf("\n%.105s\n", graph_dotted_line);
- printf(" %-16s | Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
- use_pfn ? "PFN" : "Page");
+ printf(" %-16s | %5s alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
+ use_pfn ? "PFN" : "Page", live_page ? "Live" : "Total");
printf("%.105s\n", graph_dotted_line);

if (use_pfn)
@@ -860,7 +879,8 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines
struct machine *machine = &session->machines.host;

printf("\n%.105s\n", graph_dotted_line);
- printf(" Total alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n");
+ printf(" %5s alloc (KB) | Hits | Order | Mig.type | GFP flags | Callsite\n",
+ live_page ? "Live" : "Total");
printf("%.105s\n", graph_dotted_line);

while (next && n_lines--) {
@@ -1085,8 +1105,13 @@ static void sort_result(void)
&slab_caller_sort);
}
if (kmem_page) {
- __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
- &page_alloc_sort);
+ if (live_page)
+ __sort_page_result(&page_live_tree, &page_alloc_sorted,
+ &page_alloc_sort);
+ else
+ __sort_page_result(&page_alloc_tree, &page_alloc_sorted,
+ &page_alloc_sort);
+
__sort_page_result(&page_caller_tree, &page_caller_sorted,
&page_caller_sort);
}
@@ -1630,6 +1655,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
parse_slab_opt),
OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
parse_page_opt),
+ OPT_BOOLEAN(0, "live", &live_page, "Show live page stat"),
OPT_END()
};
const char *const kmem_subcommands[] = { "record", "stat", NULL };
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/