linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>,
	Jiri Olsa <jolsa@redhat.com>, LKML <linux-kernel@vger.kernel.org>,
	David Ahern <dsahern@gmail.com>, Minchan Kim <minchan@kernel.org>,
	Joonsoo Kim <js1304@gmail.com>
Subject: [PATCH 5/5] perf kmem: Add --live option for current allocation stat
Date: Mon, 23 Mar 2015 15:30:44 +0900	[thread overview]
Message-ID: <1427092244-22764-6-git-send-email-namhyung@kernel.org> (raw)
In-Reply-To: <1427092244-22764-1-git-send-email-namhyung@kernel.org>

Currently perf kmem 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.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/Documentation/perf-kmem.txt |   5 ++
 tools/perf/builtin-kmem.c              | 101 ++++++++++++++++++++++++++++++---
 2 files changed, 97 insertions(+), 9 deletions(-)

diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 0ebd9c8bfdbf..5a2d9aaf1933 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 fcd0e6f8fbdf..de82a1c579d9 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -243,6 +243,7 @@ static unsigned long nr_page_frees;
 static unsigned long nr_page_fails;
 static unsigned long nr_page_nomatch;
 
+static bool live_page;
 static struct perf_session *kmem_session;
 
 #define MAX_MIGRATE_TYPES  6
@@ -263,6 +264,7 @@ struct page_stat {
 	int 		nr_free;
 };
 
+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;
@@ -405,6 +407,44 @@ struct sort_dimension {
 static LIST_HEAD(page_alloc_sort_input);
 static LIST_HEAD(page_caller_sort_input);
 
+static struct page_stat *search_page_live_stat(struct page_stat *this,
+					       bool create)
+{
+	struct rb_node **node = &page_live_tree.rb_node;
+	struct rb_node *parent = NULL;
+	struct page_stat *data;
+
+	while (*node) {
+		s64 cmp;
+
+		parent = *node;
+		data = rb_entry(*node, struct page_stat, node);
+
+		cmp = data->page - this->page;
+		if (cmp < 0)
+			node = &parent->rb_left;
+		else if (cmp > 0)
+			node = &parent->rb_right;
+		else
+			return data;
+	}
+
+	if (!create)
+		return NULL;
+
+	data = zalloc(sizeof(*data));
+	if (data != NULL) {
+		data->page = this->page;
+		data->order = this->order;
+		data->migrate_type = this->migrate_type;
+		data->gfp_flags = this->gfp_flags;
+
+		rb_link_node(&data->node, parent, node);
+		rb_insert_color(&data->node, &page_live_tree);
+	}
+
+	return data;
+}
 static struct page_stat *search_page_alloc_stat(struct page_stat *this,
 						bool create)
 {
@@ -523,11 +563,14 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
 	callsite = find_callsite(evsel, sample);
 
 	/*
+	 * This is to find the current page (with correct gfp flags and
+	 * migrate_type) at free event.
+	 *
 	 * XXX: We'd better to use PFN instead of page pointer to deal
 	 * with things like partial freeing.  But AFAIK there's no way
 	 * to convert a pointer to struct page into PFN in userspace.
 	 */
-	stat = search_page_alloc_stat(&this, true);
+	stat = search_page_live_stat(&this, true);
 	if (stat == NULL) {
 		pr_err("cannot create page alloc stat\n");
 		return -1;
@@ -537,6 +580,18 @@ static int perf_evsel__process_page_alloc_event(struct perf_evsel *evsel,
 	stat->alloc_bytes += bytes;
 	stat->callsite = callsite;
 
+	if (!live_page) {
+		stat = search_page_alloc_stat(&this, true);
+		if (stat == NULL) {
+			pr_err("cannot create page alloc stat\n");
+			return -1;
+		}
+
+		stat->nr_alloc++;
+		stat->alloc_bytes += bytes;
+		stat->callsite = callsite;
+	}
+
 	this.callsite = callsite;
 	stat = search_page_caller_stat(&this, true);
 	if (stat == NULL) {
@@ -572,7 +627,7 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
 	nr_page_frees++;
 	total_page_free_bytes += bytes;
 
-	stat = search_page_alloc_stat(&this, false);
+	stat = search_page_live_stat(&this, false);
 	if (stat == NULL) {
 		pr_debug2("missing free at page %"PRIx64" (order: %d)\n",
 			  page, order);
@@ -583,17 +638,37 @@ static int perf_evsel__process_page_free_event(struct perf_evsel *evsel,
 		return 0;
 	}
 
-	stat->nr_free++;
-	stat->free_bytes += bytes;
-
 	this.callsite = stat->callsite;
 	this.gfp_flags = stat->gfp_flags;
 	this.migrate_type = stat->migrate_type;
 
+	rb_erase(&stat->node, &page_live_tree);
+	free(stat);
+
+	if (live_page) {
+		order_stats[this.order][this.migrate_type]--;
+	} else {
+		stat = search_page_alloc_stat(&this, false);
+		if (stat != NULL) {
+			stat->nr_free++;
+			stat->free_bytes += bytes;
+		}
+	}
+
 	stat = search_page_caller_stat(&this, false);
 	if (stat != NULL) {
 		stat->nr_free++;
 		stat->free_bytes += bytes;
+
+		if (live_page) {
+			stat->nr_alloc--;
+			stat->alloc_bytes -= bytes;
+
+			if (stat->nr_alloc == 0) {
+				rb_erase(&stat->node, &page_caller_tree);
+				free(stat);
+			}
+		}
 	}
 
 	return 0;
@@ -712,7 +787,8 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
 	struct machine *machine = &session->machines.host;
 
 	printf("\n%.105s\n", graph_dotted_line);
-	printf(" Page             | Total alloc (KB) | Hits      | Order | Migration type | GFP flags | Callsite\n");
+	printf(" Page             | %5s alloc (KB) | Hits      | Order | Migration type | GFP flags | Callsite\n",
+	       live_page ? "Live" : "Total");
 	printf("%.105s\n", graph_dotted_line);
 
 	while (next && n_lines--) {
@@ -752,7 +828,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 | Migration type | GFP flags | Callsite\n");
+	printf(" %5s alloc (KB) | Hits      | Order | Migration type | GFP flags | Callsite\n",
+	       live_page ? "Live" : "Total");
 	printf("%.105s\n", graph_dotted_line);
 
 	while (next && n_lines--) {
@@ -977,8 +1054,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);
 	}
@@ -1509,6 +1591,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 };
-- 
2.3.3


  parent reply	other threads:[~2015-03-23  6:37 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-23  6:30 [PATCHSET 0/5] perf kmem: Implement page allocation analysis (v3) Namhyung Kim
2015-03-23  6:30 ` [PATCH 1/5] perf kmem: Print big numbers using thousands' group Namhyung Kim
2015-03-23 14:08   ` Arnaldo Carvalho de Melo
2015-03-23 23:35     ` Namhyung Kim
2015-03-24 16:31   ` [tip:perf/core] " tip-bot for Namhyung Kim
2015-03-23  6:30 ` [PATCH 2/5] perf kmem: Analyze page allocator events also Namhyung Kim
2015-03-23 17:32   ` Joonsoo Kim
2015-03-24  0:18     ` Namhyung Kim
2015-03-24  5:26       ` Joonsoo Kim
2015-03-24  6:05         ` Namhyung Kim
2015-03-24  7:08         ` Ingo Molnar
2015-03-24 13:17           ` Namhyung Kim
2015-03-23  6:30 ` [PATCH 3/5] perf kmem: Implement stat --page --caller Namhyung Kim
2015-03-23  6:30 ` [PATCH 4/5] perf kmem: Support sort keys on page analysis Namhyung Kim
2015-03-23 17:27   ` Joonsoo Kim
2015-03-24  0:20     ` Namhyung Kim
2015-03-23  6:30 ` Namhyung Kim [this message]
2015-03-23 17:23 ` [PATCHSET 0/5] perf kmem: Implement page allocation analysis (v3) Joonsoo Kim
2015-03-23 23:57   ` Namhyung Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1427092244-22764-6-git-send-email-namhyung@kernel.org \
    --to=namhyung@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=dsahern@gmail.com \
    --cc=jolsa@redhat.com \
    --cc=js1304@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=minchan@kernel.org \
    --cc=mingo@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).