linux_old1/tools/perf/util/trace-event-read.c

390 lines
6.8 KiB
C
Raw Normal View History

2009-08-17 22:18:06 +08:00
/*
* Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "../perf.h"
2009-08-17 22:18:06 +08:00
#include "util.h"
#include "trace-event.h"
static int input_fd;
int file_bigendian;
int host_bigendian;
static int long_size;
static ssize_t calc_data_size;
perf: add perf-inject builtin Currently, perf 'live mode' writes build-ids at the end of the session, which isn't actually useful for processing live mode events. What would be better would be to have the build-ids sent before any of the samples that reference them, which can be done by processing the event stream and retrieving the build-ids on the first hit. Doing that in perf-record itself, however, is off-limits. This patch introduces perf-inject, which does the same job while leaving perf-record untouched. Normal mode perf still records the build-ids at the end of the session as it should, but for live mode, perf-inject can be injected in between the record and report steps e.g.: perf record -o - ./hackbench 10 | perf inject -v -b | perf report -v -i - perf-inject reads a perf-record event stream and repipes it to stdout. At any point the processing code can inject other events into the event stream - in this case build-ids (-b option) are read and injected as needed into the event stream. Build-ids are just the first user of perf-inject - potentially anything that needs userspace processing to augment the trace stream with additional information could make use of this facility. Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frédéric Weisbecker <fweisbec@gmail.com> LKML-Reference: <1272696080-16435-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-01 14:41:20 +08:00
static bool repipe;
static int do_read(int fd, void *buf, int size)
{
int rsize = size;
while (size) {
int ret = read(fd, buf, size);
if (ret <= 0)
return -1;
perf: add perf-inject builtin Currently, perf 'live mode' writes build-ids at the end of the session, which isn't actually useful for processing live mode events. What would be better would be to have the build-ids sent before any of the samples that reference them, which can be done by processing the event stream and retrieving the build-ids on the first hit. Doing that in perf-record itself, however, is off-limits. This patch introduces perf-inject, which does the same job while leaving perf-record untouched. Normal mode perf still records the build-ids at the end of the session as it should, but for live mode, perf-inject can be injected in between the record and report steps e.g.: perf record -o - ./hackbench 10 | perf inject -v -b | perf report -v -i - perf-inject reads a perf-record event stream and repipes it to stdout. At any point the processing code can inject other events into the event stream - in this case build-ids (-b option) are read and injected as needed into the event stream. Build-ids are just the first user of perf-inject - potentially anything that needs userspace processing to augment the trace stream with additional information could make use of this facility. Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frédéric Weisbecker <fweisbec@gmail.com> LKML-Reference: <1272696080-16435-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-01 14:41:20 +08:00
if (repipe) {
int retw = write(STDOUT_FILENO, buf, ret);
if (retw <= 0 || retw != ret)
die("repiping input file");
}
size -= ret;
buf += ret;
}
return rsize;
}
2009-08-17 22:18:06 +08:00
static int read_or_die(void *data, int size)
{
int r;
r = do_read(input_fd, data, size);
if (r <= 0)
2009-08-17 22:18:06 +08:00
die("reading input file (size expected=%d received=%d)",
size, r);
if (calc_data_size)
calc_data_size += r;
2009-08-17 22:18:06 +08:00
return r;
}
/* If it fails, the next read will report it */
static void skip(int size)
{
char buf[BUFSIZ];
int r;
while (size) {
r = size > BUFSIZ ? BUFSIZ : size;
read_or_die(buf, r);
size -= r;
};
}
static unsigned int read4(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned int data;
read_or_die(&data, 4);
return __data2host4(pevent, data);
2009-08-17 22:18:06 +08:00
}
static unsigned long long read8(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned long long data;
read_or_die(&data, 8);
return __data2host8(pevent, data);
2009-08-17 22:18:06 +08:00
}
static char *read_string(void)
{
char buf[BUFSIZ];
char *str = NULL;
int size = 0;
off_t r;
char c;
2009-08-17 22:18:06 +08:00
for (;;) {
r = read(input_fd, &c, 1);
2009-08-17 22:18:06 +08:00
if (r < 0)
die("reading input file");
if (!r)
die("no data");
perf: add perf-inject builtin Currently, perf 'live mode' writes build-ids at the end of the session, which isn't actually useful for processing live mode events. What would be better would be to have the build-ids sent before any of the samples that reference them, which can be done by processing the event stream and retrieving the build-ids on the first hit. Doing that in perf-record itself, however, is off-limits. This patch introduces perf-inject, which does the same job while leaving perf-record untouched. Normal mode perf still records the build-ids at the end of the session as it should, but for live mode, perf-inject can be injected in between the record and report steps e.g.: perf record -o - ./hackbench 10 | perf inject -v -b | perf report -v -i - perf-inject reads a perf-record event stream and repipes it to stdout. At any point the processing code can inject other events into the event stream - in this case build-ids (-b option) are read and injected as needed into the event stream. Build-ids are just the first user of perf-inject - potentially anything that needs userspace processing to augment the trace stream with additional information could make use of this facility. Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frédéric Weisbecker <fweisbec@gmail.com> LKML-Reference: <1272696080-16435-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-01 14:41:20 +08:00
if (repipe) {
int retw = write(STDOUT_FILENO, &c, 1);
if (retw <= 0 || retw != r)
die("repiping input file string");
}
buf[size++] = c;
2009-08-17 22:18:06 +08:00
if (!c)
break;
2009-08-17 22:18:06 +08:00
}
if (calc_data_size)
calc_data_size += size;
str = malloc(size);
if (str)
memcpy(str, buf, size);
2009-08-17 22:18:06 +08:00
return str;
}
static int read_proc_kallsyms(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned int size;
char *buf;
size = read4(pevent);
2009-08-17 22:18:06 +08:00
if (!size)
return 0;
buf = malloc(size + 1);
if (buf == NULL)
return -1;
2009-08-17 22:18:06 +08:00
read_or_die(buf, size);
buf[size] = '\0';
2009-08-17 22:18:06 +08:00
parse_proc_kallsyms(pevent, buf, size);
2009-08-17 22:18:06 +08:00
free(buf);
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_ftrace_printk(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned int size;
char *buf;
size = read4(pevent);
2009-08-17 22:18:06 +08:00
if (!size)
return 0;
buf = malloc(size);
if (buf == NULL)
return -1;
2009-08-17 22:18:06 +08:00
read_or_die(buf, size);
parse_ftrace_printk(pevent, buf, size);
2009-08-17 22:18:06 +08:00
free(buf);
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_header_files(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned long long size;
char *header_event;
char buf[BUFSIZ];
read_or_die(buf, 12);
if (memcmp(buf, "header_page", 12) != 0)
die("did not read header page");
size = read8(pevent);
perf: Fix warning while reading ring buffer headers commit e9e94e3bd862d31777335722e747e97d9821bc1d "perf trace: Ignore "overwrite" field if present in /events/header_page" makes perf trace launching spurious warnings about unexpected tokens read: Warning: Error: expected type 6 but read 4 This change tries to handle the overcommit field in the header_page file whenever this field is present or not. The problem is that if this field is not present, we try to find it and give up in the middle of the line when we realize we are actually dealing with another field, which is the "data" one. And this failure abandons the file pointer in the middle of the "data" description line: field: u64 timestamp; offset:0; size:8; signed:0; field: local_t commit; offset:8; size:8; signed:1; field: char data; offset:16; size:4080; signed:1; ^^^ Here What happens next is that we want to read this line to parse the data field, but we fail because the pointer is not in the beginning of the line. We could probably fix that by rewinding the pointer. But in fact we don't care much about these headers that only concern the ftrace ring-buffer. We don't use them from perf. Just skip this part of perf.data, but don't remove it from recording to stay compatible with olders perf.data Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Stephane Eranian <eranian@google.com> Cc: Steven Rostedt <rostedt@goodmis.org>
2010-05-01 09:08:46 +08:00
skip(size);
2009-08-17 22:18:06 +08:00
/*
* The size field in the page is of type long,
* use that instead, since it represents the kernel.
*/
long_size = header_page_size_size;
read_or_die(buf, 13);
if (memcmp(buf, "header_event", 13) != 0)
die("did not read header event");
size = read8(pevent);
header_event = malloc(size);
if (header_event == NULL)
return -1;
2009-08-17 22:18:06 +08:00
read_or_die(header_event, size);
free(header_event);
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
2009-08-17 22:18:06 +08:00
{
char *buf;
buf = malloc(size);
if (buf == NULL)
return -1;
2009-08-17 22:18:06 +08:00
read_or_die(buf, size);
parse_ftrace_file(pevent, buf, size);
2009-08-17 22:18:06 +08:00
free(buf);
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_event_file(struct pevent *pevent, char *sys,
unsigned long long size)
2009-08-17 22:18:06 +08:00
{
char *buf;
buf = malloc(size);
if (buf == NULL)
return -1;
2009-08-17 22:18:06 +08:00
read_or_die(buf, size);
parse_event_file(pevent, buf, size, sys);
2009-08-17 22:18:06 +08:00
free(buf);
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_ftrace_files(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned long long size;
int count;
int i;
int ret;
2009-08-17 22:18:06 +08:00
count = read4(pevent);
2009-08-17 22:18:06 +08:00
for (i = 0; i < count; i++) {
size = read8(pevent);
ret = read_ftrace_file(pevent, size);
if (ret)
return ret;
2009-08-17 22:18:06 +08:00
}
return 0;
2009-08-17 22:18:06 +08:00
}
static int read_event_files(struct pevent *pevent)
2009-08-17 22:18:06 +08:00
{
unsigned long long size;
char *sys;
int systems;
int count;
int i,x;
int ret;
2009-08-17 22:18:06 +08:00
systems = read4(pevent);
2009-08-17 22:18:06 +08:00
for (i = 0; i < systems; i++) {
sys = read_string();
if (sys == NULL)
return -1;
2009-08-17 22:18:06 +08:00
count = read4(pevent);
2009-08-17 22:18:06 +08:00
for (x=0; x < count; x++) {
size = read8(pevent);
ret = read_event_file(pevent, sys, size);
if (ret)
return ret;
2009-08-17 22:18:06 +08:00
}
}
return 0;
2009-08-17 22:18:06 +08:00
}
ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
2009-08-17 22:18:06 +08:00
{
char buf[BUFSIZ];
char test[] = { 23, 8, 68 };
char *version;
perf sched: Display time in milliseconds, reorganize output After: ----------------------------------------------------------------------------------- Task | runtime ms | switches | average delay ms | maximum delay ms | ----------------------------------------------------------------------------------- migration/0 | 0.000 ms | 1 | avg: 0.047 ms | max: 0.047 ms | ksoftirqd/0 | 0.000 ms | 1 | avg: 0.039 ms | max: 0.039 ms | migration/1 | 0.000 ms | 3 | avg: 0.013 ms | max: 0.016 ms | migration/3 | 0.000 ms | 2 | avg: 0.003 ms | max: 0.004 ms | migration/4 | 0.000 ms | 1 | avg: 0.022 ms | max: 0.022 ms | distccd | 0.000 ms | 1 | avg: 0.004 ms | max: 0.004 ms | distccd | 0.000 ms | 1 | avg: 0.014 ms | max: 0.014 ms | distccd | 0.000 ms | 2 | avg: 0.000 ms | max: 0.000 ms | distccd | 0.000 ms | 2 | avg: 0.012 ms | max: 0.019 ms | distccd | 0.000 ms | 1 | avg: 0.002 ms | max: 0.002 ms | as | 0.000 ms | 2 | avg: 0.019 ms | max: 0.019 ms | as | 0.000 ms | 3 | avg: 0.015 ms | max: 0.017 ms | as | 0.000 ms | 1 | avg: 0.009 ms | max: 0.009 ms | perf | 0.000 ms | 1 | avg: 0.001 ms | max: 0.001 ms | gcc | 0.000 ms | 1 | avg: 0.021 ms | max: 0.021 ms | run-mozilla.sh | 0.000 ms | 2 | avg: 0.010 ms | max: 0.017 ms | mozilla-plugin- | 0.000 ms | 1 | avg: 0.006 ms | max: 0.006 ms | gcc | 0.000 ms | 2 | avg: 0.013 ms | max: 0.013 ms | ----------------------------------------------------------------------------------- (The runtime ms column is not filled in yet.) 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> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-12 16:08:34 +08:00
int show_version = 0;
2009-08-17 22:18:06 +08:00
int show_funcs = 0;
int show_printk = 0;
ssize_t size = -1;
struct pevent *pevent;
int err;
*ppevent = NULL;
calc_data_size = 1;
perf: add perf-inject builtin Currently, perf 'live mode' writes build-ids at the end of the session, which isn't actually useful for processing live mode events. What would be better would be to have the build-ids sent before any of the samples that reference them, which can be done by processing the event stream and retrieving the build-ids on the first hit. Doing that in perf-record itself, however, is off-limits. This patch introduces perf-inject, which does the same job while leaving perf-record untouched. Normal mode perf still records the build-ids at the end of the session as it should, but for live mode, perf-inject can be injected in between the record and report steps e.g.: perf record -o - ./hackbench 10 | perf inject -v -b | perf report -v -i - perf-inject reads a perf-record event stream and repipes it to stdout. At any point the processing code can inject other events into the event stream - in this case build-ids (-b option) are read and injected as needed into the event stream. Build-ids are just the first user of perf-inject - potentially anything that needs userspace processing to augment the trace stream with additional information could make use of this facility. Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frédéric Weisbecker <fweisbec@gmail.com> LKML-Reference: <1272696080-16435-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-01 14:41:20 +08:00
repipe = __repipe;
2009-08-17 22:18:06 +08:00
input_fd = fd;
2009-08-17 22:18:06 +08:00
read_or_die(buf, 3);
if (memcmp(buf, test, 3) != 0)
die("no trace data in the file");
2009-08-17 22:18:06 +08:00
read_or_die(buf, 7);
if (memcmp(buf, "tracing", 7) != 0)
die("not a trace file (missing 'tracing' tag)");
2009-08-17 22:18:06 +08:00
version = read_string();
if (version == NULL)
return -1;
perf sched: Display time in milliseconds, reorganize output After: ----------------------------------------------------------------------------------- Task | runtime ms | switches | average delay ms | maximum delay ms | ----------------------------------------------------------------------------------- migration/0 | 0.000 ms | 1 | avg: 0.047 ms | max: 0.047 ms | ksoftirqd/0 | 0.000 ms | 1 | avg: 0.039 ms | max: 0.039 ms | migration/1 | 0.000 ms | 3 | avg: 0.013 ms | max: 0.016 ms | migration/3 | 0.000 ms | 2 | avg: 0.003 ms | max: 0.004 ms | migration/4 | 0.000 ms | 1 | avg: 0.022 ms | max: 0.022 ms | distccd | 0.000 ms | 1 | avg: 0.004 ms | max: 0.004 ms | distccd | 0.000 ms | 1 | avg: 0.014 ms | max: 0.014 ms | distccd | 0.000 ms | 2 | avg: 0.000 ms | max: 0.000 ms | distccd | 0.000 ms | 2 | avg: 0.012 ms | max: 0.019 ms | distccd | 0.000 ms | 1 | avg: 0.002 ms | max: 0.002 ms | as | 0.000 ms | 2 | avg: 0.019 ms | max: 0.019 ms | as | 0.000 ms | 3 | avg: 0.015 ms | max: 0.017 ms | as | 0.000 ms | 1 | avg: 0.009 ms | max: 0.009 ms | perf | 0.000 ms | 1 | avg: 0.001 ms | max: 0.001 ms | gcc | 0.000 ms | 1 | avg: 0.021 ms | max: 0.021 ms | run-mozilla.sh | 0.000 ms | 2 | avg: 0.010 ms | max: 0.017 ms | mozilla-plugin- | 0.000 ms | 1 | avg: 0.006 ms | max: 0.006 ms | gcc | 0.000 ms | 2 | avg: 0.013 ms | max: 0.013 ms | ----------------------------------------------------------------------------------- (The runtime ms column is not filled in yet.) 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> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-12 16:08:34 +08:00
if (show_version)
printf("version = %s\n", version);
2009-08-17 22:18:06 +08:00
free(version);
read_or_die(buf, 1);
file_bigendian = buf[0];
host_bigendian = bigendian();
pevent = read_trace_init(file_bigendian, host_bigendian);
if (pevent == NULL) {
pr_debug("read_trace_init failed");
goto out;
}
2009-08-17 22:18:06 +08:00
read_or_die(buf, 1);
long_size = buf[0];
page_size = read4(pevent);
2009-08-17 22:18:06 +08:00
err = read_header_files(pevent);
if (err)
goto out;
err = read_ftrace_files(pevent);
if (err)
goto out;
err = read_event_files(pevent);
if (err)
goto out;
err = read_proc_kallsyms(pevent);
if (err)
goto out;
err = read_ftrace_printk(pevent);
if (err)
goto out;
2009-08-17 22:18:06 +08:00
size = calc_data_size - 1;
calc_data_size = 0;
perf: add perf-inject builtin Currently, perf 'live mode' writes build-ids at the end of the session, which isn't actually useful for processing live mode events. What would be better would be to have the build-ids sent before any of the samples that reference them, which can be done by processing the event stream and retrieving the build-ids on the first hit. Doing that in perf-record itself, however, is off-limits. This patch introduces perf-inject, which does the same job while leaving perf-record untouched. Normal mode perf still records the build-ids at the end of the session as it should, but for live mode, perf-inject can be injected in between the record and report steps e.g.: perf record -o - ./hackbench 10 | perf inject -v -b | perf report -v -i - perf-inject reads a perf-record event stream and repipes it to stdout. At any point the processing code can inject other events into the event stream - in this case build-ids (-b option) are read and injected as needed into the event stream. Build-ids are just the first user of perf-inject - potentially anything that needs userspace processing to augment the trace stream with additional information could make use of this facility. Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frédéric Weisbecker <fweisbec@gmail.com> LKML-Reference: <1272696080-16435-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-05-01 14:41:20 +08:00
repipe = false;
2009-08-17 22:18:06 +08:00
if (show_funcs) {
pevent_print_funcs(pevent);
} else if (show_printk) {
pevent_print_printk(pevent);
2009-08-17 22:18:06 +08:00
}
*ppevent = pevent;
pevent = NULL;
out:
if (pevent)
pevent_free(pevent);
return size;
2009-08-17 22:18:06 +08:00
}