perf_counter: Correct PERF_SAMPLE_RAW output
authorPeter Zijlstra <a.p.zijlstra@chello.nl>
Mon, 10 Aug 2009 09:16:52 +0000 (11:16 +0200)
committerIngo Molnar <mingo@elte.hu>
Mon, 10 Aug 2009 09:33:09 +0000 (11:33 +0200)
PERF_SAMPLE_* output switches should unconditionally output the
correct format, as they are the only way to unambiguously parse
the PERF_EVENT_SAMPLE data.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1249896447.17467.74.camel@twins>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
include/linux/perf_counter.h
include/trace/ftrace.h
kernel/perf_counter.c

index 2aabe43..a9d823a 100644 (file)
@@ -369,6 +369,8 @@ enum perf_event_type {
         *
         *      { u64                   nr,
         *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
+        *      { u32                   size;
+        *        char                  data[size];}&& PERF_SAMPLE_RAW
         * };
         */
        PERF_EVENT_SAMPLE               = 9,
index 7fb16d9..7167b9b 100644 (file)
@@ -685,7 +685,8 @@ static void ftrace_profile_##call(proto)                            \
        pc = preempt_count();                                           \
                                                                        \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
-       __entry_size = ALIGN(__data_size + sizeof(*entry), sizeof(u64));\
+       __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
+                            sizeof(u64));                              \
                                                                        \
        do {                                                            \
                char raw_data[__entry_size];                            \
index 546e62d..5229d16 100644 (file)
@@ -2646,7 +2646,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                u64 counter;
        } group_entry;
        struct perf_callchain_entry *callchain = NULL;
-       struct perf_raw_record *raw = NULL;
        int callchain_size = 0;
        u64 time;
        struct {
@@ -2716,9 +2715,15 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
        }
 
        if (sample_type & PERF_SAMPLE_RAW) {
-               raw = data->raw;
-               if (raw)
-                       header.size += raw->size;
+               int size = sizeof(u32);
+
+               if (data->raw)
+                       size += data->raw->size;
+               else
+                       size += sizeof(u32);
+
+               WARN_ON_ONCE(size & (sizeof(u64)-1));
+               header.size += size;
        }
 
        ret = perf_output_begin(&handle, counter, header.size, nmi, 1);
@@ -2784,8 +2789,21 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                }
        }
 
-       if ((sample_type & PERF_SAMPLE_RAW) && raw)
-               perf_output_copy(&handle, raw->data, raw->size);
+       if (sample_type & PERF_SAMPLE_RAW) {
+               if (data->raw) {
+                       perf_output_put(&handle, data->raw->size);
+                       perf_output_copy(&handle, data->raw->data, data->raw->size);
+               } else {
+                       struct {
+                               u32     size;
+                               u32     data;
+                       } raw = {
+                               .size = sizeof(u32),
+                               .data = 0,
+                       };
+                       perf_output_put(&handle, raw);
+               }
+       }
 
        perf_output_end(&handle);
 }