From: Steven Rostedt <[email protected]>
The functions that assign the contents for the perf software events are
defined by the TRACE_EVENT() macros. Each event has its own unique
way to assign data to its buffer. When you have over 700 events,
that means there's 700 functions assigning data uniquely for each
event.
By making helper functions in the core kernel to do the work
instead, we can shrink the size of the kernel down a bit.
With a kernel configured with 707 events, the change in size was:
text data bss dec hex filename
19966937 2594648 1945600 24507185 175f331 vmlinux-before
19924761 2594584 1945600 24464945 1754e31 vmlinux-after
That's a total of 42240 bytes, which comes down to 59 bytes per event.
Cc: Peter Zijlstra <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Steven Rostedt <[email protected]>
---
include/linux/ftrace_event.h | 13 +++++++++++++
include/trace/ftrace.h | 31 ++++++++-----------------------
kernel/trace/trace_event_perf.c | 26 ++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 23 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index b9f39d3..06c6d04 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -313,6 +313,19 @@ struct perf_event;
DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
+struct perf_trace_event {
+ struct pt_regs regs;
+ u64 addr;
+ u64 count;
+ int entry_size;
+ int rctx;
+};
+
+extern void *perf_trace_event_setup(struct ftrace_event_call *event_call,
+ struct perf_trace_event *pe);
+extern void perf_trace_event_submit(void *raw_data, struct ftrace_event_call *event_call,
+ struct perf_trace_event *pe);
+
extern int perf_trace_init(struct perf_event *event);
extern void perf_trace_destroy(struct perf_event *event);
extern int perf_trace_add(struct perf_event *event, int flags);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 8118451..a02d48d 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -677,10 +677,10 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
#define __get_str(field) (char *)__get_dynamic_array(field)
#undef __perf_addr
-#define __perf_addr(a) __addr = (a)
+#define __perf_addr(a) __pe.addr = (a)
#undef __perf_count
-#define __perf_count(c) __count = (c)
+#define __perf_count(c) __pe.count = (c)
#undef TP_perf_assign
#define TP_perf_assign(args...) args
@@ -693,36 +693,21 @@ perf_trace_##call(void *__data, proto) \
struct ftrace_event_call *event_call = __data; \
struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
struct ftrace_raw_##call *entry; \
- struct pt_regs __regs; \
- u64 __addr = 0, __count = 1; \
- struct hlist_head *head; \
- int __entry_size; \
+ struct perf_trace_event __pe; \
int __data_size; \
- int rctx; \
- \
- perf_fetch_caller_regs(&__regs); \
\
__data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
- __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
- sizeof(u64)); \
- __entry_size -= sizeof(u32); \
- \
- if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE, \
- "profile buffer not large enough")) \
- return; \
+ __pe.entry_size = __data_size + sizeof(*entry); \
+ __pe.addr = 0; \
+ __pe.count = 1; \
\
- entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare( \
- __entry_size, event_call->event.type, &__regs, &rctx); \
- if (!entry) \
- return; \
+ entry = perf_trace_event_setup(event_call, &__pe); \
\
tstruct \
\
{ assign; } \
\
- head = this_cpu_ptr(event_call->perf_events); \
- perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
- __count, &__regs, head); \
+ perf_trace_event_submit(entry, event_call, &__pe); \
}
/*
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 9824419..75484aa 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -21,6 +21,32 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
/* Count the events in use (per event id, not per instance) */
static int total_ref_count;
+void *perf_trace_event_setup(struct ftrace_event_call *event_call,
+ struct perf_trace_event *pe)
+{
+ perf_fetch_caller_regs(&pe->regs);
+
+ pe->entry_size = ALIGN(pe->entry_size + sizeof(u32), sizeof(u64));
+ pe->entry_size -= sizeof(u32);
+
+ if (WARN_ONCE(pe->entry_size > PERF_MAX_TRACE_SIZE,
+ "profile buffer not large enough"))
+ return NULL;
+
+ return perf_trace_buf_prepare(pe->entry_size,
+ event_call->event.type, &pe->regs, &pe->rctx);
+}
+
+void perf_trace_event_submit(void *raw_data, struct ftrace_event_call *event_call,
+ struct perf_trace_event *pe)
+{
+ struct hlist_head *head;
+
+ head = this_cpu_ptr(event_call->perf_events);
+ perf_trace_buf_submit(raw_data, pe->entry_size, pe->rctx, pe->addr,
+ pe->count, &pe->regs, head);
+}
+
static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
struct perf_event *p_event)
{
--
1.7.10.4
On Thu, 2012-08-09 at 23:43 -0400, Steven Rostedt wrote:
> plain text document attachment
> (0004-perf-events-Use-helper-functions-in-event-assignment.patch)
> From: Steven Rostedt <[email protected]>
>
> The functions that assign the contents for the perf software events are
> defined by the TRACE_EVENT() macros. Each event has its own unique
> way to assign data to its buffer. When you have over 700 events,
> that means there's 700 functions assigning data uniquely for each
> event.
>
> By making helper functions in the core kernel to do the work
> instead, we can shrink the size of the kernel down a bit.
>
> With a kernel configured with 707 events, the change in size was:
>
> text data bss dec hex filename
> 19966937 2594648 1945600 24507185 175f331 vmlinux-before
> 19924761 2594584 1945600 24464945 1754e31 vmlinux-after
>
> That's a total of 42240 bytes, which comes down to 59 bytes per event.
Seems like good stuff.. one nit..
> +void perf_trace_event_submit(void *raw_data, struct ftrace_event_call *event_call,
> + struct perf_trace_event *pe)
> +{
> + struct hlist_head *head;
> +
> + head = this_cpu_ptr(event_call->perf_events);
> + perf_trace_buf_submit(raw_data, pe->entry_size, pe->rctx, pe->addr,
> + pe->count, &pe->regs, head);
> +}
Can you make perf_trace_buf_submit() go away? Its reduced to a simple
fwd function and layering another wrapper on top seems like pushing it.
On Mon, 2012-08-13 at 10:03 +0200, Peter Zijlstra wrote:
> > +void perf_trace_event_submit(void *raw_data, struct ftrace_event_call *event_call,
> > + struct perf_trace_event *pe)
> > +{
> > + struct hlist_head *head;
> > +
> > + head = this_cpu_ptr(event_call->perf_events);
> > + perf_trace_buf_submit(raw_data, pe->entry_size, pe->rctx, pe->addr,
> > + pe->count, &pe->regs, head);
> > +}
>
> Can you make perf_trace_buf_submit() go away? Its reduced to a simple
> fwd function and layering another wrapper on top seems like pushing it.
You mean just have perf_trace_event_submit() call perf_tp_event()
directly?
I have no problem with that. Although I may make that into a separate
patch to keep this patch as a 'move' and the other patch as the change.
Looking at the history of perf_trace_buf_submit(), it use to be more
than one function call. But when you inlined
perf_swevent_put_recursion_context(), it became just a one2one mapping.
I'm assuming that we want to convert all calls to
perf_trace_buf_submit()s into perf_tp_event()?
-- Steve
On Mon, 2012-08-13 at 09:03 -0400, Steven Rostedt wrote:
> On Mon, 2012-08-13 at 10:03 +0200, Peter Zijlstra wrote:
>
> > > +void perf_trace_event_submit(void *raw_data, struct ftrace_event_call *event_call,
> > > + struct perf_trace_event *pe)
> > > +{
> > > + struct hlist_head *head;
> > > +
> > > + head = this_cpu_ptr(event_call->perf_events);
> > > + perf_trace_buf_submit(raw_data, pe->entry_size, pe->rctx, pe->addr,
> > > + pe->count, &pe->regs, head);
> > > +}
> >
> > Can you make perf_trace_buf_submit() go away? Its reduced to a simple
> > fwd function and layering another wrapper on top seems like pushing it.
>
> You mean just have perf_trace_event_submit() call perf_tp_event()
> directly?
>
> I have no problem with that. Although I may make that into a separate
> patch to keep this patch as a 'move' and the other patch as the change.
>
> Looking at the history of perf_trace_buf_submit(), it use to be more
> than one function call. But when you inlined
> perf_swevent_put_recursion_context(), it became just a one2one mapping.
Right.
> I'm assuming that we want to convert all calls to
> perf_trace_buf_submit()s into perf_tp_event()?
Yeah.. I think you're referring to the {u,k}probes open-coded nonsense?
Should we make those use these new helpers you created as well?
On Mon, 2012-08-13 at 15:52 +0200, Peter Zijlstra wrote:
> > Looking at the history of perf_trace_buf_submit(), it use to be more
> > than one function call. But when you inlined
> > perf_swevent_put_recursion_context(), it became just a one2one mapping.
>
> Right.
OK, this should go as a separate change.
>
> > I'm assuming that we want to convert all calls to
> > perf_trace_buf_submit()s into perf_tp_event()?
>
> Yeah.. I think you're referring to the {u,k}probes open-coded nonsense?
> Should we make those use these new helpers you created as well?
They may not need it. The helpers I created were for the macros that are
created by all TRACE_EVENT() instances. If the uprobes and kprobes only
have a single instance, then they probably don't need the helpers. But
they still call the perf_trace_buf_submit(), which can can probably be
cleaned up.
-- Steve
On Mon, 2012-08-13 at 10:40 -0400, Steven Rostedt wrote:
> > Yeah.. I think you're referring to the {u,k}probes open-coded nonsense?
> > Should we make those use these new helpers you created as well?
>
> They may not need it. The helpers I created were for the macros that are
> created by all TRACE_EVENT() instances. If the uprobes and kprobes only
> have a single instance, then they probably don't need the helpers. But
> they still call the perf_trace_buf_submit(), which can can probably be
> cleaned up.
Right, I realize that. I was just thinking it might be good to keep all
(3?) copies similar. Also avoiding two sets of wrappers seems like a
good idea.