[PATCH 6/7] perf: Use hot regs with software sched/migrate events

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Frederic Weisbecker
Date: Thursday, March 25, 2010 - 6:52 pm

Scheduler's task migration events don't work because they always
pass NULL regs perf_sw_event(). The event hence gets filtered
in perf_swevent_add().

Scheduler's context switches events use task_pt_regs() to get
the context when the event occured which is a wrong thing to
do as this won't give us the place in the kernel where we went
to sleep but the place where we left userspace. The result is
even more wrong if we switch from a kernel thread.

Use the hot regs snapshot for both events as they belong to the
non-interrupt/exception based events family. Unlike page faults
or so that provide the regs matching the exact origin of the event,
we need to save the current context.

This makes the task migration event working and fix the context
switch callchains and origin ip.

Example: perf record -a -e cs

Before:

    10.91%      ksoftirqd/0                  0  [k] 0000000000000000
                |
                --- (nil)
                    perf_callchain
                    perf_prepare_sample
                    __perf_event_overflow
                    perf_swevent_overflow
                    perf_swevent_add
                    perf_swevent_ctx_event
                    do_perf_sw_event
                    __perf_sw_event
                    perf_event_task_sched_out
                    schedule
                    run_ksoftirqd
                    kthread
                    kernel_thread_helper

After:

    23.77%  hald-addon-stor  [kernel.kallsyms]  [k] schedule
            |
            --- schedule
               |
               |--60.00%-- schedule_timeout
               |          wait_for_common
               |          wait_for_completion
               |          blk_execute_rq
               |          scsi_execute
               |          scsi_execute_req
               |          sr_test_unit_ready
               |          |
               |          |--66.67%-- sr_media_change
               |          |          media_changed
               |          |          cdrom_media_changed
               |          |          sr_block_media_changed
               |          |          check_disk_change
               |          |          cdrom_open

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: David Miller <davem@davemloft.net>
---
 include/linux/perf_event.h |   21 ++++++++++++++-------
 kernel/perf_event.c        |    3 +--
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3b59cf7..613b419 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -860,13 +860,6 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
 
 extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
 
-static inline void
-perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
-{
-	if (atomic_read(&perf_swevent_enabled[event_id]))
-		__perf_sw_event(event_id, nr, nmi, regs, addr);
-}
-
 #ifndef perf_arch_fetch_caller_regs
 static inline void
 perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { }
@@ -887,6 +880,20 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs)
 	perf_arch_fetch_caller_regs(regs, CALLER_ADDR0);
 }
 
+static inline void
+perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+{
+	if (atomic_read(&perf_swevent_enabled[event_id])) {
+		struct pt_regs caller_regs;
+
+		if (!regs) {
+			perf_fetch_caller_regs(&caller_regs);
+			regs = &caller_regs;
+		}
+		__perf_sw_event(event_id, nr, nmi, regs, addr);
+	}
+}
+
 extern void __perf_event_mmap(struct vm_area_struct *vma);
 
 static inline void perf_event_mmap(struct vm_area_struct *vma)
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index bbed6f0..8b392c3 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -1167,8 +1167,7 @@ void perf_event_task_sched_out(struct task_struct *task,
 	struct pt_regs *regs;
 	int do_switch = 1;
 
-	regs = task_pt_regs(task);
-	perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, regs, 0);
+	perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
 
 	if (likely(!ctx || !cpuctx->task_ctx))
 		return;
-- 
1.6.2.3

--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 0/7] perf updates and fixes, Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 1/7] perf: Drop the frame reliablity check, Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 2/7] perf: Fetch hot regs from the template caller, Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 3/7] x86: Unify dumpstack.h and stacktrace.h, Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 4/7] perf: Move perf_arch_fetch_caller_regs into a ..., Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 5/7] perf: Make perf_fetch_caller_regs rewind to th ..., Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 6/7] perf: Use hot regs with software sched/migrate ..., Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
[PATCH 7/7] perf: Correctly align perf event tracing buffer, Frederic Weisbecker, (Thu Mar 25, 6:52 pm)
Re: [PATCH 0/7] perf updates and fixes, Paul Mackerras, (Thu Mar 25, 11:02 pm)
Re: [PATCH 0/7] perf updates and fixes, Ingo Molnar, (Fri Mar 26, 12:58 am)
Re: [PATCH 0/7] perf updates and fixes, Frederic Weisbecker, (Fri Mar 26, 10:38 am)
Re: [PATCH 0/7] perf updates and fixes, Frederic Weisbecker, (Fri Mar 26, 10:45 am)
Re: [BUG perf] perf_fetch_caller_regs / rewind_frame_point ..., Frederic Weisbecker, (Thu Apr 8, 3:59 am)
[PATCH] perf: Fix unsafe frame rewinding with hot regs fet ..., Frederic Weisbecker, (Thu Apr 8, 5:32 am)
[GIT PULL] perf fix, Frederic Weisbecker, (Thu Apr 8, 10:31 am)
Re: [GIT PULL] perf fix, Ingo Molnar, (Tue Apr 13, 3:51 pm)