aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-sched.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-09-11 20:43:45 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-13 04:22:41 -0400
commit46538818023e8ea94f656acfa1e38297e2df20e2 (patch)
tree1cac2198d1b90036cbec61639ebee6a80d6238a3 /tools/perf/builtin-sched.c
parentbcd3279f465cdcc1e0454b5f605f021c4ff4dbb5 (diff)
perf sched: Fix bad event alignment
perf sched raises the following error when it meets a sched switch event: perf: builtin-sched.c:286: register_pid: Assertion `!(pid >= 65536)' failed. Abandon Currently in x86-64, the sched switch events have a hole in the middle of the structure: u16 common_type; u8 common_flags; u8 common_preempt_count; u32 common_pid; u32 common_tgid; char prev_comm[16]; u32 prev_pid; u32 prev_prio; <--- there u64 prev_state; char next_comm[16]; u32 next_pid; u32 next_prio; Gcc inserts a 4 bytes hole there for prev_state to be u64 aligned. And the events are exported to userspace with this hole. But in userspace, from perf sched, we fetch it using a structure that has a new field in the beginning: u32 size. This is because our trace is exported with its size as a field. But now that we have this new field, the hole in the middle disappears because it makes prev_state becoming well aligned. And since we are using a pointer to the raw trace using this struct, instead of reading prev_state, we are reading the hole. We could fix it by keeping the size seperate from the struct but actually there a lot of other potential problems: some fields may be saved as long in a 64 bits system and later read as long in a 32 bits system. Also this direct cast doesn't care about the endianness differences between the host traced machine and the machine in which we do the post processing. So instead of using such dangerous direct casts, fetch the values using the trace parsing API that already takes care of all these problems. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-sched.c')
-rw-r--r--tools/perf/builtin-sched.c101
1 files changed, 76 insertions, 25 deletions
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index de93a2604528..0215936696ed 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -653,6 +653,30 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
653 return 0; 653 return 0;
654} 654}
655 655
656
657struct raw_event_sample {
658 u32 size;
659 char data[0];
660};
661
662#define FILL_FIELD(ptr, field, event, data) \
663 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
664
665#define FILL_ARRAY(ptr, array, event, data) \
666do { \
667 void *__array = raw_field_ptr(event, #array, data); \
668 memcpy(ptr.array, __array, sizeof(ptr.array)); \
669} while(0)
670
671#define FILL_COMMON_FIELDS(ptr, event, data) \
672do { \
673 FILL_FIELD(ptr, common_type, event, data); \
674 FILL_FIELD(ptr, common_flags, event, data); \
675 FILL_FIELD(ptr, common_preempt_count, event, data); \
676 FILL_FIELD(ptr, common_pid, event, data); \
677 FILL_FIELD(ptr, common_tgid, event, data); \
678} while (0)
679
656struct trace_wakeup_event { 680struct trace_wakeup_event {
657 u32 size; 681 u32 size;
658 682
@@ -671,22 +695,32 @@ struct trace_wakeup_event {
671}; 695};
672 696
673static void 697static void
674process_sched_wakeup_event(struct trace_wakeup_event *wakeup_event, struct event *event, 698process_sched_wakeup_event(struct raw_event_sample *raw, struct event *event,
675 int cpu __used, u64 timestamp __used, struct thread *thread __used) 699 int cpu __used, u64 timestamp __used, struct thread *thread __used)
676{ 700{
677 struct task_desc *waker, *wakee; 701 struct task_desc *waker, *wakee;
702 struct trace_wakeup_event wakeup_event;
703
704 FILL_COMMON_FIELDS(wakeup_event, event, raw->data);
705
706 FILL_ARRAY(wakeup_event, comm, event, raw->data);
707 FILL_FIELD(wakeup_event, pid, event, raw->data);
708 FILL_FIELD(wakeup_event, prio, event, raw->data);
709 FILL_FIELD(wakeup_event, success, event, raw->data);
710 FILL_FIELD(wakeup_event, cpu, event, raw->data);
711
678 712
679 if (verbose) { 713 if (verbose) {
680 printf("sched_wakeup event %p\n", event); 714 printf("sched_wakeup event %p\n", event);
681 715
682 printf(" ... pid %d woke up %s/%d\n", 716 printf(" ... pid %d woke up %s/%d\n",
683 wakeup_event->common_pid, 717 wakeup_event.common_pid,
684 wakeup_event->comm, 718 wakeup_event.comm,
685 wakeup_event->pid); 719 wakeup_event.pid);
686 } 720 }
687 721
688 waker = register_pid(wakeup_event->common_pid, "<unknown>"); 722 waker = register_pid(wakeup_event.common_pid, "<unknown>");
689 wakee = register_pid(wakeup_event->pid, wakeup_event->comm); 723 wakee = register_pid(wakeup_event.pid, wakeup_event.comm);
690 724
691 add_sched_event_wakeup(waker, timestamp, wakee); 725 add_sched_event_wakeup(waker, timestamp, wakee);
692} 726}
@@ -714,13 +748,24 @@ struct trace_switch_event {
714unsigned long cpu_last_switched[MAX_CPUS]; 748unsigned long cpu_last_switched[MAX_CPUS];
715 749
716static void 750static void
717process_sched_switch_event(struct trace_switch_event *switch_event, struct event *event, 751process_sched_switch_event(struct raw_event_sample *raw, struct event *event,
718 int cpu __used, u64 timestamp __used, struct thread *thread __used) 752 int cpu __used, u64 timestamp __used, struct thread *thread __used)
719{ 753{
754 struct trace_switch_event switch_event;
720 struct task_desc *prev, *next; 755 struct task_desc *prev, *next;
721 u64 timestamp0; 756 u64 timestamp0;
722 s64 delta; 757 s64 delta;
723 758
759 FILL_COMMON_FIELDS(switch_event, event, raw->data);
760
761 FILL_ARRAY(switch_event, prev_comm, event, raw->data);
762 FILL_FIELD(switch_event, prev_pid, event, raw->data);
763 FILL_FIELD(switch_event, prev_prio, event, raw->data);
764 FILL_FIELD(switch_event, prev_state, event, raw->data);
765 FILL_ARRAY(switch_event, next_comm, event, raw->data);
766 FILL_FIELD(switch_event, next_pid, event, raw->data);
767 FILL_FIELD(switch_event, next_prio, event, raw->data);
768
724 if (verbose) 769 if (verbose)
725 printf("sched_switch event %p\n", event); 770 printf("sched_switch event %p\n", event);
726 771
@@ -738,18 +783,18 @@ process_sched_switch_event(struct trace_switch_event *switch_event, struct event
738 783
739 if (verbose) { 784 if (verbose) {
740 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", 785 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
741 switch_event->prev_comm, switch_event->prev_pid, 786 switch_event.prev_comm, switch_event.prev_pid,
742 switch_event->next_comm, switch_event->next_pid, 787 switch_event.next_comm, switch_event.next_pid,
743 delta); 788 delta);
744 } 789 }
745 790
746 prev = register_pid(switch_event->prev_pid, switch_event->prev_comm); 791 prev = register_pid(switch_event.prev_pid, switch_event.prev_comm);
747 next = register_pid(switch_event->next_pid, switch_event->next_comm); 792 next = register_pid(switch_event.next_pid, switch_event.next_comm);
748 793
749 cpu_last_switched[cpu] = timestamp; 794 cpu_last_switched[cpu] = timestamp;
750 795
751 add_sched_event_run(prev, timestamp, delta); 796 add_sched_event_run(prev, timestamp, delta);
752 add_sched_event_sleep(prev, timestamp, switch_event->prev_state); 797 add_sched_event_sleep(prev, timestamp, switch_event.prev_state);
753} 798}
754 799
755struct trace_fork_event { 800struct trace_fork_event {
@@ -768,16 +813,25 @@ struct trace_fork_event {
768}; 813};
769 814
770static void 815static void
771process_sched_fork_event(struct trace_fork_event *fork_event, struct event *event, 816process_sched_fork_event(struct raw_event_sample *raw, struct event *event,
772 int cpu __used, u64 timestamp __used, struct thread *thread __used) 817 int cpu __used, u64 timestamp __used, struct thread *thread __used)
773{ 818{
819 struct trace_fork_event fork_event;
820
821 FILL_COMMON_FIELDS(fork_event, event, raw->data);
822
823 FILL_ARRAY(fork_event, parent_comm, event, raw->data);
824 FILL_FIELD(fork_event, parent_pid, event, raw->data);
825 FILL_ARRAY(fork_event, child_comm, event, raw->data);
826 FILL_FIELD(fork_event, child_pid, event, raw->data);
827
774 if (verbose) { 828 if (verbose) {
775 printf("sched_fork event %p\n", event); 829 printf("sched_fork event %p\n", event);
776 printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid); 830 printf("... parent: %s/%d\n", fork_event.parent_comm, fork_event.parent_pid);
777 printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid); 831 printf("... child: %s/%d\n", fork_event.child_comm, fork_event.child_pid);
778 } 832 }
779 register_pid(fork_event->parent_pid, fork_event->parent_comm); 833 register_pid(fork_event.parent_pid, fork_event.parent_comm);
780 register_pid(fork_event->child_pid, fork_event->child_comm); 834 register_pid(fork_event.child_pid, fork_event.child_comm);
781} 835}
782 836
783static void process_sched_exit_event(struct event *event, 837static void process_sched_exit_event(struct event *event,
@@ -791,10 +845,7 @@ static void
791process_raw_event(event_t *raw_event __used, void *more_data, 845process_raw_event(event_t *raw_event __used, void *more_data,
792 int cpu, u64 timestamp, struct thread *thread) 846 int cpu, u64 timestamp, struct thread *thread)
793{ 847{
794 struct { 848 struct raw_event_sample *raw = more_data;
795 u32 size;
796 char data[0];
797 } *raw = more_data;
798 struct event *event; 849 struct event *event;
799 int type; 850 int type;
800 851
@@ -802,13 +853,13 @@ process_raw_event(event_t *raw_event __used, void *more_data,
802 event = trace_find_event(type); 853 event = trace_find_event(type);
803 854
804 if (!strcmp(event->name, "sched_switch")) 855 if (!strcmp(event->name, "sched_switch"))
805 process_sched_switch_event(more_data, event, cpu, timestamp, thread); 856 process_sched_switch_event(raw, event, cpu, timestamp, thread);
806 if (!strcmp(event->name, "sched_wakeup")) 857 if (!strcmp(event->name, "sched_wakeup"))
807 process_sched_wakeup_event(more_data, event, cpu, timestamp, thread); 858 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
808 if (!strcmp(event->name, "sched_wakeup_new")) 859 if (!strcmp(event->name, "sched_wakeup_new"))
809 process_sched_wakeup_event(more_data, event, cpu, timestamp, thread); 860 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
810 if (!strcmp(event->name, "sched_process_fork")) 861 if (!strcmp(event->name, "sched_process_fork"))
811 process_sched_fork_event(more_data, event, cpu, timestamp, thread); 862 process_sched_fork_event(raw, event, cpu, timestamp, thread);
812 if (!strcmp(event->name, "sched_process_exit")) 863 if (!strcmp(event->name, "sched_process_exit"))
813 process_sched_exit_event(event, cpu, timestamp, thread); 864 process_sched_exit_event(event, cpu, timestamp, thread);
814} 865}