mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>,
	Andrew Morton <akpm@linux-foundation.org>,
	Frederic Weisbecker <fweisbec@gmail.com>
Subject: [PATCH 05/16] ftrace: Allocate the mcount record pages as groups
Date: Wed, 21 Dec 2011 07:36:29 -0500	[thread overview]
Message-ID: <20111221123804.992614557@goodmis.org> (raw)
In-Reply-To: <20111221123624.193898256@goodmis.org>

[-- Attachment #1: Type: text/plain, Size: 7465 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Allocate the mcount record pages as a group of pages as big
as can be allocated and waste no more than a single page.

Grouping the mcount pages as much as possible helps with cache
locality, as we do not need to redirect with descriptors as we
cross from page to page. It also allows us to do more with the
records later on (sort them with bigger benefits).

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c |  179 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 128 insertions(+), 51 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index be6888f..2e72188 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -983,12 +983,13 @@ static DEFINE_MUTEX(ftrace_regex_lock);
 
 struct ftrace_page {
 	struct ftrace_page	*next;
+	struct dyn_ftrace	*records;
 	int			index;
-	struct dyn_ftrace	records[];
+	int			size;
 };
 
-#define ENTRIES_PER_PAGE \
-  ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace))
+#define ENTRY_SIZE sizeof(struct dyn_ftrace)
+#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
 
 /* estimate from running different kernels */
 #define NR_TO_INIT		10000
@@ -1421,14 +1422,10 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
 
 static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
 {
-	if (ftrace_pages->index == ENTRIES_PER_PAGE) {
-		if (!ftrace_pages->next) {
-			/* allocate another page */
-			ftrace_pages->next =
-				(void *)get_zeroed_page(GFP_KERNEL);
-			if (!ftrace_pages->next)
-				return NULL;
-		}
+	if (ftrace_pages->index == ftrace_pages->size) {
+		/* We should have allocated enough */
+		if (WARN_ON(!ftrace_pages->next))
+			return NULL;
 		ftrace_pages = ftrace_pages->next;
 	}
 
@@ -2005,47 +2002,106 @@ static int ftrace_update_code(struct module *mod)
 	return 0;
 }
 
-static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
+static int ftrace_allocate_records(struct ftrace_page *pg, int count)
 {
-	struct ftrace_page *pg;
+	int order;
 	int cnt;
-	int i;
 
-	/* allocate a few pages */
-	ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
-	if (!ftrace_pages_start)
-		return -1;
+	if (WARN_ON(!count))
+		return -EINVAL;
+
+	order = get_count_order(DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
 
 	/*
-	 * Allocate a few more pages.
-	 *
-	 * TODO: have some parser search vmlinux before
-	 *   final linking to find all calls to ftrace.
-	 *   Then we can:
-	 *    a) know how many pages to allocate.
-	 *     and/or
-	 *    b) set up the table then.
-	 *
-	 *  The dynamic code is still necessary for
-	 *  modules.
+	 * We want to fill as much as possible. No more than a page
+	 * may be empty.
 	 */
+	while ((PAGE_SIZE << order) / ENTRY_SIZE >= count + ENTRIES_PER_PAGE)
+		order--;
 
-	pg = ftrace_pages = ftrace_pages_start;
+ again:
+	pg->records = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
 
-	cnt = num_to_init / ENTRIES_PER_PAGE;
-	pr_info("ftrace: allocating %ld entries in %d pages\n",
-		num_to_init, cnt + 1);
+	if (!pg->records) {
+		/* if we can't allocate this size, try something smaller */
+		if (!order)
+			return -ENOMEM;
+		order >>= 1;
+		goto again;
+	}
 
-	for (i = 0; i < cnt; i++) {
-		pg->next = (void *)get_zeroed_page(GFP_KERNEL);
+	cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
+	pg->size = cnt;
 
-		/* If we fail, we'll try later anyway */
-		if (!pg->next)
+	if (cnt > count)
+		cnt = count;
+
+	return cnt;
+}
+
+static struct ftrace_page *
+ftrace_allocate_pages(unsigned long num_to_init)
+{
+	struct ftrace_page *start_pg;
+	struct ftrace_page *pg;
+	int order;
+	int cnt;
+
+	if (!num_to_init)
+		return 0;
+
+	start_pg = pg = kzalloc(sizeof(*pg), GFP_KERNEL);
+	if (!pg)
+		return NULL;
+
+	/*
+	 * Try to allocate as much as possible in one continues
+	 * location that fills in all of the space. We want to
+	 * waste as little space as possible.
+	 */
+	for (;;) {
+		cnt = ftrace_allocate_records(pg, num_to_init);
+		if (cnt < 0)
+			goto free_pages;
+
+		num_to_init -= cnt;
+		if (!num_to_init)
 			break;
 
+		pg->next = kzalloc(sizeof(*pg), GFP_KERNEL);
+		if (!pg->next)
+			goto free_pages;
+
 		pg = pg->next;
 	}
 
+	return start_pg;
+
+ free_pages:
+	while (start_pg) {
+		order = get_count_order(pg->size / ENTRIES_PER_PAGE);
+		free_pages((unsigned long)pg->records, order);
+		start_pg = pg->next;
+		kfree(pg);
+		pg = start_pg;
+	}
+	pr_info("ftrace: FAILED to allocate memory for functions\n");
+	return NULL;
+}
+
+static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
+{
+	int cnt;
+
+	if (!num_to_init) {
+		pr_info("ftrace: No functions to be traced?\n");
+		return -1;
+	}
+
+	cnt = num_to_init / ENTRIES_PER_PAGE;
+	pr_info("ftrace: allocating %ld entries in %d pages\n",
+		num_to_init, cnt + 1);
+
 	return 0;
 }
 
@@ -3520,30 +3576,45 @@ static int ftrace_process_locs(struct module *mod,
 			       unsigned long *start,
 			       unsigned long *end)
 {
+	struct ftrace_page *pg;
+	unsigned long count;
 	unsigned long *p;
 	unsigned long addr;
 	unsigned long flags = 0; /* Shut up gcc */
+	int ret = -ENOMEM;
+
+	count = end - start;
+
+	if (!count)
+		return 0;
+
+	pg = ftrace_allocate_pages(count);
+	if (!pg)
+		return -ENOMEM;
 
 	mutex_lock(&ftrace_lock);
+
 	/*
 	 * Core and each module needs their own pages, as
 	 * modules will free them when they are removed.
 	 * Force a new page to be allocated for modules.
 	 */
-	if (mod) {
+	if (!mod) {
+		WARN_ON(ftrace_pages || ftrace_pages_start);
+		/* First initialization */
+		ftrace_pages = ftrace_pages_start = pg;
+	} else {
 		if (!ftrace_pages)
-			return -ENOMEM;
+			goto out;
 
-		/*
-		 * If the last page was full, it will be
-		 * allocated anyway.
-		 */
-		if (ftrace_pages->index != ENTRIES_PER_PAGE) {
-			ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
-			if (!ftrace_pages->next)
-				return -ENOMEM;
-			ftrace_pages = ftrace_pages->next;
+		if (WARN_ON(ftrace_pages->next)) {
+			/* Hmm, we have free pages? */
+			while (ftrace_pages->next)
+				ftrace_pages = ftrace_pages->next;
 		}
+
+		ftrace_pages->next = pg;
+		ftrace_pages = pg;
 	}
 
 	p = start;
@@ -3557,7 +3628,8 @@ static int ftrace_process_locs(struct module *mod,
 		 */
 		if (!addr)
 			continue;
-		ftrace_record_ip(addr);
+		if (!ftrace_record_ip(addr))
+			break;
 	}
 
 	/*
@@ -3573,9 +3645,11 @@ static int ftrace_process_locs(struct module *mod,
 	ftrace_update_code(mod);
 	if (!mod)
 		local_irq_restore(flags);
+	ret = 0;
+ out:
 	mutex_unlock(&ftrace_lock);
 
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_MODULES
@@ -3587,6 +3661,7 @@ void ftrace_release_mod(struct module *mod)
 	struct dyn_ftrace *rec;
 	struct ftrace_page **last_pg;
 	struct ftrace_page *pg;
+	int order;
 
 	mutex_lock(&ftrace_lock);
 
@@ -3613,7 +3688,9 @@ void ftrace_release_mod(struct module *mod)
 				ftrace_pages = next_to_ftrace_page(last_pg);
 
 			*last_pg = pg->next;
-			free_page((unsigned long)pg);
+			order = get_count_order(pg->size / ENTRIES_PER_PAGE);
+			free_pages((unsigned long)pg->records, order);
+			kfree(pg);
 		} else
 			last_pg = &pg->next;
 	}
-- 
1.7.7.3



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

  parent reply	other threads:[~2011-12-21 12:40 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-21 12:36 [PATCH 00/16] [GIT PULL] tracing: fixes/cleanups, no stop-machine, update stack tracer Steven Rostedt
2011-12-21 12:36 ` [PATCH 01/16] ftrace: Fix unregister ftrace_ops accounting Steven Rostedt
2011-12-21 12:36 ` [PATCH 02/16] ftrace: Do not function trace inlined functions Steven Rostedt
2011-12-21 12:36 ` [PATCH 03/16] ftrace: Allow archs to modify code without stop machine Steven Rostedt
2011-12-21 12:36 ` [PATCH 04/16] ftrace: Remove usage of "freed" records Steven Rostedt
2011-12-21 12:36 ` Steven Rostedt [this message]
2011-12-21 12:36 ` [PATCH 06/16] ftrace: Replace record newlist with record page list Steven Rostedt
2011-12-21 12:36 ` [PATCH 07/16] ftrace: Sort the mcount records on each page Steven Rostedt
2011-12-21 12:36 ` [PATCH 08/16] ftrace: Use bsearch to find record ip Steven Rostedt
2011-12-21 12:36 ` [PATCH 09/16] ftrace: Fix ftrace hash record update with notrace Steven Rostedt
2011-12-21 12:36 ` [PATCH 10/16] ftrace: Create ftrace_hash_empty() helper routine Steven Rostedt
2011-12-21 12:36 ` [PATCH 11/16] ftrace: Allow other users of function tracing to use the output listing Steven Rostedt
2011-12-21 12:36 ` [PATCH 12/16] ftrace: Decouple hash items from showing filtered functions Steven Rostedt
2011-12-21 12:36 ` [PATCH 13/16] tracing: Have stack_tracer use a separate list of functions Steven Rostedt
2011-12-21 12:36 ` [PATCH 14/16] ftrace: Allow access to the boot time function enabling Steven Rostedt
2011-12-21 12:36 ` [PATCH 15/16] tracing: Have stack tracing set filtered functions at boot Steven Rostedt
2011-12-21 12:36 ` [PATCH 16/16] tracing: Factorize filter creation Steven Rostedt
2012-01-01 18:09 ` [PATCH 00/16] [GIT PULL] tracing: fixes/cleanups, no stop-machine, update stack tracer Ingo Molnar
2012-01-02 10:58   ` Ingo Molnar
2012-01-02 13:48     ` Ingo Molnar
2012-01-02 15:10       ` Ingo Molnar
2012-01-04  0:02       ` Steven Rostedt
2012-01-04  0:12         ` Steven Rostedt
2012-01-04  5:01           ` Steven Rostedt
2012-01-04 14:11             ` Ingo Molnar
2012-01-04 17:05               ` Steven Rostedt
2012-01-04 18:39                 ` Ingo Molnar
2012-01-05  9:19                 ` Ingo Molnar
2012-01-05 11:46                   ` Steven Rostedt
2012-01-05 12:16                     ` Steven Rostedt
2012-01-06  4:58                       ` Steven Rostedt
2012-01-06  8:51                         ` Ingo Molnar
2012-01-06 12:10                           ` Steven Rostedt
2012-01-06 15:29                             ` Steven Rostedt
2012-01-07 12:20                             ` Ingo Molnar
2012-01-07 12:25                     ` Ingo Molnar
2012-01-07 22:32                       ` Steven Rostedt
2012-01-08 11:38                         ` Ingo Molnar
2012-01-02 19:33   ` Steven Rostedt
2012-01-06  5:04   ` Steven Rostedt

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=20111221123804.992614557@goodmis.org \
    --to=rostedt@goodmis.org \
    --cc=akpm@linux-foundation.org \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    /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

Powered by JetHome