Having perf use libparsevent.a
cover Having perf use libparsevent.a
Hi All,
I've spent the week working on getting libparsevent.a working with perf. After several rewrites, hacking in both perf and the trace-cmd code, and breaking both beyond repair, I finally got to a point that it just works.
The library was originally going to be called libperf.so, but after talking with Arnaldo, he wants the functionality of the libraries separated more, not combined all in one binary. As this code deals only with the parsing the event formats and creating a way to read the binary data from it, we both agreed that it is best to keep its original name that was in trace-cmd and call it libparsevent.so.
Note, because perf installs in the user's ~/bin and I did not want to make it a requirement to add ~/bin to LD_LIBRARY_PATH, I kept the library as a .a that is linked directly into perf.
In the beginning, I tried to work with the library code within the tools/perf directory, and because of the CFLAGS of perf, it made compiling the library code very nasty (namely the -Wswitch-enum). I also talked with Arnaldo and Frederic about the placement of this code, and we all agreed that tools/lib/events is a good place to put it.
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
Thus, this is what I ended up with.
This patch set just gets the libparsevent.a/so working with perf. New code would be required to get it packaged for distributions to ship as a library itself. Once it gets there, I'll work on getting this code to work with code like latencytrace.
Anyway, this is still in the RFC phase. Lets hear what people have to say.
(some of the patches are quite large as they either insert full files or remove them, and probably will not make LKML due to the size constraint.)
This patches can be viewed from:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
tip/perf/parse-events
Head SHA1: 781d261ff8241243173cf996ceb068cb19bd5874
Julia Lawall (1):
perf/events: Correct size given to memset
Steven Rostedt (6):
perf: Separate out trace-cmd parse-events from perf files tools/events: Add files to create libparsevent.a
perf: Build libparsevent.a
events: Update tools/lib/events to work with perf
perf: Have perf use the new libparsevent.a library perf/events: Add flag to produce nsec output
Tom Zanussi (1):
perf/events: Add flag/symbol format_flags
----
tools/lib/events/Makefile | 303 ++ tools/lib/events/event-parse.c | 4991 ++++++++++++++++++++ tools/lib/events/event-parse.h | 804 ++++ tools/lib/events/event-utils.h | 80 + tools/lib/events/parse-filter.c | 2262 +++++++++ tools/lib/events/parse-utils.c | 110 + tools/lib/events/trace-seq.c | 200 + tools/perf/Makefile | 17 +- tools/perf/builtin-kmem.c | 6 +- tools/perf/builtin-lock.c | 26 +- tools/perf/builtin-sched.c | 42 +- tools/perf/builtin-script.c | 2 +- .../util/scripting-engines/trace-event-python.c | 16 +- tools/perf/util/trace-event-info.c | 4 +- tools/perf/util/trace-event-parse.c | 3188 +------------ tools/perf/util/trace-event-read.c | 34 +- tools/perf/util/trace-event.h | 268 +- 17 files changed, 9070 insertions(+), 3283 deletions(-)
RFC PATCH 1/8 perf: Separate out trace-cmd parse-events from perf files
From: Steven Rostedt <[email protected]>
Move the trace-event-parse.c code that originally came from trace-cmd into their own files. The new file will be called trace-parse-events.c, as the name of trace-cmd's file was parse-events.c too, but it conflicted with the parse-events.c file in perf that parses the command line.
This tries to update the code with mimimal changes.
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in trace-parse-events.c and trace-parse-events.h.
--- tools/perf/Makefile | 2 + tools/perf/util/trace-event-parse.c | 3125 --------------------------------- tools/perf/util/trace-event.h | 274 +--- tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++ tools/perf/util/trace-parse-events.h | 273 +++ 5 files changed, 3407 insertions(+), 3395 deletions(-) create mode 100644 tools/perf/util/trace-parse-events.c create mode 100644 tools/perf/util/trace-parse-events.h
tools/perf/Makefile +2 -0
@@ -278,6 +278,7 @@ LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h +LIB_H += util/trace-parse-events.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h LIB_H += util/pstack.h
@@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o +LIB_OBJS += $(OUTPUT)util/trace-parse-events.o LIB_OBJS += $(OUTPUT)util/svghelper.o LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/hist.o
tools/perf/util/trace-event-parse.c +0 -3125
2,986 lines not on this page · raw message
tools/perf/util/trace-event.h +4 -270
274 lines not on this page · raw message
tools/perf/util/trace-parse-events.c new file +3128 -0
3,128 lines not on this page · raw message
tools/perf/util/trace-parse-events.h new file +273 -0
273 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.5.4
Part of the diff is not shown here. View the raw message.
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Hi Steve:
Quoted 7 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Move the
trace-event-parse.ccode that originally came from trace-cmd into their own files. The new file will be calledtrace-parse-events.c, as the name of trace-cmd's file wasparse-events.ctoo, but it conflicted with theparse-events.cfile in perf that parses the command line.
Quoted 5 lines
This tries to update the code with mimimal changes.
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in
trace-parse-events.candtrace-parse-events.h.
What branch should these apply cleanly to?
David
Quoted 6,875 lines
Signed-off-by Steven Rostedt <[email protected]>--- tools/perf/Makefile | 2 + tools/perf/util/trace-event-parse.c | 3125 --------------------------------- tools/perf/util/trace-event.h | 274 +--- tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++ tools/perf/util/trace-parse-events.h | 273 +++ 5 files changed, 3407 insertions(+), 3395 deletions(-) create mode 100644 tools/perf/util/trace-parse-events.c create mode 100644 tools/perf/util/trace-parse-events.htools/perf/Makefile +2
-0@@ -278,6 +278,7 @@ LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h +LIB_H += util/trace-parse-events.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h LIB_H += util/pstack.h@@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o +LIB_OBJS += $(OUTPUT)util/trace-parse-events.o LIB_OBJS += $(OUTPUT)util/svghelper.o LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/hist.otools/perf/util/trace-event-parse.c +0
-3125@@ -1,3132 +1,7 @@ -/* -* Copyright (C) 2009, Steven Rostedt <[email protected]> -* -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* 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 -* -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* The parts for function graph printing was taken and modified from the -* Linux Kernel that were written by Frederic Weisbecker. -*/ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#undef _GNU_SOURCE#include "../perf.h" #include "util.h" #include "trace-event.h" -int header_page_ts_offset; -int header_page_ts_size; -int header_page_size_offset; -int header_page_size_size; -int header_page_overwrite_offset; -int header_page_overwrite_size; -int header_page_data_offset; -int header_page_data_size; - -bool latency_format; - -static char *input_buf; -static unsigned long long input_buf_ptr; -static unsigned long long input_buf_siz; - -static int cpus; -static int long_size; -static int is_flag_field; -static int is_symbolic_field; - -static struct format_field * -find_any_field (struct event *event,const char *name); - -static void init_input_buf (char *buf,unsigned long long size) -{ - input_buf = buf; - input_buf_siz = size; - input_buf_ptr =0 ; -} - -struct cmdline { -char *comm; -int pid; -}; - -static struct cmdline *cmdlines; -static int cmdline_count; - -static int cmdline_cmp (const void *a,const void *b) -{ -const struct cmdline *ca = a; -const struct cmdline *cb = b; - -if (ca->pid < cb->pid) -return -1 ; -if (ca->pid > cb->pid) -return 1 ; - -return 0 ; -} - -void parse_cmdlines(char *file, int size __unused) -{ -struct cmdline_list { -struct cmdline_list *next; -char *comm; -int pid; - } *list =NULL , *item; -char *line; -char *next =NULL ; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - item =malloc_or_die (sizeof (*item)); -sscanf (line,"%d %as" , &item->pid, - (float *)(void *)&item->comm);/* workaround gcc warning */ - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - cmdline_count++; - } - - cmdlines =malloc_or_die (sizeof (*cmdlines) * cmdline_count); - - i =0 ; -while (list) { - cmdlines[i].pid = list->pid; - cmdlines[i].comm = list->comm; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (cmdlines, cmdline_count,sizeof (*cmdlines), cmdline_cmp); -} - -static struct func_map { -unsigned long long addr; -char *func; -char *mod; -} *func_list; -static unsigned int func_count; - -static int func_cmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if (fa->addr < fb->addr) -return -1 ; -if (fa->addr > fb->addr) -return 1 ; - -return 0 ; -} - -void parse_proc_kallsyms(char *file, unsigned int size __unused) -{ -struct func_list { -struct func_list *next; -unsigned long long addr; -char *func; -char *mod; - } *list =NULL , *item; -char *line; -char *next =NULL ; -char *addr_str; -char ch; -int ret__used ; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - item =malloc_or_die (sizeof (*item)); - item->mod =NULL ; - ret =sscanf (line,"%as %c %as\t[%as" , - (float *)(void *)&addr_str,/* workaround gcc warning */ - &ch, - (float *)(void *)&item->func, - (float *)(void *)&item->mod); - item->addr =strtoull (addr_str,NULL ,16 ); -free (addr_str); - -/* truncate the extra ']' */ -if (item->mod) - item->mod[strlen (item->mod) -1 ] =0 ; - - - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - func_count++; - } - - func_list =malloc_or_die (sizeof (*func_list) * (func_count +1 )); - - i =0 ; -while (list) { - func_list[i].func = list->func; - func_list[i].addr = list->addr; - func_list[i].mod = list->mod; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (func_list, func_count,sizeof (*func_list), func_cmp); - -/* -* Add a special record at the end. -*/ - func_list[func_count].func =NULL ; - func_list[func_count].addr =0 ; - func_list[func_count].mod =NULL ; -} - -/* -* We are searching for a record in between, not an exact -* match. -*/ -static int func_bcmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if ((fa->addr == fb->addr) || - - (fa->addr > fb->addr && - fa->addr < (fb+1 )->addr)) -return 0 ; - -if (fa->addr < fb->addr) -return -1 ; - -return 1 ; -} - -static struct func_map *find_func (unsigned long long addr) -{ -struct func_map *func; -struct func_map key; - - key.addr = addr; - - func =bsearch (&key, func_list, func_count,sizeof (*func_list), - func_bcmp); - -return func; -} - -void print_funcs (void ) -{ -int i; - -for (i =0 ; i < (int )func_count; i++) { -printf ("%016llx %s" , - func_list[i].addr, - func_list[i].func); -if (func_list[i].mod) -printf (" [%s]\n" , func_list[i].mod); -else -printf ("\n" ); - } -} - -static struct printk_map { -unsigned long long addr; -char *printk; -} *printk_list; -static unsigned int printk_count; - -static int printk_cmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if (fa->addr < fb->addr) -return -1 ; -if (fa->addr > fb->addr) -return 1 ; - -return 0 ; -} - -static struct printk_map *find_printk (unsigned long long addr) -{ -struct printk_map *printk; -struct printk_map key; - - key.addr = addr; - - printk =bsearch (&key, printk_list, printk_count,sizeof (*printk_list), - printk_cmp); - -return printk; -} - -void parse_ftrace_printk(char *file, unsigned int size __unused) -{ -struct printk_list { -struct printk_list *next; -unsigned long long addr; -char *printk; - } *list =NULL , *item; -char *line; -char *next =NULL ; -char *addr_str; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - addr_str =strsep (&line,":" ); -if (!line) { -warning ("error parsing print strings" ); -break ; - } - item =malloc_or_die (sizeof (*item)); - item->addr =strtoull (addr_str,NULL ,16 ); -/* fmt still has a space, skip it */ - item->printk =strdup (line+1 ); - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - printk_count++; - } - - printk_list =malloc_or_die (sizeof (*printk_list) * printk_count +1 ); - - i =0 ; -while (list) { - printk_list[i].printk = list->printk; - printk_list[i].addr = list->addr; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (printk_list, printk_count,sizeof (*printk_list), printk_cmp); -} - -void print_printk (void ) -{ -int i; - -for (i =0 ; i < (int )printk_count; i++) { -printf ("%016llx %s\n" , - printk_list[i].addr, - printk_list[i].printk); - } -} - -static struct event *alloc_event (void ) -{ -struct event *event; - - event =malloc_or_die (sizeof (*event)); -memset (event,0 ,sizeof (*event)); - -return event; -} - -enum event_type { -EVENT_ERROR , -EVENT_NONE , -EVENT_SPACE , -EVENT_NEWLINE , -EVENT_OP , -EVENT_DELIM , -EVENT_ITEM , -EVENT_DQUOTE , -EVENT_SQUOTE , -}; - -static struct event *event_list; - -static void add_event (struct event *event) -{ - event->next = event_list; - event_list = event; -} - -static int event_item_type (enum event_type type) -{ -switch (type) { - case EVENT_ITEM ... EVENT_SQUOTE: -return 1 ; - case EVENT_ERROR ... EVENT_DELIM: -default : -return 0 ; - } -} - -static void free_arg (struct print_arg *arg) -{ -if (!arg) -return ; - -switch (arg->type) { -case PRINT_ATOM : -if (arg->atom.atom) -free (arg->atom.atom); -break ; -case PRINT_NULL : - case PRINT_FIELD ... PRINT_OP: -default : -/* todo */ -break ; - } - -free (arg); -} - -static enum event_type get_type (int ch) -{ -if (ch =='\n' ) -return EVENT_NEWLINE ; -if (isspace (ch)) -return EVENT_SPACE ; -if (isalnum (ch) || ch =='_' ) -return EVENT_ITEM ; -if (ch =='\'' ) -return EVENT_SQUOTE ; -if (ch =='"' ) -return EVENT_DQUOTE ; -if (!isprint (ch)) -return EVENT_NONE ; -if (ch =='(' || ch ==')' || ch ==',' ) -return EVENT_DELIM ; - -return EVENT_OP ; -} - -static int __read_char (void ) -{ -if (input_buf_ptr >= input_buf_siz) -return -1 ; - -return input_buf[input_buf_ptr++]; -} - -static int __peek_char (void ) -{ -if (input_buf_ptr >= input_buf_siz) -return -1 ; - -return input_buf[input_buf_ptr]; -} - -static enum event_type __read_token (char **tok) -{ -char buf[BUFSIZ ]; -int ch, last_ch, quote_ch, next_ch; -int i =0 ; -int tok_size =0 ; -enum event_type type; - - *tok =NULL ; - - - ch =__read_char (); -if (ch <0 ) -return EVENT_NONE ; - - type =get_type (ch); -if (type ==EVENT_NONE ) -return type; - - buf[i++] = ch; - -switch (type) { -case EVENT_NEWLINE : -case EVENT_DELIM : - *tok =malloc_or_die (2 ); - (*tok)[0 ] = ch; - (*tok)[1 ] =0 ; -return type; - -case EVENT_OP : -switch (ch) { -case '-' : - next_ch =__peek_char (); -if (next_ch =='>' ) { - buf[i++] =__read_char (); -break ; - } -/* fall through */ -case '+' : -case '|' : -case '&' : -case '>' : -case '<' : - last_ch = ch; - ch =__peek_char (); -if (ch != last_ch) - goto test_equal; - buf[i++] =__read_char (); -switch (last_ch) { -case '>' : -case '<' : - goto test_equal; -default : -break ; - } -break ; -case '!' : -case '=' : - goto test_equal; -default :/* what should we do instead? */ -break ; - } - buf[i] =0 ; - *tok =strdup (buf); -return type; - - test_equal: - ch =__peek_char (); -if (ch =='=' ) - buf[i++] =__read_char (); -break ; - -case EVENT_DQUOTE : -case EVENT_SQUOTE : -/* don't keep quotes */ - i--; - quote_ch = ch; - last_ch =0 ; -do { -if (i == (BUFSIZ -1 )) { - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size +BUFSIZ ); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); - -if (!*tok) -return EVENT_NONE ; - tok_size +=BUFSIZ ; - i =0 ; - } - last_ch = ch; - ch =__read_char (); - buf[i++] = ch; -/* the '\' '\' will cancel itself */ -if (ch =='\\' && last_ch =='\\' ) - last_ch =0 ; - }while (ch != quote_ch || last_ch =='\\' ); -/* remove the last quote */ - i--; - goto out; - - case EVENT_ERROR ... EVENT_SPACE: -case EVENT_ITEM : -default : -break ; - } - -while (get_type (__peek_char ()) == type) { -if (i == (BUFSIZ -1 )) { - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size +BUFSIZ ); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); - -if (!*tok) -return EVENT_NONE ; - tok_size +=BUFSIZ ; - i =0 ; - } - ch =__read_char (); - buf[i++] = ch; - } - - out: - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size + i); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); -if (!*tok) -return EVENT_NONE ; - -return type; -} - -static void free_token (char *tok) -{ -if (tok) -free (tok); -} - -static enum event_type read_token (char **tok) -{ -enum event_type type; - -for (;;) { - type =__read_token (tok); -if (type !=EVENT_SPACE ) -return type; - -free_token (*tok); - } - -/* not reached */ -return EVENT_NONE ; -} - -/* no newline */ -static enum event_type read_token_item (char **tok) -{ -enum event_type type; - -for (;;) { - type =__read_token (tok); -if (type !=EVENT_SPACE && type !=EVENT_NEWLINE ) -return type; - -free_token (*tok); - } - -/* not reached */ -return EVENT_NONE ; -} - -static int test_type (enum event_type type,enum event_type expect) -{ -if (type != expect) { -warning ("Error: expected type %d but read %d" , - expect, type); -return -1 ; - } -return 0 ; -} - -static int __test_type_token (enum event_type type,char *token, -enum event_type expect,const char *expect_tok, -bool warn) -{ -if (type != expect) { -if (warn) -warning ("Error: expected type %d but read %d" , - expect, type); -return -1 ; - } - -if (strcmp (token, expect_tok) !=0 ) { -if (warn) -warning ("Error: expected '%s' but read '%s'" , - expect_tok, token); -return -1 ; - } -return 0 ; -} - -static int test_type_token (enum event_type type,char *token, -enum event_type expect,const char *expect_tok) -{ -return __test_type_token (type, token, expect, expect_tok, true); -} - -static int __read_expect_type (enum event_type expect,char **tok,int newline_ok) -{ -enum event_type type; - -if (newline_ok) - type =read_token (tok); -else - type =read_token_item (tok); -return test_type (type, expect); -} - -static int read_expect_type (enum event_type expect,char **tok) -{ -return __read_expect_type (expect, tok,1 ); -} - -static int __read_expected (enum event_type expect,const char *str, -int newline_ok,bool warn) -{ -enum event_type type; -char *token; -int ret; - -if (newline_ok) - type =read_token (&token); -else - type =read_token_item (&token); - - ret =__test_type_token (type, token, expect, str, warn); - -free_token (token); - -return ret; -} - -static int read_expected (enum event_type expect,const char *str) -{ -return __read_expected (expect, str,1 , true); -} - -static int read_expected_item (enum event_type expect,const char *str) -{ -return __read_expected (expect, str,0 , true); -} - -static char *event_read_name (void ) -{ -char *token; - -if (read_expected (EVENT_ITEM ,"name" ) <0 ) -return NULL ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return NULL ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - -return token; - - fail: -free_token (token); -return NULL ; -} - -static int event_read_id (void ) -{ -char *token; -int id; - -if (read_expected_item (EVENT_ITEM ,"ID" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - id =strtoul (token,NULL ,0 ); -free_token (token); -return id; - - fail: -free_token (token); -return -1 ; -} - -static int field_is_string (struct format_field *field) -{ -if ((field->flags &FIELD_IS_ARRAY ) && - (!strstr (field->type,"char" ) || !strstr (field->type,"u8" ) || - !strstr (field->type,"s8" ))) -return 1 ; - -return 0 ; -} - -static int field_is_dynamic (struct format_field *field) -{ -if (!strncmp (field->type,"__data_loc" ,10 )) -return 1 ; - -return 0 ; -} - -static int event_read_fields (struct event *event,struct format_field **fields) -{ -struct format_field *field =NULL ; -enum event_type type; -char *token; -char *last_token; -int count =0 ; - -do { - type =read_token (&token); -if (type ==EVENT_NEWLINE ) { -free_token (token); -return count; - } - - count++; - -if (test_type_token (type, token,EVENT_ITEM ,"field" )) - goto fail; -free_token (token); - - type =read_token (&token); -/* -* The ftrace fields may still use the "special" name. -* Just ignore it. -*/ -if (event->flags &EVENT_FL_ISFTRACE && - type ==EVENT_ITEM &&strcmp (token,"special" ) ==0 ) { -free_token (token); - type =read_token (&token); - } - -if (test_type_token (type, token,EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - last_token = token; - - field =malloc_or_die (sizeof (*field)); -memset (field,0 ,sizeof (*field)); - -/* read the rest of the type */ -for (;;) { - type =read_token (&token); -if (type ==EVENT_ITEM || - (type ==EVENT_OP &&strcmp (token,"*" ) ==0 ) || -/* -* Some of the ftrace fields are broken and have -* an illegal "." in them. -*/ - (event->flags &EVENT_FL_ISFTRACE && - type ==EVENT_OP &&strcmp (token,"." ) ==0 )) { - -if (strcmp (token,"*" ) ==0 ) - field->flags |=FIELD_IS_POINTER ; - -if (field->type) { - field->type =realloc (field->type, -strlen (field->type) + -strlen (last_token) +2 ); -strcat (field->type," " ); -strcat (field->type, last_token); - }else - field->type = last_token; - last_token = token; -continue ; - } - -break ; - } - -if (!field->type) { -die ("no type found" ); - goto fail; - } - field->name = last_token; - -if (test_type (type,EVENT_OP )) - goto fail; - -if (strcmp (token,"[" ) ==0 ) { -enum event_type last_type = type; -char *brackets = token; -int len; - - field->flags |=FIELD_IS_ARRAY ; - - type =read_token (&token); -while (strcmp (token,"]" ) !=0 ) { -if (last_type ==EVENT_ITEM && - type ==EVENT_ITEM ) - len =2 ; -else - len =1 ; - last_type = type; - - brackets =realloc (brackets, -strlen (brackets) + -strlen (token) + len); -if (len ==2 ) -strcat (brackets," " ); -strcat (brackets, token); -free_token (token); - type =read_token (&token); -if (type ==EVENT_NONE ) { -die ("failed to find token" ); - goto fail; - } - } - -free_token (token); - - brackets =realloc (brackets,strlen (brackets) +2 ); -strcat (brackets,"]" ); - -/* add brackets to type */ - - type =read_token (&token); -/* -* If the next token is not an OP, then it is of -* the format: type [] item; -*/ -if (type ==EVENT_ITEM ) { - field->type =realloc (field->type, -strlen (field->type) + -strlen (field->name) + -strlen (brackets) +2 ); -strcat (field->type," " ); -strcat (field->type, field->name); -free_token (field->name); -strcat (field->type, brackets); - field->name = token; - type =read_token (&token); - }else { - field->type =realloc (field->type, -strlen (field->type) + -strlen (brackets) +1 ); -strcat (field->type, brackets); - } -free (brackets); - } - -if (field_is_string (field)) { - field->flags |=FIELD_IS_STRING ; -if (field_is_dynamic (field)) - field->flags |=FIELD_IS_DYNAMIC ; - } - -if (test_type_token (type, token,EVENT_OP ,";" )) - goto fail; -free_token (token); - -if (read_expected (EVENT_ITEM ,"offset" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - field->offset =strtoul (token,NULL ,0 ); -free_token (token); - -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_ITEM ,"size" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - field->size =strtoul (token,NULL ,0 ); -free_token (token); - -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - - type =read_token (&token); -if (type !=EVENT_NEWLINE ) { -/* newer versions of the kernel have a "signed" type */ -if (test_type_token (type, token,EVENT_ITEM ,"signed" )) - goto fail; - -free_token (token); - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - -if (strtoul (token,NULL ,0 )) - field->flags |=FIELD_IS_SIGNED ; - -free_token (token); -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_NEWLINE , &token)) - goto fail; - } - -free_token (token); - - *fields = field; - fields = &field->next; - - }while (1 ); - -return 0 ; - -fail: -free_token (token); -fail_expect: -if (field) -free (field); -return -1 ; -} - -static int event_read_format (struct event *event) -{ -char *token; -int ret; - -if (read_expected_item (EVENT_ITEM ,"format" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_NEWLINE , &token)) - goto fail; -free_token (token); - - ret =event_read_fields (event, &event->format.common_fields); -if (ret <0 ) -return ret; - event->format.nr_common = ret; - - ret =event_read_fields (event, &event->format.fields); -if (ret <0 ) -return ret; - event->format.nr_fields = ret; - -return 0 ; - - fail: -free_token (token); -return -1 ; -} - -enum event_type -process_arg_token (struct event *event,struct print_arg *arg, -char **tok,enum event_type type); - -static enum event_type -process_arg (struct event *event,struct print_arg *arg,char **tok) -{ -enum event_type type; -char *token; - - type =read_token (&token); - *tok = token; - -return process_arg_token (event, arg, tok, type); -} - -static enum event_type -process_cond (struct event *event,struct print_arg *top,char **tok) -{ -struct print_arg *arg, *left, *right; -enum event_type type; -char *token =NULL ; - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - left =malloc_or_die (sizeof (*left)); - - right =malloc_or_die (sizeof (*right)); - - arg->type =PRINT_OP ; - arg->op.left = left; - arg->op.right = right; - - *tok =NULL ; - type =process_arg (event, left, &token); -if (test_type_token (type, token,EVENT_OP ,":" )) - goto out_free; - - arg->op.op = token; - - type =process_arg (event, right, &token); - - top->op.right = arg; - - *tok = token; -return type; - -out_free: -free_token (*tok); -free (right); -free (left); -free_arg (arg); -return EVENT_ERROR ; -} - -static enum event_type -process_array (struct event *event,struct print_arg *top,char **tok) -{ -struct print_arg *arg; -enum event_type type; -char *token =NULL ; - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - *tok =NULL ; - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_OP ,"]" )) - goto out_free; - - top->op.right = arg; - -free_token (token); - type =read_token_item (&token); - *tok = token; - -return type; - -out_free: -free_token (*tok); -free_arg (arg); -return EVENT_ERROR ; -} - -static int get_op_prio (char *op) -{ -if (!op[1 ]) { -switch (op[0 ]) { -case '*' : -case '/' : -case '%' : -return 6 ; -case '+' : -case '-' : -return 7 ; -/* '>>' and '<<' are 8 */ -case '<' : -case '>' : -return 9 ; -/* '==' and '!=' are 10 */ -case '&' : -return 11 ; -case '^' : -return 12 ; -case '|' : -return 13 ; -case '?' : -return 16 ; -default : -die ("unknown op '%c'" , op[0 ]); -return -1 ; - } - }else { -if (strcmp (op,"++" ) ==0 || -strcmp (op,"--" ) ==0 ) { -return 3 ; - }else if (strcmp (op,">>" ) ==0 || -strcmp (op,"<<" ) ==0 ) { -return 8 ; - }else if (strcmp (op,">=" ) ==0 || -strcmp (op,"<=" ) ==0 ) { -return 9 ; - }else if (strcmp (op,"==" ) ==0 || -strcmp (op,"!=" ) ==0 ) { -return 10 ; - }else if (strcmp (op,"&&" ) ==0 ) { -return 14 ; - }else if (strcmp (op,"||" ) ==0 ) { -return 15 ; - }else { -die ("unknown op '%s'" , op); -return -1 ; - } - } -} - -static void set_op_prio (struct print_arg *arg) -{ - -/* single ops are the greatest */ -if (!arg->op.left || arg->op.left->type ==PRINT_NULL ) { - arg->op.prio =0 ; -return ; - } - - arg->op.prio =get_op_prio (arg->op.op); -} - -static enum event_type -process_op (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *left, *right =NULL ; -enum event_type type; -char *token; - -/* the op is passed in via tok */ - token = *tok; - -if (arg->type ==PRINT_OP && !arg->op.left) { -/* handle single op */ -if (token[1 ]) { -die ("bad op token %s" , token); -return EVENT_ERROR ; - } -switch (token[0 ]) { -case '!' : -case '+' : -case '-' : -break ; -default : -die ("bad op token %s" , token); -return EVENT_ERROR ; - } - -/* make an empty left */ - left =malloc_or_die (sizeof (*left)); - left->type =PRINT_NULL ; - arg->op.left = left; - - right =malloc_or_die (sizeof (*right)); - arg->op.right = right; - - type =process_arg (event, right, tok); - - }else if (strcmp (token,"?" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); -/* copy the top arg to the left */ - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - arg->op.prio =0 ; - - type =process_cond (event, arg, tok); - - }else if (strcmp (token,">>" ) ==0 || -strcmp (token,"<<" ) ==0 || -strcmp (token,"&" ) ==0 || -strcmp (token,"|" ) ==0 || -strcmp (token,"&&" ) ==0 || -strcmp (token,"||" ) ==0 || -strcmp (token,"-" ) ==0 || -strcmp (token,"+" ) ==0 || -strcmp (token,"*" ) ==0 || -strcmp (token,"^" ) ==0 || -strcmp (token,"/" ) ==0 || -strcmp (token,"<" ) ==0 || -strcmp (token,">" ) ==0 || -strcmp (token,"==" ) ==0 || -strcmp (token,"!=" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); - -/* copy the top arg to the left */ - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - -set_op_prio (arg); - - right =malloc_or_die (sizeof (*right)); - - type =read_token_item (&token); - *tok = token; - -/* could just be a type pointer */ -if ((strcmp (arg->op.op,"*" ) ==0 ) && - type ==EVENT_DELIM && (strcmp (token,")" ) ==0 )) { -if (left->type !=PRINT_ATOM ) -die ("bad pointer type" ); - left->atom.atom =realloc (left->atom.atom, -sizeof (left->atom.atom) +3 ); -strcat (left->atom.atom," *" ); - *arg = *left; -free (arg); - -return type; - } - - type =process_arg_token (event, right, tok, type); - - arg->op.right = right; - - }else if (strcmp (token,"[" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - - arg->op.prio =0 ; - type =process_array (event, arg, tok); - - }else { -warning ("unknown op '%s'" , token); - event->flags |=EVENT_FL_FAILED ; -/* the arg is now the left side */ -return EVENT_NONE ; - } - -if (type ==EVENT_OP ) { -int prio; - -/* higher prios need to be closer to the root */ - prio =get_op_prio (*tok); - -if (prio > arg->op.prio) -return process_op (event, arg, tok); - -return process_op (event, right, tok); - } - -return type; -} - -static enum event_type -process_entry(struct event *event __unused, struct print_arg *arg, -char **tok) -{ -enum event_type type; -char *field; -char *token; - -if (read_expected (EVENT_OP ,"->" ) <0 ) -return EVENT_ERROR ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - field = token; - - arg->type =PRINT_FIELD ; - arg->field.name = field; - -if (is_flag_field) { - arg->field.field =find_any_field (event, arg->field.name); - arg->field.field->flags |=FIELD_IS_FLAG ; - is_flag_field =0 ; - }else if (is_symbolic_field) { - arg->field.field =find_any_field (event, arg->field.name); - arg->field.field->flags |=FIELD_IS_SYMBOLIC ; - is_symbolic_field =0 ; - } - - type =read_token (&token); - *tok = token; - -return type; - -fail: -free_token (token); -return EVENT_ERROR ; -} - -static char *arg_eval (struct print_arg *arg); - -static long long arg_num_eval (struct print_arg *arg) -{ -long long left, right; -long long val =0 ; - -switch (arg->type) { -case PRINT_ATOM : - val =strtoll (arg->atom.atom,NULL ,0 ); -break ; -case PRINT_TYPE : - val =arg_num_eval (arg->typecast.item); -break ; -case PRINT_OP : -switch (arg->op.op[0 ]) { -case '|' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -if (arg->op.op[1 ]) - val = left || right; -else - val = left | right; -break ; -case '&' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -if (arg->op.op[1 ]) - val = left && right; -else - val = left & right; -break ; -case '<' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -switch (arg->op.op[1 ]) { -case 0 : - val = left < right; -break ; -case '<' : - val = left << right; -break ; -case '=' : - val = left <= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '>' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -switch (arg->op.op[1 ]) { -case 0 : - val = left > right; -break ; -case '>' : - val = left >> right; -break ; -case '=' : - val = left >= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '=' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); - -if (arg->op.op[1 ] !='=' ) -die ("unknown op '%s'" , arg->op.op); - - val = left == right; -break ; -case '!' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); - -switch (arg->op.op[1 ]) { -case '=' : - val = left != right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; - -case PRINT_NULL : - case PRINT_FIELD ... PRINT_SYMBOL: -case PRINT_STRING : -default : -die ("invalid eval type %d" , arg->type); - - } -return val; -} - -static char *arg_eval (struct print_arg *arg) -{ -long long val; -static char buf[20 ]; - -switch (arg->type) { -case PRINT_ATOM : -return arg->atom.atom; -case PRINT_TYPE : -return arg_eval (arg->typecast.item); -case PRINT_OP : - val =arg_num_eval (arg); -sprintf (buf,"%lld" , val); -return buf; - -case PRINT_NULL : - case PRINT_FIELD ... PRINT_SYMBOL: -case PRINT_STRING : -default : -die ("invalid eval type %d" , arg->type); -break ; - } - -return NULL ; -} - -static enum event_type -process_fields (struct event *event,struct print_flag_sym **list,char **tok) -{ -enum event_type type; -struct print_arg *arg =NULL ; -struct print_flag_sym *field; -char *token =NULL ; -char *value; - -do { -free_token (token); - type =read_token_item (&token); -if (test_type_token (type, token,EVENT_OP ,"{" )) -break ; - - arg =malloc_or_die (sizeof (*arg)); - -free_token (token); - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - field =malloc_or_die (sizeof (*field)); -memset (field,0 ,sizeof (*field)); - - value =arg_eval (arg); - field->value =strdup (value); - -free_token (token); - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_OP ,"}" )) - goto out_free; - - value =arg_eval (arg); - field->str =strdup (value); -free_arg (arg); - arg =NULL ; - - *list = field; - list = &field->next; - -free_token (token); - type =read_token_item (&token); - }while (type ==EVENT_DELIM &&strcmp (token,"," ) ==0 ); - - *tok = token; -return type; - -out_free: -free_arg (arg); -free_token (token); - -return EVENT_ERROR ; -} - -static enum event_type -process_flags (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *field; -enum event_type type; -char *token; - -memset (arg,0 ,sizeof (*arg)); - arg->type =PRINT_FLAGS ; - -if (read_expected_item (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - - field =malloc_or_die (sizeof (*field)); - - type =process_arg (event, field, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - arg->flags.field = field; - - type =read_token_item (&token); -if (event_item_type (type)) { - arg->flags.delim = token; - type =read_token_item (&token); - } - -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - type =process_fields (event, &arg->flags.flags, &token); -if (test_type_token (type, token,EVENT_DELIM ,")" )) - goto out_free; - -free_token (token); - type =read_token_item (tok); -return type; - -out_free: -free_token (token); -return EVENT_ERROR ; -} - -static enum event_type -process_symbols (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *field; -enum event_type type; -char *token; - -memset (arg,0 ,sizeof (*arg)); - arg->type =PRINT_SYMBOL ; - -if (read_expected_item (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - - field =malloc_or_die (sizeof (*field)); - - type =process_arg (event, field, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - arg->symbol.field = field; - - type =process_fields (event, &arg->symbol.symbols, &token); -if (test_type_token (type, token,EVENT_DELIM ,")" )) - goto out_free; - -free_token (token); - type =read_token_item (tok); -return type; - -out_free: -free_token (token); -return EVENT_ERROR ; -} - -static enum event_type -process_paren (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *item_arg; -enum event_type type; -char *token; - - type =process_arg (event, arg, &token); - -if (type ==EVENT_ERROR ) -return EVENT_ERROR ; - -if (type ==EVENT_OP ) - type =process_op (event, arg, &token); - -if (type ==EVENT_ERROR ) -return EVENT_ERROR ; - -if (test_type_token (type, token,EVENT_DELIM ,")" )) { -free_token (token); -return EVENT_ERROR ; - } - -free_token (token); - type =read_token_item (&token); - -/* -* If the next token is an item or another open paren, then -* this was a typecast. -*/ -if (event_item_type (type) || - (type ==EVENT_DELIM &&strcmp (token,"(" ) ==0 )) { - -/* make this a typecast and contine */ - -/* prevous must be an atom */ -if (arg->type !=PRINT_ATOM ) -die ("previous needed to be PRINT_ATOM" ); - - item_arg =malloc_or_die (sizeof (*item_arg)); - - arg->type =PRINT_TYPE ; - arg->typecast.type = arg->atom.atom; - arg->typecast.item = item_arg; - type =process_arg_token (event, item_arg, &token, type); - - } - - *tok = token; -return type; -} - - -static enum event_type -process_str(struct event *event __unused, struct print_arg *arg, char **tok) -{ -enum event_type type; -char *token; - -if (read_expected (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - arg->type =PRINT_STRING ; - arg->string.string = token; - arg->string.offset =-1 ; - -if (read_expected (EVENT_DELIM ,")" ) <0 ) -return EVENT_ERROR ; - - type =read_token (&token); - *tok = token; - -return type; -fail: -free_token (token); -return EVENT_ERROR ; -} - -enum event_type -process_arg_token (struct event *event,struct print_arg *arg, -char **tok,enum event_type type) -{ -char *token; -char *atom; - - token = *tok; - -switch (type) { -case EVENT_ITEM : -if (strcmp (token,"REC" ) ==0 ) { -free_token (token); - type =process_entry (event, arg, &token); - }else if (strcmp (token,"__print_flags" ) ==0 ) { -free_token (token); - is_flag_field =1 ; - type =process_flags (event, arg, &token); - }else if (strcmp (token,"__print_symbolic" ) ==0 ) { -free_token (token); - is_symbolic_field =1 ; - type =process_symbols (event, arg, &token); - }else if (strcmp (token,"__get_str" ) ==0 ) { -free_token (token); - type =process_str (event, arg, &token); - }else { - atom = token; -/* test the next token */ - type =read_token_item (&token); - -/* atoms can be more than one token long */ -while (type ==EVENT_ITEM ) { - atom =realloc (atom,strlen (atom) +strlen (token) +2 ); -strcat (atom," " ); -strcat (atom, token); -free_token (token); - type =read_token_item (&token); - } - -/* todo, test for function */ - - arg->type =PRINT_ATOM ; - arg->atom.atom = atom; - } -break ; -case EVENT_DQUOTE : -case EVENT_SQUOTE : - arg->type =PRINT_ATOM ; - arg->atom.atom = token; - type =read_token_item (&token); -break ; -case EVENT_DELIM : -if (strcmp (token,"(" ) ==0 ) { -free_token (token); - type =process_paren (event, arg, &token); -break ; - } -case EVENT_OP : -/* handle single ops */ - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left =NULL ; - type =process_op (event, arg, &token); - -break ; - - case EVENT_ERROR ... EVENT_NEWLINE: -default : -die ("unexpected type %d" , type); - } - *tok = token; - -return type; -} - -static int event_read_print_args (struct event *event,struct print_arg **list) -{ -enum event_type type =EVENT_ERROR ; -struct print_arg *arg; -char *token; -int args =0 ; - -do { -if (type ==EVENT_NEWLINE ) { -free_token (token); - type =read_token_item (&token); -continue ; - } - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - type =process_arg (event, arg, &token); - -if (type ==EVENT_ERROR ) { -free_arg (arg); -return -1 ; - } - - *list = arg; - args++; - -if (type ==EVENT_OP ) { - type =process_op (event, arg, &token); - list = &arg->next; -continue ; - } - -if (type ==EVENT_DELIM &&strcmp (token,"," ) ==0 ) { -free_token (token); - *list = arg; - list = &arg->next; -continue ; - } -break ; - }while (type !=EVENT_NONE ); - -if (type !=EVENT_NONE ) -free_token (token); - -return args; -} - -static int event_read_print (struct event *event) -{ -enum event_type type; -char *token; -int ret; - -if (read_expected_item (EVENT_ITEM ,"print" ) <0 ) -return -1 ; - -if (read_expected (EVENT_ITEM ,"fmt" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_DQUOTE , &token) <0 ) - goto fail; - - concat: - event->print_fmt.format = token; - event->print_fmt.args =NULL ; - -/* ok to have no arg */ - type =read_token_item (&token); - -if (type ==EVENT_NONE ) -return 0 ; - -/* Handle concatination of print lines */ -if (type ==EVENT_DQUOTE ) { -char *cat; - - cat =malloc_or_die (strlen (event->print_fmt.format) + -strlen (token) +1 ); -strcpy (cat, event->print_fmt.format); -strcat (cat, token); -free_token (token); -free_token (event->print_fmt.format); - event->print_fmt.format =NULL ; - token = cat; - goto concat; - } - -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto fail; - -free_token (token); - - ret =event_read_print_args (event, &event->print_fmt.args); -if (ret <0 ) -return -1 ; - -return ret; - - fail: -free_token (token); -return -1 ; -} - -static struct format_field * -find_common_field (struct event *event,const char *name) -{ -struct format_field *format; - -for (format = event->format.common_fields; - format; format = format->next) { -if (strcmp (format->name, name) ==0 ) -break ; - } - -return format; -} - -static struct format_field * -find_field (struct event *event,const char *name) -{ -struct format_field *format; - -for (format = event->format.fields; - format; format = format->next) { -if (strcmp (format->name, name) ==0 ) -break ; - } - -return format; -} - -static struct format_field * -find_any_field (struct event *event,const char *name) -{ -struct format_field *format; - - format =find_common_field (event, name); -if (format) -return format; -return find_field (event, name); -} - -unsigned long long read_size (void *ptr,int size) -{ -switch (size) { -case 1 : -return *(unsigned char *)ptr; -case 2 : -return data2host2 (ptr); -case 4 : -return data2host4 (ptr); -case 8 : -return data2host8 (ptr); -default : -/* BUG! */ -return 0 ; - } -} - -unsigned long long -raw_field_value (struct event *event,const char *name,void *data) -{ -struct format_field *field; - - field =find_any_field (event, name); -if (!field) -return 0ULL ; - -return read_size (data + field->offset, field->size); -} - -void *raw_field_ptr (struct event *event,const char *name,void *data) -{ -struct format_field *field; - - field =find_any_field (event, name); -if (!field) -return NULL ; - -if (field->flags &FIELD_IS_DYNAMIC ) { -int offset; - - offset = *(int *)(data + field->offset); - offset &=0xffff ; - -return data + offset; - } - -return data + field->offset; -} - -static int get_common_info (const char *type,int *offset,int *size) -{ -struct event *event; -struct format_field *field; - -/* -* All events should have the same common elements. -* Pick any event to find where the type is; -*/ -if (!event_list) -die ("no event_list!" ); - - event = event_list; - field =find_common_field (event, type); -if (!field) -die ("field '%s' not found" , type); - - *offset = field->offset; - *size = field->size; - -return 0 ; -} - -static int __parse_common (void *data,int *size,int *offset, -const char *name) -{ -int ret; - -if (!*size) { - ret =get_common_info (name, offset, size); -if (ret <0 ) -return ret; - } -return read_size (data + *offset, *size); -} - -int trace_parse_common_type (void *data) -{ -static int type_offset; -static int type_size; - -return __parse_common (data, &type_size, &type_offset, -"common_type" ); -} - -int trace_parse_common_pid (void *data) -{ -static int pid_offset; -static int pid_size; - -return __parse_common (data, &pid_size, &pid_offset, -"common_pid" ); -} - -int parse_common_pc (void *data) -{ -static int pc_offset; -static int pc_size; - -return __parse_common (data, &pc_size, &pc_offset, -"common_preempt_count" ); -} - -int parse_common_flags (void *data) -{ -static int flags_offset; -static int flags_size; - -return __parse_common (data, &flags_size, &flags_offset, -"common_flags" ); -} - -int parse_common_lock_depth (void *data) -{ -static int ld_offset; -static int ld_size; -int ret; - - ret =__parse_common (data, &ld_size, &ld_offset, -"common_lock_depth" ); -if (ret <0 ) -return -1 ; - -return ret; -} - -struct event *trace_find_event (int id) -{ -struct event *event; - -for (event = event_list; event; event = event->next) { -if (event->id == id) -break ; - } -return event; -} - -struct event *trace_find_next_event (struct event *event) -{ -if (!event) -return event_list; - -return event->next; -} - -static unsigned long long eval_num_arg (void *data,int size, -struct event *event,struct print_arg *arg) -{ -unsigned long long val =0 ; -unsigned long long left, right; -struct print_arg *larg; - -switch (arg->type) { -case PRINT_NULL : -/* ?? */ -return 0 ; -case PRINT_ATOM : -return strtoull (arg->atom.atom,NULL ,0 ); -case PRINT_FIELD : -if (!arg->field.field) { - arg->field.field =find_any_field (event, arg->field.name); -if (!arg->field.field) -die ("field %s not found" , arg->field.name); - } -/* must be a number */ - val =read_size (data + arg->field.field->offset, - arg->field.field->size); -break ; -case PRINT_FLAGS : -case PRINT_SYMBOL : -break ; -case PRINT_TYPE : -return eval_num_arg (data, size, event, arg->typecast.item); -case PRINT_STRING : -return 0 ; -break ; -case PRINT_OP : -if (strcmp (arg->op.op,"[" ) ==0 ) { -/* -* Arrays are special, since we don't want -* to read the arg as is. -*/ -if (arg->op.left->type !=PRINT_FIELD ) - goto default_op;/* oops, all bets off */ - larg = arg->op.left; -if (!larg->field.field) { - larg->field.field = -find_any_field (event, larg->field.name); -if (!larg->field.field) -die ("field %s not found" , larg->field.name); - } - right =eval_num_arg (data, size, event, arg->op.right); - val =read_size (data + larg->field.field->offset + - right * long_size, long_size); -break ; - } - default_op: - left =eval_num_arg (data, size, event, arg->op.left); - right =eval_num_arg (data, size, event, arg->op.right); -switch (arg->op.op[0 ]) { -case '|' : -if (arg->op.op[1 ]) - val = left || right; -else - val = left | right; -break ; -case '&' : -if (arg->op.op[1 ]) - val = left && right; -else - val = left & right; -break ; -case '<' : -switch (arg->op.op[1 ]) { -case 0 : - val = left < right; -break ; -case '<' : - val = left << right; -break ; -case '=' : - val = left <= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '>' : -switch (arg->op.op[1 ]) { -case 0 : - val = left > right; -break ; -case '>' : - val = left >> right; -break ; -case '=' : - val = left >= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '=' : -if (arg->op.op[1 ] !='=' ) -die ("unknown op '%s'" , arg->op.op); - val = left == right; -break ; -case '-' : - val = left - right; -break ; -case '+' : - val = left + right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -default :/* not sure what to do there */ -return 0 ; - } -return val; -} - -struct flag { -const char *name; -unsigned long long value; -}; - -static const struct flag flags[] = { - {"HI_SOFTIRQ" ,0 }, - {"TIMER_SOFTIRQ" ,1 }, - {"NET_TX_SOFTIRQ" ,2 }, - {"NET_RX_SOFTIRQ" ,3 }, - {"BLOCK_SOFTIRQ" ,4 }, - {"BLOCK_IOPOLL_SOFTIRQ" ,5 }, - {"TASKLET_SOFTIRQ" ,6 }, - {"SCHED_SOFTIRQ" ,7 }, - {"HRTIMER_SOFTIRQ" ,8 }, - {"RCU_SOFTIRQ" ,9 }, - - {"HRTIMER_NORESTART" ,0 }, - {"HRTIMER_RESTART" ,1 }, -}; - -unsigned long long eval_flag (const char *flag) -{ -int i; - -/* -* Some flags in the format files do not get converted. -* If the flag is not numeric, see if it is something that -* we already know about. -*/ -if (isdigit (flag[0 ])) -return strtoull (flag,NULL ,0 ); - -for (i =0 ; i < (int )(sizeof (flags)/sizeof (flags[0 ])); i++) -if (strcmp (flags[i].name, flag) ==0 ) -return flags[i].value; - -return 0 ; -} - -static void print_str_arg (void *data,int size, -struct event *event,struct print_arg *arg) -{ -struct print_flag_sym *flag; -unsigned long long val, fval; -char *str; -int print; - -switch (arg->type) { -case PRINT_NULL : -/* ?? */ -return ; -case PRINT_ATOM : -printf ("%s" , arg->atom.atom); -return ; -case PRINT_FIELD : -if (!arg->field.field) { - arg->field.field =find_any_field (event, arg->field.name); -if (!arg->field.field) -die ("field %s not found" , arg->field.name); - } - str =malloc_or_die (arg->field.field->size +1 ); -memcpy (str, data + arg->field.field->offset, - arg->field.field->size); - str[arg->field.field->size] =0 ; -printf ("%s" , str); -free (str); -break ; -case PRINT_FLAGS : - val =eval_num_arg (data, size, event, arg->flags.field); - print =0 ; -for (flag = arg->flags.flags; flag; flag = flag->next) { - fval =eval_flag (flag->value); -if (!val && !fval) { -printf ("%s" , flag->str); -break ; - } -if (fval && (val & fval) == fval) { -if (print && arg->flags.delim) -printf ("%s" , arg->flags.delim); -printf ("%s" , flag->str); - print =1 ; - val &= ~fval; - } - } -break ; -case PRINT_SYMBOL : - val =eval_num_arg (data, size, event, arg->symbol.field); -for (flag = arg->symbol.symbols; flag; flag = flag->next) { - fval =eval_flag (flag->value); -if (val == fval) { -printf ("%s" , flag->str); -break ; - } - } -break ; - -case PRINT_TYPE : -break ; -case PRINT_STRING : { -int str_offset; - -if (arg->string.offset ==-1 ) { -struct format_field *f; - - f =find_any_field (event, arg->string.string); - arg->string.offset = f->offset; - } - str_offset = *(int *)(data + arg->string.offset); - str_offset &=0xffff ; -printf ("%s" , ((char *)data) + str_offset); -break ; - } -case PRINT_OP : -/* -* The only op for string should be ? : -*/ -if (arg->op.op[0 ] !='?' ) -return ; - val =eval_num_arg (data, size, event, arg->op.left); -if (val) -print_str_arg (data, size, event, arg->op.right->op.left); -else -print_str_arg (data, size, event, arg->op.right->op.right); -break ; -default : -/* well... */ -break ; - } -} - -static struct print_arg *make_bprint_args (char *fmt,void *data,int size,struct event *event) -{ -static struct format_field *field, *ip_field; -struct print_arg *args, *arg, **next; -unsigned long long ip, val; -char *ptr; -void *bptr; - -if (!field) { - field =find_field (event,"buf" ); -if (!field) -die ("can't find buffer field for binary printk" ); - ip_field =find_field (event,"ip" ); -if (!ip_field) -die ("can't find ip field for binary printk" ); - } - - ip =read_size (data + ip_field->offset, ip_field->size); - -/* -* The first arg is the IP pointer. -*/ - args =malloc_or_die (sizeof (*args)); - arg = args; - arg->next =NULL ; - next = &arg->next; - - arg->type =PRINT_ATOM ; - arg->atom.atom =malloc_or_die (32 ); -sprintf (arg->atom.atom,"%lld" , ip); - -/* skip the first "%pf : " */ -for (ptr = fmt +6 , bptr = data + field->offset; - bptr < data + size && *ptr; ptr++) { -int ls =0 ; - -if (*ptr =='%' ) { - process_again: - ptr++; -switch (*ptr) { -case '%' : -break ; -case 'l' : - ls++; - goto process_again; -case 'L' : - ls =2 ; - goto process_again; - case '0' ... '9': - goto process_again; -case 'p' : - ls =1 ; -/* fall through */ -case 'd' : -case 'u' : -case 'x' : -case 'i' : -/* the pointers are always 4 bytes aligned */ - bptr = (void *)(((unsigned long )bptr +3 ) & - ~3 ); -switch (ls) { -case 0 : -case 1 : - ls = long_size; -break ; -case 2 : - ls =8 ; -default : -break ; - } - val =read_size (bptr, ls); - bptr += ls; - arg =malloc_or_die (sizeof (*arg)); - arg->next =NULL ; - arg->type =PRINT_ATOM ; - arg->atom.atom =malloc_or_die (32 ); -sprintf (arg->atom.atom,"%lld" , val); - *next = arg; - next = &arg->next; -break ; -case 's' : - arg =malloc_or_die (sizeof (*arg)); - arg->next =NULL ; - arg->type =PRINT_STRING ; - arg->string.string =strdup (bptr); - bptr +=strlen (bptr) +1 ; - *next = arg; - next = &arg->next; -default : -break ; - } - } - } - -return args; -} - -static void free_args (struct print_arg *args) -{ -struct print_arg *next; - -while (args) { - next = args->next; - -if (args->type ==PRINT_ATOM ) -free (args->atom.atom); -else -free (args->string.string); -free (args); - args = next; - } -} - -static char *get_bprint_format(void *data, int size __unused, struct event *event) -{ -unsigned long long addr; -static struct format_field *field; -struct printk_map *printk; -char *format; -char *p; - -if (!field) { - field =find_field (event,"fmt" ); -if (!field) -die ("can't find format field for binary printk" ); -printf ("field->offset = %d size=%d\n" , field->offset, field->size); - } - - addr =read_size (data + field->offset, field->size); - - printk =find_printk (addr); -if (!printk) { - format =malloc_or_die (45 ); -sprintf (format,"%%pf : (NO FORMAT FOUND at %llx)\n" , - addr); -return format; - } - - p = printk->printk; -/* Remove any quotes. */ -if (*p =='"' ) - p++; - format =malloc_or_die (strlen (p) +10 ); -sprintf (format,"%s : %s" ,"%pf" , p); -/* remove ending quotes and new line since we will add one too */ - p = format +strlen (format) -1 ; -if (*p =='"' ) - *p =0 ; - - p -=2 ; -if (strcmp (p,"\\n" ) ==0 ) - *p =0 ; - -return format; -} - -static void pretty_print (void *data,int size,struct event *event) -{ -struct print_fmt *print_fmt = &event->print_fmt; -struct print_arg *arg = print_fmt->args; -struct print_arg *args =NULL ; -const char *ptr = print_fmt->format; -unsigned long long val; -struct func_map *func; -const char *saveptr; -char *bprint_fmt =NULL ; -char format[32 ]; -int show_func; -int len; -int ls; - -if (event->flags &EVENT_FL_ISFUNC ) - ptr =" %pF <-- %pF" ; - -if (event->flags &EVENT_FL_ISBPRINT ) { - bprint_fmt =get_bprint_format (data, size, event); - args =make_bprint_args (bprint_fmt, data, size, event); - arg = args; - ptr = bprint_fmt; - } - -for (; *ptr; ptr++) { - ls =0 ; -if (*ptr =='\\' ) { - ptr++; -switch (*ptr) { -case 'n' : -printf ("\n" ); -break ; -case 't' : -printf ("\t" ); -break ; -case 'r' : -printf ("\r" ); -break ; -case '\\' : -printf ("\\" ); -break ; -default : -printf ("%c" , *ptr); -break ; - } - - }else if (*ptr =='%' ) { - saveptr = ptr; - show_func =0 ; - cont_process: - ptr++; -switch (*ptr) { -case '%' : -printf ("%%" ); -break ; -case 'l' : - ls++; - goto cont_process; -case 'L' : - ls =2 ; - goto cont_process; -case 'z' : -case 'Z' : - case '0' ... '9': - goto cont_process; -case 'p' : -if (long_size ==4 ) - ls =1 ; -else - ls =2 ; - -if (*(ptr+1 ) =='F' || - *(ptr+1 ) =='f' ) { - ptr++; - show_func = *ptr; - } - -/* fall through */ -case 'd' : -case 'i' : -case 'x' : -case 'X' : -case 'u' : -if (!arg) -die ("no argument match" ); - - len = ((unsigned long )ptr +1 ) - - (unsigned long )saveptr; - -/* should never happen */ -if (len >32 ) -die ("bad format!" ); - -memcpy (format, saveptr, len); - format[len] =0 ; - - val =eval_num_arg (data, size, event, arg); - arg = arg->next; - -if (show_func) { - func =find_func (val); -if (func) { -printf ("%s" , func->func); -if (show_func =='F' ) -printf ("+0x%llx" , - val - func->addr); -break ; - } - } -switch (ls) { -case 0 : -printf (format, (int )val); -break ; -case 1 : -printf (format, (long )val); -break ; -case 2 : -printf (format, (long long )val); -break ; -default : -die ("bad count (%d)" , ls); - } -break ; -case 's' : -if (!arg) -die ("no matching argument" ); - -print_str_arg (data, size, event, arg); - arg = arg->next; -break ; -default : -printf (">%c<" , *ptr); - - } - }else -printf ("%c" , *ptr); - } - -if (args) { -free_args (args); -free (bprint_fmt); - } -} - -static inline int log10_cpu (int nb) -{ -if (nb /100 ) -return 3 ; -if (nb /10 ) -return 2 ; -return 1 ; -} - -static void print_lat_fmt(void *data, int size __unused) -{ -unsigned int lat_flags; -unsigned int pc; -int lock_depth; -int hardirq; -int softirq; - - lat_flags =parse_common_flags (data); - pc =parse_common_pc (data); - lock_depth =parse_common_lock_depth (data); - - hardirq = lat_flags &TRACE_FLAG_HARDIRQ ; - softirq = lat_flags &TRACE_FLAG_SOFTIRQ ; - -printf ("%c%c%c" , - (lat_flags &TRACE_FLAG_IRQS_OFF ) ?'d' : - (lat_flags &TRACE_FLAG_IRQS_NOSUPPORT ) ? -'X' :'.' , - (lat_flags &TRACE_FLAG_NEED_RESCHED ) ? -'N' :'.' , - (hardirq && softirq) ?'H' : - hardirq ?'h' : softirq ?'s' :'.' ); - -if (pc) -printf ("%x" , pc); -else -printf ("." ); - -if (lock_depth <0 ) -printf (". " ); -else -printf ("%d " , lock_depth); -} - -#define TRACE_GRAPH_INDENT 2 - -static struct record * -get_return_for_leaf (int cpu,int cur_pid,unsigned long long cur_func, -struct record *next) -{ -struct format_field *field; -struct event *event; -unsigned long val; -int type; -int pid; - - type =trace_parse_common_type (next->data); - event =trace_find_event (type); -if (!event) -return NULL ; - -if (!(event->flags &EVENT_FL_ISFUNCRET )) -return NULL ; - - pid =trace_parse_common_pid (next->data); - field =find_field (event,"func" ); -if (!field) -die ("function return does not have field func" ); - - val =read_size (next->data + field->offset, field->size); - -if (cur_pid != pid || cur_func != val) -return NULL ; - -/* this is a leaf, now advance the iterator */ -return trace_read_data (cpu); -} - -/* Signal a overhead of time execution to the output */ -static void print_graph_overhead (unsigned long long duration) -{ -/* Non nested entry or return */ -if (duration == ~0ULL ) -return (void )printf (" " ); - -/* Duration exceeded 100 msecs */ -if (duration >100000ULL ) -return (void )printf ("! " ); - -/* Duration exceeded 10 msecs */ -if (duration >10000ULL ) -return (void )printf ("+ " ); - -printf (" " ); -} - -static void print_graph_duration (unsigned long long duration) -{ -unsigned long usecs = duration /1000 ; -unsigned long nsecs_rem = duration %1000 ; -/* log10(ULONG_MAX) + '\0' */ -char msecs_str[21 ]; -char nsecs_str[5 ]; -int len; -int i; - -sprintf (msecs_str,"%lu" , usecs); - -/* Print msecs */ - len =printf ("%lu" , usecs); - -/* Print nsecs (we don't want to exceed 7 numbers) */ -if (len <7 ) { -snprintf (nsecs_str,8 - len,"%03lu" , nsecs_rem); - len +=printf (".%s" , nsecs_str); - } - -printf (" us " ); - -/* Print remaining spaces to fit the row's width */ -for (i = len; i <7 ; i++) -printf (" " ); - -printf ("| " ); -} - -static void -print_graph_entry_leaf (struct event *event,void *data,struct record *ret_rec) -{ -unsigned long long rettime, calltime; -unsigned long long duration, depth; -unsigned long long val; -struct format_field *field; -struct func_map *func; -struct event *ret_event; -int type; -int i; - - type =trace_parse_common_type (ret_rec->data); - ret_event =trace_find_event (type); - - field =find_field (ret_event,"rettime" ); -if (!field) -die ("can't find rettime in return graph" ); - rettime =read_size (ret_rec->data + field->offset, field->size); - - field =find_field (ret_event,"calltime" ); -if (!field) -die ("can't find rettime in return graph" ); - calltime =read_size (ret_rec->data + field->offset, field->size); - - duration = rettime - calltime; - -/* Overhead */ -print_graph_overhead (duration); - -/* Duration */ -print_graph_duration (duration); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - - field =find_field (event,"func" ); -if (!field) -die ("can't find func in entry graph" ); - val =read_size (data + field->offset, field->size); - func =find_func (val); - -if (func) -printf ("%s();" , func->func); -else -printf ("%llx();" , val); -} - -static void print_graph_nested (struct event *event,void *data) -{ -struct format_field *field; -unsigned long long depth; -unsigned long long val; -struct func_map *func; -int i; - -/* No overhead */ -print_graph_overhead (-1 ); - -/* No time */ -printf (" | " ); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - - field =find_field (event,"func" ); -if (!field) -die ("can't find func in entry graph" ); - val =read_size (data + field->offset, field->size); - func =find_func (val); - -if (func) -printf ("%s() {" , func->func); -else -printf ("%llx() {" , val); -} - -static void -pretty_print_func_ent (void *data,int size,struct event *event, -int cpu,int pid) -{ -struct format_field *field; -struct record *rec; -void *copy_data; -unsigned long val; - -if (latency_format) { -print_lat_fmt (data, size); -printf (" | " ); - } - - field =find_field (event,"func" ); -if (!field) -die ("function entry does not have func field" ); - - val =read_size (data + field->offset, field->size); - -/* -* peek_data may unmap the data pointer. Copy it first. -*/ - copy_data =malloc_or_die (size); -memcpy (copy_data, data, size); - data = copy_data; - - rec =trace_peek_data (cpu); -if (rec) { - rec =get_return_for_leaf (cpu, pid, val, rec); -if (rec) { -print_graph_entry_leaf (event, data, rec); - goto out_free; - } - } -print_graph_nested (event, data); -out_free: -free (data); -} - -static void -pretty_print_func_ret(void *data, int size __unused, struct event *event) -{ -unsigned long long rettime, calltime; -unsigned long long duration, depth; -struct format_field *field; -int i; - -if (latency_format) { -print_lat_fmt (data, size); -printf (" | " ); - } - - field =find_field (event,"rettime" ); -if (!field) -die ("can't find rettime in return graph" ); - rettime =read_size (data + field->offset, field->size); - - field =find_field (event,"calltime" ); -if (!field) -die ("can't find calltime in return graph" ); - calltime =read_size (data + field->offset, field->size); - - duration = rettime - calltime; - -/* Overhead */ -print_graph_overhead (duration); - -/* Duration */ -print_graph_duration (duration); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - -printf ("}" ); -} - -static void -pretty_print_func_graph (void *data,int size,struct event *event, -int cpu,int pid) -{ -if (event->flags &EVENT_FL_ISFUNCENT ) -pretty_print_func_ent (data, size, event, cpu, pid); -else if (event->flags &EVENT_FL_ISFUNCRET ) -pretty_print_func_ret (data, size, event); -printf ("\n" ); -} - -void print_trace_event (int cpu,void *data,int size) -{ -struct event *event; -int type; -int pid; - - type =trace_parse_common_type (data); - - event =trace_find_event (type); -if (!event) { -warning ("ug! no event found for type %d" , type); -return ; - } - - pid =trace_parse_common_pid (data); - -if (event->flags & (EVENT_FL_ISFUNCENT |EVENT_FL_ISFUNCRET )) -return pretty_print_func_graph (data, size, event, cpu, pid); - -if (latency_format) -print_lat_fmt (data, size); - -if (event->flags &EVENT_FL_FAILED ) { -printf ("EVENT '%s' FAILED TO PARSE\n" , - event->name); -return ; - } - -pretty_print (data, size, event); -} - -static void print_fields (struct print_flag_sym *field) -{ -printf ("{ %s, %s }" , field->value, field->str); -if (field->next) { -printf (", " ); -print_fields (field->next); - } -} - -static void print_args (struct print_arg *args) -{ -int print_paren =1 ; - -switch (args->type) { -case PRINT_NULL : -printf ("null" ); -break ; -case PRINT_ATOM : -printf ("%s" , args->atom.atom); -break ; -case PRINT_FIELD : -printf ("REC->%s" , args->field.name); -break ; -case PRINT_FLAGS : -printf ("__print_flags(" ); -print_args (args->flags.field); -printf (", %s, " , args->flags.delim); -print_fields (args->flags.flags); -printf (")" ); -break ; -case PRINT_SYMBOL : -printf ("__print_symbolic(" ); -print_args (args->symbol.field); -printf (", " ); -print_fields (args->symbol.symbols); -printf (")" ); -break ; -case PRINT_STRING : -printf ("__get_str(%s)" , args->string.string); -break ;Lines of this file are not shown. View the raw message.
tools/perf/util/trace-parse-events.c new file +3128
-0Lines of this file are not shown. View the raw message.
tools/perf/util/trace-parse-events.h new file +273
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Quoted 10 lines · David Ahern
Hi Steve:
Quoted 7 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Move the
trace-event-parse.ccode that originally came from trace-cmd into their own files. The new file will be calledtrace-parse-events.c, as the name of trace-cmd's file wasparse-events.ctoo, but it conflicted with theparse-events.cfile in perf that parses the command line.
Quoted 7 lines
Quoted 5 lines
This tries to update the code with mimimal changes.
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in
trace-parse-events.candtrace-parse-events.h.What branch should these apply cleanly to?
They are based off of v3.0. You can get these patches from my repo as described in the 0/8 announce email.
-- Steve
Quoted 6,876 lines
Quoted 6,876 lines
Signed-off-by Steven Rostedt <[email protected]>--- tools/perf/Makefile | 2 + tools/perf/util/trace-event-parse.c | 3125 --------------------------------- tools/perf/util/trace-event.h | 274 +--- tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++ tools/perf/util/trace-parse-events.h | 273 +++ 5 files changed, 3407 insertions(+), 3395 deletions(-) create mode 100644 tools/perf/util/trace-parse-events.c create mode 100644 tools/perf/util/trace-parse-events.htools/perf/Makefile +2
-0@@ -278,6 +278,7 @@ LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h +LIB_H += util/trace-parse-events.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h LIB_H += util/pstack.h@@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o +LIB_OBJS += $(OUTPUT)util/trace-parse-events.o LIB_OBJS += $(OUTPUT)util/svghelper.o LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/hist.otools/perf/util/trace-event-parse.c +0
-3125@@ -1,3132 +1,7 @@ -/* -* Copyright (C) 2009, Steven Rostedt <[email protected]> -* -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* 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 -* -* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* -* The parts for function graph printing was taken and modified from the -* Linux Kernel that were written by Frederic Weisbecker. -*/ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#undef _GNU_SOURCE#include "../perf.h" #include "util.h" #include "trace-event.h" -int header_page_ts_offset; -int header_page_ts_size; -int header_page_size_offset; -int header_page_size_size; -int header_page_overwrite_offset; -int header_page_overwrite_size; -int header_page_data_offset; -int header_page_data_size; - -bool latency_format; - -static char *input_buf; -static unsigned long long input_buf_ptr; -static unsigned long long input_buf_siz; - -static int cpus; -static int long_size; -static int is_flag_field; -static int is_symbolic_field; - -static struct format_field * -find_any_field (struct event *event,const char *name); - -static void init_input_buf (char *buf,unsigned long long size) -{ - input_buf = buf; - input_buf_siz = size; - input_buf_ptr =0 ; -} - -struct cmdline { -char *comm; -int pid; -}; - -static struct cmdline *cmdlines; -static int cmdline_count; - -static int cmdline_cmp (const void *a,const void *b) -{ -const struct cmdline *ca = a; -const struct cmdline *cb = b; - -if (ca->pid < cb->pid) -return -1 ; -if (ca->pid > cb->pid) -return 1 ; - -return 0 ; -} - -void parse_cmdlines(char *file, int size __unused) -{ -struct cmdline_list { -struct cmdline_list *next; -char *comm; -int pid; - } *list =NULL , *item; -char *line; -char *next =NULL ; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - item =malloc_or_die (sizeof (*item)); -sscanf (line,"%d %as" , &item->pid, - (float *)(void *)&item->comm);/* workaround gcc warning */ - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - cmdline_count++; - } - - cmdlines =malloc_or_die (sizeof (*cmdlines) * cmdline_count); - - i =0 ; -while (list) { - cmdlines[i].pid = list->pid; - cmdlines[i].comm = list->comm; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (cmdlines, cmdline_count,sizeof (*cmdlines), cmdline_cmp); -} - -static struct func_map { -unsigned long long addr; -char *func; -char *mod; -} *func_list; -static unsigned int func_count; - -static int func_cmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if (fa->addr < fb->addr) -return -1 ; -if (fa->addr > fb->addr) -return 1 ; - -return 0 ; -} - -void parse_proc_kallsyms(char *file, unsigned int size __unused) -{ -struct func_list { -struct func_list *next; -unsigned long long addr; -char *func; -char *mod; - } *list =NULL , *item; -char *line; -char *next =NULL ; -char *addr_str; -char ch; -int ret__used ; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - item =malloc_or_die (sizeof (*item)); - item->mod =NULL ; - ret =sscanf (line,"%as %c %as\t[%as" , - (float *)(void *)&addr_str,/* workaround gcc warning */ - &ch, - (float *)(void *)&item->func, - (float *)(void *)&item->mod); - item->addr =strtoull (addr_str,NULL ,16 ); -free (addr_str); - -/* truncate the extra ']' */ -if (item->mod) - item->mod[strlen (item->mod) -1 ] =0 ; - - - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - func_count++; - } - - func_list =malloc_or_die (sizeof (*func_list) * (func_count +1 )); - - i =0 ; -while (list) { - func_list[i].func = list->func; - func_list[i].addr = list->addr; - func_list[i].mod = list->mod; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (func_list, func_count,sizeof (*func_list), func_cmp); - -/* -* Add a special record at the end. -*/ - func_list[func_count].func =NULL ; - func_list[func_count].addr =0 ; - func_list[func_count].mod =NULL ; -} - -/* -* We are searching for a record in between, not an exact -* match. -*/ -static int func_bcmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if ((fa->addr == fb->addr) || - - (fa->addr > fb->addr && - fa->addr < (fb+1 )->addr)) -return 0 ; - -if (fa->addr < fb->addr) -return -1 ; - -return 1 ; -} - -static struct func_map *find_func (unsigned long long addr) -{ -struct func_map *func; -struct func_map key; - - key.addr = addr; - - func =bsearch (&key, func_list, func_count,sizeof (*func_list), - func_bcmp); - -return func; -} - -void print_funcs (void ) -{ -int i; - -for (i =0 ; i < (int )func_count; i++) { -printf ("%016llx %s" , - func_list[i].addr, - func_list[i].func); -if (func_list[i].mod) -printf (" [%s]\n" , func_list[i].mod); -else -printf ("\n" ); - } -} - -static struct printk_map { -unsigned long long addr; -char *printk; -} *printk_list; -static unsigned int printk_count; - -static int printk_cmp (const void *a,const void *b) -{ -const struct func_map *fa = a; -const struct func_map *fb = b; - -if (fa->addr < fb->addr) -return -1 ; -if (fa->addr > fb->addr) -return 1 ; - -return 0 ; -} - -static struct printk_map *find_printk (unsigned long long addr) -{ -struct printk_map *printk; -struct printk_map key; - - key.addr = addr; - - printk =bsearch (&key, printk_list, printk_count,sizeof (*printk_list), - printk_cmp); - -return printk; -} - -void parse_ftrace_printk(char *file, unsigned int size __unused) -{ -struct printk_list { -struct printk_list *next; -unsigned long long addr; -char *printk; - } *list =NULL , *item; -char *line; -char *next =NULL ; -char *addr_str; -int i; - - line =strtok_r (file,"\n" , &next); -while (line) { - addr_str =strsep (&line,":" ); -if (!line) { -warning ("error parsing print strings" ); -break ; - } - item =malloc_or_die (sizeof (*item)); - item->addr =strtoull (addr_str,NULL ,16 ); -/* fmt still has a space, skip it */ - item->printk =strdup (line+1 ); - item->next = list; - list = item; - line =strtok_r (NULL ,"\n" , &next); - printk_count++; - } - - printk_list =malloc_or_die (sizeof (*printk_list) * printk_count +1 ); - - i =0 ; -while (list) { - printk_list[i].printk = list->printk; - printk_list[i].addr = list->addr; - i++; - item = list; - list = list->next; -free (item); - } - -qsort (printk_list, printk_count,sizeof (*printk_list), printk_cmp); -} - -void print_printk (void ) -{ -int i; - -for (i =0 ; i < (int )printk_count; i++) { -printf ("%016llx %s\n" , - printk_list[i].addr, - printk_list[i].printk); - } -} - -static struct event *alloc_event (void ) -{ -struct event *event; - - event =malloc_or_die (sizeof (*event)); -memset (event,0 ,sizeof (*event)); - -return event; -} - -enum event_type { -EVENT_ERROR , -EVENT_NONE , -EVENT_SPACE , -EVENT_NEWLINE , -EVENT_OP , -EVENT_DELIM , -EVENT_ITEM , -EVENT_DQUOTE , -EVENT_SQUOTE , -}; - -static struct event *event_list; - -static void add_event (struct event *event) -{ - event->next = event_list; - event_list = event; -} - -static int event_item_type (enum event_type type) -{ -switch (type) { - case EVENT_ITEM ... EVENT_SQUOTE: -return 1 ; - case EVENT_ERROR ... EVENT_DELIM: -default : -return 0 ; - } -} - -static void free_arg (struct print_arg *arg) -{ -if (!arg) -return ; - -switch (arg->type) { -case PRINT_ATOM : -if (arg->atom.atom) -free (arg->atom.atom); -break ; -case PRINT_NULL : - case PRINT_FIELD ... PRINT_OP: -default : -/* todo */ -break ; - } - -free (arg); -} - -static enum event_type get_type (int ch) -{ -if (ch =='\n' ) -return EVENT_NEWLINE ; -if (isspace (ch)) -return EVENT_SPACE ; -if (isalnum (ch) || ch =='_' ) -return EVENT_ITEM ; -if (ch =='\'' ) -return EVENT_SQUOTE ; -if (ch =='"' ) -return EVENT_DQUOTE ; -if (!isprint (ch)) -return EVENT_NONE ; -if (ch =='(' || ch ==')' || ch ==',' ) -return EVENT_DELIM ; - -return EVENT_OP ; -} - -static int __read_char (void ) -{ -if (input_buf_ptr >= input_buf_siz) -return -1 ; - -return input_buf[input_buf_ptr++]; -} - -static int __peek_char (void ) -{ -if (input_buf_ptr >= input_buf_siz) -return -1 ; - -return input_buf[input_buf_ptr]; -} - -static enum event_type __read_token (char **tok) -{ -char buf[BUFSIZ ]; -int ch, last_ch, quote_ch, next_ch; -int i =0 ; -int tok_size =0 ; -enum event_type type; - - *tok =NULL ; - - - ch =__read_char (); -if (ch <0 ) -return EVENT_NONE ; - - type =get_type (ch); -if (type ==EVENT_NONE ) -return type; - - buf[i++] = ch; - -switch (type) { -case EVENT_NEWLINE : -case EVENT_DELIM : - *tok =malloc_or_die (2 ); - (*tok)[0 ] = ch; - (*tok)[1 ] =0 ; -return type; - -case EVENT_OP : -switch (ch) { -case '-' : - next_ch =__peek_char (); -if (next_ch =='>' ) { - buf[i++] =__read_char (); -break ; - } -/* fall through */ -case '+' : -case '|' : -case '&' : -case '>' : -case '<' : - last_ch = ch; - ch =__peek_char (); -if (ch != last_ch) - goto test_equal; - buf[i++] =__read_char (); -switch (last_ch) { -case '>' : -case '<' : - goto test_equal; -default : -break ; - } -break ; -case '!' : -case '=' : - goto test_equal; -default :/* what should we do instead? */ -break ; - } - buf[i] =0 ; - *tok =strdup (buf); -return type; - - test_equal: - ch =__peek_char (); -if (ch =='=' ) - buf[i++] =__read_char (); -break ; - -case EVENT_DQUOTE : -case EVENT_SQUOTE : -/* don't keep quotes */ - i--; - quote_ch = ch; - last_ch =0 ; -do { -if (i == (BUFSIZ -1 )) { - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size +BUFSIZ ); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); - -if (!*tok) -return EVENT_NONE ; - tok_size +=BUFSIZ ; - i =0 ; - } - last_ch = ch; - ch =__read_char (); - buf[i++] = ch; -/* the '\' '\' will cancel itself */ -if (ch =='\\' && last_ch =='\\' ) - last_ch =0 ; - }while (ch != quote_ch || last_ch =='\\' ); -/* remove the last quote */ - i--; - goto out; - - case EVENT_ERROR ... EVENT_SPACE: -case EVENT_ITEM : -default : -break ; - } - -while (get_type (__peek_char ()) == type) { -if (i == (BUFSIZ -1 )) { - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size +BUFSIZ ); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); - -if (!*tok) -return EVENT_NONE ; - tok_size +=BUFSIZ ; - i =0 ; - } - ch =__read_char (); - buf[i++] = ch; - } - - out: - buf[i] =0 ; -if (*tok) { - *tok =realloc (*tok, tok_size + i); -if (!*tok) -return EVENT_NONE ; -strcat (*tok, buf); - }else - *tok =strdup (buf); -if (!*tok) -return EVENT_NONE ; - -return type; -} - -static void free_token (char *tok) -{ -if (tok) -free (tok); -} - -static enum event_type read_token (char **tok) -{ -enum event_type type; - -for (;;) { - type =__read_token (tok); -if (type !=EVENT_SPACE ) -return type; - -free_token (*tok); - } - -/* not reached */ -return EVENT_NONE ; -} - -/* no newline */ -static enum event_type read_token_item (char **tok) -{ -enum event_type type; - -for (;;) { - type =__read_token (tok); -if (type !=EVENT_SPACE && type !=EVENT_NEWLINE ) -return type; - -free_token (*tok); - } - -/* not reached */ -return EVENT_NONE ; -} - -static int test_type (enum event_type type,enum event_type expect) -{ -if (type != expect) { -warning ("Error: expected type %d but read %d" , - expect, type); -return -1 ; - } -return 0 ; -} - -static int __test_type_token (enum event_type type,char *token, -enum event_type expect,const char *expect_tok, -bool warn) -{ -if (type != expect) { -if (warn) -warning ("Error: expected type %d but read %d" , - expect, type); -return -1 ; - } - -if (strcmp (token, expect_tok) !=0 ) { -if (warn) -warning ("Error: expected '%s' but read '%s'" , - expect_tok, token); -return -1 ; - } -return 0 ; -} - -static int test_type_token (enum event_type type,char *token, -enum event_type expect,const char *expect_tok) -{ -return __test_type_token (type, token, expect, expect_tok, true); -} - -static int __read_expect_type (enum event_type expect,char **tok,int newline_ok) -{ -enum event_type type; - -if (newline_ok) - type =read_token (tok); -else - type =read_token_item (tok); -return test_type (type, expect); -} - -static int read_expect_type (enum event_type expect,char **tok) -{ -return __read_expect_type (expect, tok,1 ); -} - -static int __read_expected (enum event_type expect,const char *str, -int newline_ok,bool warn) -{ -enum event_type type; -char *token; -int ret; - -if (newline_ok) - type =read_token (&token); -else - type =read_token_item (&token); - - ret =__test_type_token (type, token, expect, str, warn); - -free_token (token); - -return ret; -} - -static int read_expected (enum event_type expect,const char *str) -{ -return __read_expected (expect, str,1 , true); -} - -static int read_expected_item (enum event_type expect,const char *str) -{ -return __read_expected (expect, str,0 , true); -} - -static char *event_read_name (void ) -{ -char *token; - -if (read_expected (EVENT_ITEM ,"name" ) <0 ) -return NULL ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return NULL ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - -return token; - - fail: -free_token (token); -return NULL ; -} - -static int event_read_id (void ) -{ -char *token; -int id; - -if (read_expected_item (EVENT_ITEM ,"ID" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - id =strtoul (token,NULL ,0 ); -free_token (token); -return id; - - fail: -free_token (token); -return -1 ; -} - -static int field_is_string (struct format_field *field) -{ -if ((field->flags &FIELD_IS_ARRAY ) && - (!strstr (field->type,"char" ) || !strstr (field->type,"u8" ) || - !strstr (field->type,"s8" ))) -return 1 ; - -return 0 ; -} - -static int field_is_dynamic (struct format_field *field) -{ -if (!strncmp (field->type,"__data_loc" ,10 )) -return 1 ; - -return 0 ; -} - -static int event_read_fields (struct event *event,struct format_field **fields) -{ -struct format_field *field =NULL ; -enum event_type type; -char *token; -char *last_token; -int count =0 ; - -do { - type =read_token (&token); -if (type ==EVENT_NEWLINE ) { -free_token (token); -return count; - } - - count++; - -if (test_type_token (type, token,EVENT_ITEM ,"field" )) - goto fail; -free_token (token); - - type =read_token (&token); -/* -* The ftrace fields may still use the "special" name. -* Just ignore it. -*/ -if (event->flags &EVENT_FL_ISFTRACE && - type ==EVENT_ITEM &&strcmp (token,"special" ) ==0 ) { -free_token (token); - type =read_token (&token); - } - -if (test_type_token (type, token,EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - last_token = token; - - field =malloc_or_die (sizeof (*field)); -memset (field,0 ,sizeof (*field)); - -/* read the rest of the type */ -for (;;) { - type =read_token (&token); -if (type ==EVENT_ITEM || - (type ==EVENT_OP &&strcmp (token,"*" ) ==0 ) || -/* -* Some of the ftrace fields are broken and have -* an illegal "." in them. -*/ - (event->flags &EVENT_FL_ISFTRACE && - type ==EVENT_OP &&strcmp (token,"." ) ==0 )) { - -if (strcmp (token,"*" ) ==0 ) - field->flags |=FIELD_IS_POINTER ; - -if (field->type) { - field->type =realloc (field->type, -strlen (field->type) + -strlen (last_token) +2 ); -strcat (field->type," " ); -strcat (field->type, last_token); - }else - field->type = last_token; - last_token = token; -continue ; - } - -break ; - } - -if (!field->type) { -die ("no type found" ); - goto fail; - } - field->name = last_token; - -if (test_type (type,EVENT_OP )) - goto fail; - -if (strcmp (token,"[" ) ==0 ) { -enum event_type last_type = type; -char *brackets = token; -int len; - - field->flags |=FIELD_IS_ARRAY ; - - type =read_token (&token); -while (strcmp (token,"]" ) !=0 ) { -if (last_type ==EVENT_ITEM && - type ==EVENT_ITEM ) - len =2 ; -else - len =1 ; - last_type = type; - - brackets =realloc (brackets, -strlen (brackets) + -strlen (token) + len); -if (len ==2 ) -strcat (brackets," " ); -strcat (brackets, token); -free_token (token); - type =read_token (&token); -if (type ==EVENT_NONE ) { -die ("failed to find token" ); - goto fail; - } - } - -free_token (token); - - brackets =realloc (brackets,strlen (brackets) +2 ); -strcat (brackets,"]" ); - -/* add brackets to type */ - - type =read_token (&token); -/* -* If the next token is not an OP, then it is of -* the format: type [] item; -*/ -if (type ==EVENT_ITEM ) { - field->type =realloc (field->type, -strlen (field->type) + -strlen (field->name) + -strlen (brackets) +2 ); -strcat (field->type," " ); -strcat (field->type, field->name); -free_token (field->name); -strcat (field->type, brackets); - field->name = token; - type =read_token (&token); - }else { - field->type =realloc (field->type, -strlen (field->type) + -strlen (brackets) +1 ); -strcat (field->type, brackets); - } -free (brackets); - } - -if (field_is_string (field)) { - field->flags |=FIELD_IS_STRING ; -if (field_is_dynamic (field)) - field->flags |=FIELD_IS_DYNAMIC ; - } - -if (test_type_token (type, token,EVENT_OP ,";" )) - goto fail; -free_token (token); - -if (read_expected (EVENT_ITEM ,"offset" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - field->offset =strtoul (token,NULL ,0 ); -free_token (token); - -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_ITEM ,"size" ) <0 ) - goto fail_expect; - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - field->size =strtoul (token,NULL ,0 ); -free_token (token); - -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - - type =read_token (&token); -if (type !=EVENT_NEWLINE ) { -/* newer versions of the kernel have a "signed" type */ -if (test_type_token (type, token,EVENT_ITEM ,"signed" )) - goto fail; - -free_token (token); - -if (read_expected (EVENT_OP ,":" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_ITEM , &token)) - goto fail; - -if (strtoul (token,NULL ,0 )) - field->flags |=FIELD_IS_SIGNED ; - -free_token (token); -if (read_expected (EVENT_OP ,";" ) <0 ) - goto fail_expect; - -if (read_expect_type (EVENT_NEWLINE , &token)) - goto fail; - } - -free_token (token); - - *fields = field; - fields = &field->next; - - }while (1 ); - -return 0 ; - -fail: -free_token (token); -fail_expect: -if (field) -free (field); -return -1 ; -} - -static int event_read_format (struct event *event) -{ -char *token; -int ret; - -if (read_expected_item (EVENT_ITEM ,"format" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_NEWLINE , &token)) - goto fail; -free_token (token); - - ret =event_read_fields (event, &event->format.common_fields); -if (ret <0 ) -return ret; - event->format.nr_common = ret; - - ret =event_read_fields (event, &event->format.fields); -if (ret <0 ) -return ret; - event->format.nr_fields = ret; - -return 0 ; - - fail: -free_token (token); -return -1 ; -} - -enum event_type -process_arg_token (struct event *event,struct print_arg *arg, -char **tok,enum event_type type); - -static enum event_type -process_arg (struct event *event,struct print_arg *arg,char **tok) -{ -enum event_type type; -char *token; - - type =read_token (&token); - *tok = token; - -return process_arg_token (event, arg, tok, type); -} - -static enum event_type -process_cond (struct event *event,struct print_arg *top,char **tok) -{ -struct print_arg *arg, *left, *right; -enum event_type type; -char *token =NULL ; - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - left =malloc_or_die (sizeof (*left)); - - right =malloc_or_die (sizeof (*right)); - - arg->type =PRINT_OP ; - arg->op.left = left; - arg->op.right = right; - - *tok =NULL ; - type =process_arg (event, left, &token); -if (test_type_token (type, token,EVENT_OP ,":" )) - goto out_free; - - arg->op.op = token; - - type =process_arg (event, right, &token); - - top->op.right = arg; - - *tok = token; -return type; - -out_free: -free_token (*tok); -free (right); -free (left); -free_arg (arg); -return EVENT_ERROR ; -} - -static enum event_type -process_array (struct event *event,struct print_arg *top,char **tok) -{ -struct print_arg *arg; -enum event_type type; -char *token =NULL ; - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - *tok =NULL ; - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_OP ,"]" )) - goto out_free; - - top->op.right = arg; - -free_token (token); - type =read_token_item (&token); - *tok = token; - -return type; - -out_free: -free_token (*tok); -free_arg (arg); -return EVENT_ERROR ; -} - -static int get_op_prio (char *op) -{ -if (!op[1 ]) { -switch (op[0 ]) { -case '*' : -case '/' : -case '%' : -return 6 ; -case '+' : -case '-' : -return 7 ; -/* '>>' and '<<' are 8 */ -case '<' : -case '>' : -return 9 ; -/* '==' and '!=' are 10 */ -case '&' : -return 11 ; -case '^' : -return 12 ; -case '|' : -return 13 ; -case '?' : -return 16 ; -default : -die ("unknown op '%c'" , op[0 ]); -return -1 ; - } - }else { -if (strcmp (op,"++" ) ==0 || -strcmp (op,"--" ) ==0 ) { -return 3 ; - }else if (strcmp (op,">>" ) ==0 || -strcmp (op,"<<" ) ==0 ) { -return 8 ; - }else if (strcmp (op,">=" ) ==0 || -strcmp (op,"<=" ) ==0 ) { -return 9 ; - }else if (strcmp (op,"==" ) ==0 || -strcmp (op,"!=" ) ==0 ) { -return 10 ; - }else if (strcmp (op,"&&" ) ==0 ) { -return 14 ; - }else if (strcmp (op,"||" ) ==0 ) { -return 15 ; - }else { -die ("unknown op '%s'" , op); -return -1 ; - } - } -} - -static void set_op_prio (struct print_arg *arg) -{ - -/* single ops are the greatest */ -if (!arg->op.left || arg->op.left->type ==PRINT_NULL ) { - arg->op.prio =0 ; -return ; - } - - arg->op.prio =get_op_prio (arg->op.op); -} - -static enum event_type -process_op (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *left, *right =NULL ; -enum event_type type; -char *token; - -/* the op is passed in via tok */ - token = *tok; - -if (arg->type ==PRINT_OP && !arg->op.left) { -/* handle single op */ -if (token[1 ]) { -die ("bad op token %s" , token); -return EVENT_ERROR ; - } -switch (token[0 ]) { -case '!' : -case '+' : -case '-' : -break ; -default : -die ("bad op token %s" , token); -return EVENT_ERROR ; - } - -/* make an empty left */ - left =malloc_or_die (sizeof (*left)); - left->type =PRINT_NULL ; - arg->op.left = left; - - right =malloc_or_die (sizeof (*right)); - arg->op.right = right; - - type =process_arg (event, right, tok); - - }else if (strcmp (token,"?" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); -/* copy the top arg to the left */ - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - arg->op.prio =0 ; - - type =process_cond (event, arg, tok); - - }else if (strcmp (token,">>" ) ==0 || -strcmp (token,"<<" ) ==0 || -strcmp (token,"&" ) ==0 || -strcmp (token,"|" ) ==0 || -strcmp (token,"&&" ) ==0 || -strcmp (token,"||" ) ==0 || -strcmp (token,"-" ) ==0 || -strcmp (token,"+" ) ==0 || -strcmp (token,"*" ) ==0 || -strcmp (token,"^" ) ==0 || -strcmp (token,"/" ) ==0 || -strcmp (token,"<" ) ==0 || -strcmp (token,">" ) ==0 || -strcmp (token,"==" ) ==0 || -strcmp (token,"!=" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); - -/* copy the top arg to the left */ - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - -set_op_prio (arg); - - right =malloc_or_die (sizeof (*right)); - - type =read_token_item (&token); - *tok = token; - -/* could just be a type pointer */ -if ((strcmp (arg->op.op,"*" ) ==0 ) && - type ==EVENT_DELIM && (strcmp (token,")" ) ==0 )) { -if (left->type !=PRINT_ATOM ) -die ("bad pointer type" ); - left->atom.atom =realloc (left->atom.atom, -sizeof (left->atom.atom) +3 ); -strcat (left->atom.atom," *" ); - *arg = *left; -free (arg); - -return type; - } - - type =process_arg_token (event, right, tok, type); - - arg->op.right = right; - - }else if (strcmp (token,"[" ) ==0 ) { - - left =malloc_or_die (sizeof (*left)); - *left = *arg; - - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left = left; - - arg->op.prio =0 ; - type =process_array (event, arg, tok); - - }else { -warning ("unknown op '%s'" , token); - event->flags |=EVENT_FL_FAILED ; -/* the arg is now the left side */ -return EVENT_NONE ; - } - -if (type ==EVENT_OP ) { -int prio; - -/* higher prios need to be closer to the root */ - prio =get_op_prio (*tok); - -if (prio > arg->op.prio) -return process_op (event, arg, tok); - -return process_op (event, right, tok); - } - -return type; -} - -static enum event_type -process_entry(struct event *event __unused, struct print_arg *arg, -char **tok) -{ -enum event_type type; -char *field; -char *token; - -if (read_expected (EVENT_OP ,"->" ) <0 ) -return EVENT_ERROR ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - field = token; - - arg->type =PRINT_FIELD ; - arg->field.name = field; - -if (is_flag_field) { - arg->field.field =find_any_field (event, arg->field.name); - arg->field.field->flags |=FIELD_IS_FLAG ; - is_flag_field =0 ; - }else if (is_symbolic_field) { - arg->field.field =find_any_field (event, arg->field.name); - arg->field.field->flags |=FIELD_IS_SYMBOLIC ; - is_symbolic_field =0 ; - } - - type =read_token (&token); - *tok = token; - -return type; - -fail: -free_token (token); -return EVENT_ERROR ; -} - -static char *arg_eval (struct print_arg *arg); - -static long long arg_num_eval (struct print_arg *arg) -{ -long long left, right; -long long val =0 ; - -switch (arg->type) { -case PRINT_ATOM : - val =strtoll (arg->atom.atom,NULL ,0 ); -break ; -case PRINT_TYPE : - val =arg_num_eval (arg->typecast.item); -break ; -case PRINT_OP : -switch (arg->op.op[0 ]) { -case '|' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -if (arg->op.op[1 ]) - val = left || right; -else - val = left | right; -break ; -case '&' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -if (arg->op.op[1 ]) - val = left && right; -else - val = left & right; -break ; -case '<' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -switch (arg->op.op[1 ]) { -case 0 : - val = left < right; -break ; -case '<' : - val = left << right; -break ; -case '=' : - val = left <= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '>' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); -switch (arg->op.op[1 ]) { -case 0 : - val = left > right; -break ; -case '>' : - val = left >> right; -break ; -case '=' : - val = left >= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '=' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); - -if (arg->op.op[1 ] !='=' ) -die ("unknown op '%s'" , arg->op.op); - - val = left == right; -break ; -case '!' : - left =arg_num_eval (arg->op.left); - right =arg_num_eval (arg->op.right); - -switch (arg->op.op[1 ]) { -case '=' : - val = left != right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; - -case PRINT_NULL : - case PRINT_FIELD ... PRINT_SYMBOL: -case PRINT_STRING : -default : -die ("invalid eval type %d" , arg->type); - - } -return val; -} - -static char *arg_eval (struct print_arg *arg) -{ -long long val; -static char buf[20 ]; - -switch (arg->type) { -case PRINT_ATOM : -return arg->atom.atom; -case PRINT_TYPE : -return arg_eval (arg->typecast.item); -case PRINT_OP : - val =arg_num_eval (arg); -sprintf (buf,"%lld" , val); -return buf; - -case PRINT_NULL : - case PRINT_FIELD ... PRINT_SYMBOL: -case PRINT_STRING : -default : -die ("invalid eval type %d" , arg->type); -break ; - } - -return NULL ; -} - -static enum event_type -process_fields (struct event *event,struct print_flag_sym **list,char **tok) -{ -enum event_type type; -struct print_arg *arg =NULL ; -struct print_flag_sym *field; -char *token =NULL ; -char *value; - -do { -free_token (token); - type =read_token_item (&token); -if (test_type_token (type, token,EVENT_OP ,"{" )) -break ; - - arg =malloc_or_die (sizeof (*arg)); - -free_token (token); - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - field =malloc_or_die (sizeof (*field)); -memset (field,0 ,sizeof (*field)); - - value =arg_eval (arg); - field->value =strdup (value); - -free_token (token); - type =process_arg (event, arg, &token); -if (test_type_token (type, token,EVENT_OP ,"}" )) - goto out_free; - - value =arg_eval (arg); - field->str =strdup (value); -free_arg (arg); - arg =NULL ; - - *list = field; - list = &field->next; - -free_token (token); - type =read_token_item (&token); - }while (type ==EVENT_DELIM &&strcmp (token,"," ) ==0 ); - - *tok = token; -return type; - -out_free: -free_arg (arg); -free_token (token); - -return EVENT_ERROR ; -} - -static enum event_type -process_flags (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *field; -enum event_type type; -char *token; - -memset (arg,0 ,sizeof (*arg)); - arg->type =PRINT_FLAGS ; - -if (read_expected_item (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - - field =malloc_or_die (sizeof (*field)); - - type =process_arg (event, field, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - arg->flags.field = field; - - type =read_token_item (&token); -if (event_item_type (type)) { - arg->flags.delim = token; - type =read_token_item (&token); - } - -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - type =process_fields (event, &arg->flags.flags, &token); -if (test_type_token (type, token,EVENT_DELIM ,")" )) - goto out_free; - -free_token (token); - type =read_token_item (tok); -return type; - -out_free: -free_token (token); -return EVENT_ERROR ; -} - -static enum event_type -process_symbols (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *field; -enum event_type type; -char *token; - -memset (arg,0 ,sizeof (*arg)); - arg->type =PRINT_SYMBOL ; - -if (read_expected_item (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - - field =malloc_or_die (sizeof (*field)); - - type =process_arg (event, field, &token); -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto out_free; - - arg->symbol.field = field; - - type =process_fields (event, &arg->symbol.symbols, &token); -if (test_type_token (type, token,EVENT_DELIM ,")" )) - goto out_free; - -free_token (token); - type =read_token_item (tok); -return type; - -out_free: -free_token (token); -return EVENT_ERROR ; -} - -static enum event_type -process_paren (struct event *event,struct print_arg *arg,char **tok) -{ -struct print_arg *item_arg; -enum event_type type; -char *token; - - type =process_arg (event, arg, &token); - -if (type ==EVENT_ERROR ) -return EVENT_ERROR ; - -if (type ==EVENT_OP ) - type =process_op (event, arg, &token); - -if (type ==EVENT_ERROR ) -return EVENT_ERROR ; - -if (test_type_token (type, token,EVENT_DELIM ,")" )) { -free_token (token); -return EVENT_ERROR ; - } - -free_token (token); - type =read_token_item (&token); - -/* -* If the next token is an item or another open paren, then -* this was a typecast. -*/ -if (event_item_type (type) || - (type ==EVENT_DELIM &&strcmp (token,"(" ) ==0 )) { - -/* make this a typecast and contine */ - -/* prevous must be an atom */ -if (arg->type !=PRINT_ATOM ) -die ("previous needed to be PRINT_ATOM" ); - - item_arg =malloc_or_die (sizeof (*item_arg)); - - arg->type =PRINT_TYPE ; - arg->typecast.type = arg->atom.atom; - arg->typecast.item = item_arg; - type =process_arg_token (event, item_arg, &token, type); - - } - - *tok = token; -return type; -} - - -static enum event_type -process_str(struct event *event __unused, struct print_arg *arg, char **tok) -{ -enum event_type type; -char *token; - -if (read_expected (EVENT_DELIM ,"(" ) <0 ) -return EVENT_ERROR ; - -if (read_expect_type (EVENT_ITEM , &token) <0 ) - goto fail; - - arg->type =PRINT_STRING ; - arg->string.string = token; - arg->string.offset =-1 ; - -if (read_expected (EVENT_DELIM ,")" ) <0 ) -return EVENT_ERROR ; - - type =read_token (&token); - *tok = token; - -return type; -fail: -free_token (token); -return EVENT_ERROR ; -} - -enum event_type -process_arg_token (struct event *event,struct print_arg *arg, -char **tok,enum event_type type) -{ -char *token; -char *atom; - - token = *tok; - -switch (type) { -case EVENT_ITEM : -if (strcmp (token,"REC" ) ==0 ) { -free_token (token); - type =process_entry (event, arg, &token); - }else if (strcmp (token,"__print_flags" ) ==0 ) { -free_token (token); - is_flag_field =1 ; - type =process_flags (event, arg, &token); - }else if (strcmp (token,"__print_symbolic" ) ==0 ) { -free_token (token); - is_symbolic_field =1 ; - type =process_symbols (event, arg, &token); - }else if (strcmp (token,"__get_str" ) ==0 ) { -free_token (token); - type =process_str (event, arg, &token); - }else { - atom = token; -/* test the next token */ - type =read_token_item (&token); - -/* atoms can be more than one token long */ -while (type ==EVENT_ITEM ) { - atom =realloc (atom,strlen (atom) +strlen (token) +2 ); -strcat (atom," " ); -strcat (atom, token); -free_token (token); - type =read_token_item (&token); - } - -/* todo, test for function */ - - arg->type =PRINT_ATOM ; - arg->atom.atom = atom; - } -break ; -case EVENT_DQUOTE : -case EVENT_SQUOTE : - arg->type =PRINT_ATOM ; - arg->atom.atom = token; - type =read_token_item (&token); -break ; -case EVENT_DELIM : -if (strcmp (token,"(" ) ==0 ) { -free_token (token); - type =process_paren (event, arg, &token); -break ; - } -case EVENT_OP : -/* handle single ops */ - arg->type =PRINT_OP ; - arg->op.op = token; - arg->op.left =NULL ; - type =process_op (event, arg, &token); - -break ; - - case EVENT_ERROR ... EVENT_NEWLINE: -default : -die ("unexpected type %d" , type); - } - *tok = token; - -return type; -} - -static int event_read_print_args (struct event *event,struct print_arg **list) -{ -enum event_type type =EVENT_ERROR ; -struct print_arg *arg; -char *token; -int args =0 ; - -do { -if (type ==EVENT_NEWLINE ) { -free_token (token); - type =read_token_item (&token); -continue ; - } - - arg =malloc_or_die (sizeof (*arg)); -memset (arg,0 ,sizeof (*arg)); - - type =process_arg (event, arg, &token); - -if (type ==EVENT_ERROR ) { -free_arg (arg); -return -1 ; - } - - *list = arg; - args++; - -if (type ==EVENT_OP ) { - type =process_op (event, arg, &token); - list = &arg->next; -continue ; - } - -if (type ==EVENT_DELIM &&strcmp (token,"," ) ==0 ) { -free_token (token); - *list = arg; - list = &arg->next; -continue ; - } -break ; - }while (type !=EVENT_NONE ); - -if (type !=EVENT_NONE ) -free_token (token); - -return args; -} - -static int event_read_print (struct event *event) -{ -enum event_type type; -char *token; -int ret; - -if (read_expected_item (EVENT_ITEM ,"print" ) <0 ) -return -1 ; - -if (read_expected (EVENT_ITEM ,"fmt" ) <0 ) -return -1 ; - -if (read_expected (EVENT_OP ,":" ) <0 ) -return -1 ; - -if (read_expect_type (EVENT_DQUOTE , &token) <0 ) - goto fail; - - concat: - event->print_fmt.format = token; - event->print_fmt.args =NULL ; - -/* ok to have no arg */ - type =read_token_item (&token); - -if (type ==EVENT_NONE ) -return 0 ; - -/* Handle concatination of print lines */ -if (type ==EVENT_DQUOTE ) { -char *cat; - - cat =malloc_or_die (strlen (event->print_fmt.format) + -strlen (token) +1 ); -strcpy (cat, event->print_fmt.format); -strcat (cat, token); -free_token (token); -free_token (event->print_fmt.format); - event->print_fmt.format =NULL ; - token = cat; - goto concat; - } - -if (test_type_token (type, token,EVENT_DELIM ,"," )) - goto fail; - -free_token (token); - - ret =event_read_print_args (event, &event->print_fmt.args); -if (ret <0 ) -return -1 ; - -return ret; - - fail: -free_token (token); -return -1 ; -} - -static struct format_field * -find_common_field (struct event *event,const char *name) -{ -struct format_field *format; - -for (format = event->format.common_fields; - format; format = format->next) { -if (strcmp (format->name, name) ==0 ) -break ; - } - -return format; -} - -static struct format_field * -find_field (struct event *event,const char *name) -{ -struct format_field *format; - -for (format = event->format.fields; - format; format = format->next) { -if (strcmp (format->name, name) ==0 ) -break ; - } - -return format; -} - -static struct format_field * -find_any_field (struct event *event,const char *name) -{ -struct format_field *format; - - format =find_common_field (event, name); -if (format) -return format; -return find_field (event, name); -} - -unsigned long long read_size (void *ptr,int size) -{ -switch (size) { -case 1 : -return *(unsigned char *)ptr; -case 2 : -return data2host2 (ptr); -case 4 : -return data2host4 (ptr); -case 8 : -return data2host8 (ptr); -default : -/* BUG! */ -return 0 ; - } -} - -unsigned long long -raw_field_value (struct event *event,const char *name,void *data) -{ -struct format_field *field; - - field =find_any_field (event, name); -if (!field) -return 0ULL ; - -return read_size (data + field->offset, field->size); -} - -void *raw_field_ptr (struct event *event,const char *name,void *data) -{ -struct format_field *field; - - field =find_any_field (event, name); -if (!field) -return NULL ; - -if (field->flags &FIELD_IS_DYNAMIC ) { -int offset; - - offset = *(int *)(data + field->offset); - offset &=0xffff ; - -return data + offset; - } - -return data + field->offset; -} - -static int get_common_info (const char *type,int *offset,int *size) -{ -struct event *event; -struct format_field *field; - -/* -* All events should have the same common elements. -* Pick any event to find where the type is; -*/ -if (!event_list) -die ("no event_list!" ); - - event = event_list; - field =find_common_field (event, type); -if (!field) -die ("field '%s' not found" , type); - - *offset = field->offset; - *size = field->size; - -return 0 ; -} - -static int __parse_common (void *data,int *size,int *offset, -const char *name) -{ -int ret; - -if (!*size) { - ret =get_common_info (name, offset, size); -if (ret <0 ) -return ret; - } -return read_size (data + *offset, *size); -} - -int trace_parse_common_type (void *data) -{ -static int type_offset; -static int type_size; - -return __parse_common (data, &type_size, &type_offset, -"common_type" ); -} - -int trace_parse_common_pid (void *data) -{ -static int pid_offset; -static int pid_size; - -return __parse_common (data, &pid_size, &pid_offset, -"common_pid" ); -} - -int parse_common_pc (void *data) -{ -static int pc_offset; -static int pc_size; - -return __parse_common (data, &pc_size, &pc_offset, -"common_preempt_count" ); -} - -int parse_common_flags (void *data) -{ -static int flags_offset; -static int flags_size; - -return __parse_common (data, &flags_size, &flags_offset, -"common_flags" ); -} - -int parse_common_lock_depth (void *data) -{ -static int ld_offset; -static int ld_size; -int ret; - - ret =__parse_common (data, &ld_size, &ld_offset, -"common_lock_depth" ); -if (ret <0 ) -return -1 ; - -return ret; -} - -struct event *trace_find_event (int id) -{ -struct event *event; - -for (event = event_list; event; event = event->next) { -if (event->id == id) -break ; - } -return event; -} - -struct event *trace_find_next_event (struct event *event) -{ -if (!event) -return event_list; - -return event->next; -} - -static unsigned long long eval_num_arg (void *data,int size, -struct event *event,struct print_arg *arg) -{ -unsigned long long val =0 ; -unsigned long long left, right; -struct print_arg *larg; - -switch (arg->type) { -case PRINT_NULL : -/* ?? */ -return 0 ; -case PRINT_ATOM : -return strtoull (arg->atom.atom,NULL ,0 ); -case PRINT_FIELD : -if (!arg->field.field) { - arg->field.field =find_any_field (event, arg->field.name); -if (!arg->field.field) -die ("field %s not found" , arg->field.name); - } -/* must be a number */ - val =read_size (data + arg->field.field->offset, - arg->field.field->size); -break ; -case PRINT_FLAGS : -case PRINT_SYMBOL : -break ; -case PRINT_TYPE : -return eval_num_arg (data, size, event, arg->typecast.item); -case PRINT_STRING : -return 0 ; -break ; -case PRINT_OP : -if (strcmp (arg->op.op,"[" ) ==0 ) { -/* -* Arrays are special, since we don't want -* to read the arg as is. -*/ -if (arg->op.left->type !=PRINT_FIELD ) - goto default_op;/* oops, all bets off */ - larg = arg->op.left; -if (!larg->field.field) { - larg->field.field = -find_any_field (event, larg->field.name); -if (!larg->field.field) -die ("field %s not found" , larg->field.name); - } - right =eval_num_arg (data, size, event, arg->op.right); - val =read_size (data + larg->field.field->offset + - right * long_size, long_size); -break ; - } - default_op: - left =eval_num_arg (data, size, event, arg->op.left); - right =eval_num_arg (data, size, event, arg->op.right); -switch (arg->op.op[0 ]) { -case '|' : -if (arg->op.op[1 ]) - val = left || right; -else - val = left | right; -break ; -case '&' : -if (arg->op.op[1 ]) - val = left && right; -else - val = left & right; -break ; -case '<' : -switch (arg->op.op[1 ]) { -case 0 : - val = left < right; -break ; -case '<' : - val = left << right; -break ; -case '=' : - val = left <= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '>' : -switch (arg->op.op[1 ]) { -case 0 : - val = left > right; -break ; -case '>' : - val = left >> right; -break ; -case '=' : - val = left >= right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -case '=' : -if (arg->op.op[1 ] !='=' ) -die ("unknown op '%s'" , arg->op.op); - val = left == right; -break ; -case '-' : - val = left - right; -break ; -case '+' : - val = left + right; -break ; -default : -die ("unknown op '%s'" , arg->op.op); - } -break ; -default :/* not sure what to do there */ -return 0 ; - } -return val; -} - -struct flag { -const char *name; -unsigned long long value; -}; - -static const struct flag flags[] = { - {"HI_SOFTIRQ" ,0 }, - {"TIMER_SOFTIRQ" ,1 }, - {"NET_TX_SOFTIRQ" ,2 }, - {"NET_RX_SOFTIRQ" ,3 }, - {"BLOCK_SOFTIRQ" ,4 }, - {"BLOCK_IOPOLL_SOFTIRQ" ,5 }, - {"TASKLET_SOFTIRQ" ,6 }, - {"SCHED_SOFTIRQ" ,7 }, - {"HRTIMER_SOFTIRQ" ,8 }, - {"RCU_SOFTIRQ" ,9 }, - - {"HRTIMER_NORESTART" ,0 }, - {"HRTIMER_RESTART" ,1 }, -}; - -unsigned long long eval_flag (const char *flag) -{ -int i; - -/* -* Some flags in the format files do not get converted. -* If the flag is not numeric, see if it is something that -* we already know about. -*/ -if (isdigit (flag[0 ])) -return strtoull (flag,NULL ,0 ); - -for (i =0 ; i < (int )(sizeof (flags)/sizeof (flags[0 ])); i++) -if (strcmp (flags[i].name, flag) ==0 ) -return flags[i].value; - -return 0 ; -} - -static void print_str_arg (void *data,int size, -struct event *event,struct print_arg *arg) -{ -struct print_flag_sym *flag; -unsigned long long val, fval; -char *str; -int print; - -switch (arg->type) { -case PRINT_NULL : -/* ?? */ -return ; -case PRINT_ATOM : -printf ("%s" , arg->atom.atom); -return ; -case PRINT_FIELD : -if (!arg->field.field) { - arg->field.field =find_any_field (event, arg->field.name); -if (!arg->field.field) -die ("field %s not found" , arg->field.name); - } - str =malloc_or_die (arg->field.field->size +1 ); -memcpy (str, data + arg->field.field->offset, - arg->field.field->size); - str[arg->field.field->size] =0 ; -printf ("%s" , str); -free (str); -break ; -case PRINT_FLAGS : - val =eval_num_arg (data, size, event, arg->flags.field); - print =0 ; -for (flag = arg->flags.flags; flag; flag = flag->next) { - fval =eval_flag (flag->value); -if (!val && !fval) { -printf ("%s" , flag->str); -break ; - } -if (fval && (val & fval) == fval) { -if (print && arg->flags.delim) -printf ("%s" , arg->flags.delim); -printf ("%s" , flag->str); - print =1 ; - val &= ~fval; - } - } -break ; -case PRINT_SYMBOL : - val =eval_num_arg (data, size, event, arg->symbol.field); -for (flag = arg->symbol.symbols; flag; flag = flag->next) { - fval =eval_flag (flag->value); -if (val == fval) { -printf ("%s" , flag->str); -break ; - } - } -break ; - -case PRINT_TYPE : -break ; -case PRINT_STRING : { -int str_offset; - -if (arg->string.offset ==-1 ) { -struct format_field *f; - - f =find_any_field (event, arg->string.string); - arg->string.offset = f->offset; - } - str_offset = *(int *)(data + arg->string.offset); - str_offset &=0xffff ; -printf ("%s" , ((char *)data) + str_offset); -break ; - } -case PRINT_OP : -/* -* The only op for string should be ? : -*/ -if (arg->op.op[0 ] !='?' ) -return ; - val =eval_num_arg (data, size, event, arg->op.left); -if (val) -print_str_arg (data, size, event, arg->op.right->op.left); -else -print_str_arg (data, size, event, arg->op.right->op.right); -break ; -default : -/* well... */ -break ; - } -} - -static struct print_arg *make_bprint_args (char *fmt,void *data,int size,struct event *event) -{ -static struct format_field *field, *ip_field; -struct print_arg *args, *arg, **next; -unsigned long long ip, val; -char *ptr; -void *bptr; - -if (!field) { - field =find_field (event,"buf" ); -if (!field) -die ("can't find buffer field for binary printk" ); - ip_field =find_field (event,"ip" ); -if (!ip_field) -die ("can't find ip field for binary printk" ); - } - - ip =read_size (data + ip_field->offset, ip_field->size); - -/* -* The first arg is the IP pointer. -*/ - args =malloc_or_die (sizeof (*args)); - arg = args; - arg->next =NULL ; - next = &arg->next; - - arg->type =PRINT_ATOM ; - arg->atom.atom =malloc_or_die (32 ); -sprintf (arg->atom.atom,"%lld" , ip); - -/* skip the first "%pf : " */ -for (ptr = fmt +6 , bptr = data + field->offset; - bptr < data + size && *ptr; ptr++) { -int ls =0 ; - -if (*ptr =='%' ) { - process_again: - ptr++; -switch (*ptr) { -case '%' : -break ; -case 'l' : - ls++; - goto process_again; -case 'L' : - ls =2 ; - goto process_again; - case '0' ... '9': - goto process_again; -case 'p' : - ls =1 ; -/* fall through */ -case 'd' : -case 'u' : -case 'x' : -case 'i' : -/* the pointers are always 4 bytes aligned */ - bptr = (void *)(((unsigned long )bptr +3 ) & - ~3 ); -switch (ls) { -case 0 : -case 1 : - ls = long_size; -break ; -case 2 : - ls =8 ; -default : -break ; - } - val =read_size (bptr, ls); - bptr += ls; - arg =malloc_or_die (sizeof (*arg)); - arg->next =NULL ; - arg->type =PRINT_ATOM ; - arg->atom.atom =malloc_or_die (32 ); -sprintf (arg->atom.atom,"%lld" , val); - *next = arg; - next = &arg->next; -break ; -case 's' : - arg =malloc_or_die (sizeof (*arg)); - arg->next =NULL ; - arg->type =PRINT_STRING ; - arg->string.string =strdup (bptr); - bptr +=strlen (bptr) +1 ; - *next = arg; - next = &arg->next; -default : -break ; - } - } - } - -return args; -} - -static void free_args (struct print_arg *args) -{ -struct print_arg *next; - -while (args) { - next = args->next; - -if (args->type ==PRINT_ATOM ) -free (args->atom.atom); -else -free (args->string.string); -free (args); - args = next; - } -} - -static char *get_bprint_format(void *data, int size __unused, struct event *event) -{ -unsigned long long addr; -static struct format_field *field; -struct printk_map *printk; -char *format; -char *p; - -if (!field) { - field =find_field (event,"fmt" ); -if (!field) -die ("can't find format field for binary printk" ); -printf ("field->offset = %d size=%d\n" , field->offset, field->size); - } - - addr =read_size (data + field->offset, field->size); - - printk =find_printk (addr); -if (!printk) { - format =malloc_or_die (45 ); -sprintf (format,"%%pf : (NO FORMAT FOUND at %llx)\n" , - addr); -return format; - } - - p = printk->printk; -/* Remove any quotes. */ -if (*p =='"' ) - p++; - format =malloc_or_die (strlen (p) +10 ); -sprintf (format,"%s : %s" ,"%pf" , p); -/* remove ending quotes and new line since we will add one too */ - p = format +strlen (format) -1 ; -if (*p =='"' ) - *p =0 ; - - p -=2 ; -if (strcmp (p,"\\n" ) ==0 ) - *p =0 ; - -return format; -} - -static void pretty_print (void *data,int size,struct event *event) -{ -struct print_fmt *print_fmt = &event->print_fmt; -struct print_arg *arg = print_fmt->args; -struct print_arg *args =NULL ; -const char *ptr = print_fmt->format; -unsigned long long val; -struct func_map *func; -const char *saveptr; -char *bprint_fmt =NULL ; -char format[32 ]; -int show_func; -int len; -int ls; - -if (event->flags &EVENT_FL_ISFUNC ) - ptr =" %pF <-- %pF" ; - -if (event->flags &EVENT_FL_ISBPRINT ) { - bprint_fmt =get_bprint_format (data, size, event); - args =make_bprint_args (bprint_fmt, data, size, event); - arg = args; - ptr = bprint_fmt; - } - -for (; *ptr; ptr++) { - ls =0 ; -if (*ptr =='\\' ) { - ptr++; -switch (*ptr) { -case 'n' : -printf ("\n" ); -break ; -case 't' : -printf ("\t" ); -break ; -case 'r' : -printf ("\r" ); -break ; -case '\\' : -printf ("\\" ); -break ; -default : -printf ("%c" , *ptr); -break ; - } - - }else if (*ptr =='%' ) { - saveptr = ptr; - show_func =0 ; - cont_process: - ptr++; -switch (*ptr) { -case '%' : -printf ("%%" ); -break ; -case 'l' : - ls++; - goto cont_process; -case 'L' : - ls =2 ; - goto cont_process; -case 'z' : -case 'Z' : - case '0' ... '9': - goto cont_process; -case 'p' : -if (long_size ==4 ) - ls =1 ; -else - ls =2 ; - -if (*(ptr+1 ) =='F' || - *(ptr+1 ) =='f' ) { - ptr++; - show_func = *ptr; - } - -/* fall through */ -case 'd' : -case 'i' : -case 'x' : -case 'X' : -case 'u' : -if (!arg) -die ("no argument match" ); - - len = ((unsigned long )ptr +1 ) - - (unsigned long )saveptr; - -/* should never happen */ -if (len >32 ) -die ("bad format!" ); - -memcpy (format, saveptr, len); - format[len] =0 ; - - val =eval_num_arg (data, size, event, arg); - arg = arg->next; - -if (show_func) { - func =find_func (val); -if (func) { -printf ("%s" , func->func); -if (show_func =='F' ) -printf ("+0x%llx" , - val - func->addr); -break ; - } - } -switch (ls) { -case 0 : -printf (format, (int )val); -break ; -case 1 : -printf (format, (long )val); -break ; -case 2 : -printf (format, (long long )val); -break ; -default : -die ("bad count (%d)" , ls); - } -break ; -case 's' : -if (!arg) -die ("no matching argument" ); - -print_str_arg (data, size, event, arg); - arg = arg->next; -break ; -default : -printf (">%c<" , *ptr); - - } - }else -printf ("%c" , *ptr); - } - -if (args) { -free_args (args); -free (bprint_fmt); - } -} - -static inline int log10_cpu (int nb) -{ -if (nb /100 ) -return 3 ; -if (nb /10 ) -return 2 ; -return 1 ; -} - -static void print_lat_fmt(void *data, int size __unused) -{ -unsigned int lat_flags; -unsigned int pc; -int lock_depth; -int hardirq; -int softirq; - - lat_flags =parse_common_flags (data); - pc =parse_common_pc (data); - lock_depth =parse_common_lock_depth (data); - - hardirq = lat_flags &TRACE_FLAG_HARDIRQ ; - softirq = lat_flags &TRACE_FLAG_SOFTIRQ ; - -printf ("%c%c%c" , - (lat_flags &TRACE_FLAG_IRQS_OFF ) ?'d' : - (lat_flags &TRACE_FLAG_IRQS_NOSUPPORT ) ? -'X' :'.' , - (lat_flags &TRACE_FLAG_NEED_RESCHED ) ? -'N' :'.' , - (hardirq && softirq) ?'H' : - hardirq ?'h' : softirq ?'s' :'.' ); - -if (pc) -printf ("%x" , pc); -else -printf ("." ); - -if (lock_depth <0 ) -printf (". " ); -else -printf ("%d " , lock_depth); -} - -#define TRACE_GRAPH_INDENT 2 - -static struct record * -get_return_for_leaf (int cpu,int cur_pid,unsigned long long cur_func, -struct record *next) -{ -struct format_field *field; -struct event *event; -unsigned long val; -int type; -int pid; - - type =trace_parse_common_type (next->data); - event =trace_find_event (type); -if (!event) -return NULL ; - -if (!(event->flags &EVENT_FL_ISFUNCRET )) -return NULL ; - - pid =trace_parse_common_pid (next->data); - field =find_field (event,"func" ); -if (!field) -die ("function return does not have field func" ); - - val =read_size (next->data + field->offset, field->size); - -if (cur_pid != pid || cur_func != val) -return NULL ; - -/* this is a leaf, now advance the iterator */ -return trace_read_data (cpu); -} - -/* Signal a overhead of time execution to the output */ -static void print_graph_overhead (unsigned long long duration) -{ -/* Non nested entry or return */ -if (duration == ~0ULL ) -return (void )printf (" " ); - -/* Duration exceeded 100 msecs */ -if (duration >100000ULL ) -return (void )printf ("! " ); - -/* Duration exceeded 10 msecs */ -if (duration >10000ULL ) -return (void )printf ("+ " ); - -printf (" " ); -} - -static void print_graph_duration (unsigned long long duration) -{ -unsigned long usecs = duration /1000 ; -unsigned long nsecs_rem = duration %1000 ; -/* log10(ULONG_MAX) + '\0' */ -char msecs_str[21 ]; -char nsecs_str[5 ]; -int len; -int i; - -sprintf (msecs_str,"%lu" , usecs); - -/* Print msecs */ - len =printf ("%lu" , usecs); - -/* Print nsecs (we don't want to exceed 7 numbers) */ -if (len <7 ) { -snprintf (nsecs_str,8 - len,"%03lu" , nsecs_rem); - len +=printf (".%s" , nsecs_str); - } - -printf (" us " ); - -/* Print remaining spaces to fit the row's width */ -for (i = len; i <7 ; i++) -printf (" " ); - -printf ("| " ); -} - -static void -print_graph_entry_leaf (struct event *event,void *data,struct record *ret_rec) -{ -unsigned long long rettime, calltime; -unsigned long long duration, depth; -unsigned long long val; -struct format_field *field; -struct func_map *func; -struct event *ret_event; -int type; -int i; - - type =trace_parse_common_type (ret_rec->data); - ret_event =trace_find_event (type); - - field =find_field (ret_event,"rettime" ); -if (!field) -die ("can't find rettime in return graph" ); - rettime =read_size (ret_rec->data + field->offset, field->size); - - field =find_field (ret_event,"calltime" ); -if (!field) -die ("can't find rettime in return graph" ); - calltime =read_size (ret_rec->data + field->offset, field->size); - - duration = rettime - calltime; - -/* Overhead */ -print_graph_overhead (duration); - -/* Duration */ -print_graph_duration (duration); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - - field =find_field (event,"func" ); -if (!field) -die ("can't find func in entry graph" ); - val =read_size (data + field->offset, field->size); - func =find_func (val); - -if (func) -printf ("%s();" , func->func); -else -printf ("%llx();" , val); -} - -static void print_graph_nested (struct event *event,void *data) -{ -struct format_field *field; -unsigned long long depth; -unsigned long long val; -struct func_map *func; -int i; - -/* No overhead */ -print_graph_overhead (-1 ); - -/* No time */ -printf (" | " ); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - - field =find_field (event,"func" ); -if (!field) -die ("can't find func in entry graph" ); - val =read_size (data + field->offset, field->size); - func =find_func (val); - -if (func) -printf ("%s() {" , func->func); -else -printf ("%llx() {" , val); -} - -static void -pretty_print_func_ent (void *data,int size,struct event *event, -int cpu,int pid) -{ -struct format_field *field; -struct record *rec; -void *copy_data; -unsigned long val; - -if (latency_format) { -print_lat_fmt (data, size); -printf (" | " ); - } - - field =find_field (event,"func" ); -if (!field) -die ("function entry does not have func field" ); - - val =read_size (data + field->offset, field->size); - -/* -* peek_data may unmap the data pointer. Copy it first. -*/ - copy_data =malloc_or_die (size); -memcpy (copy_data, data, size); - data = copy_data; - - rec =trace_peek_data (cpu); -if (rec) { - rec =get_return_for_leaf (cpu, pid, val, rec); -if (rec) { -print_graph_entry_leaf (event, data, rec); - goto out_free; - } - } -print_graph_nested (event, data); -out_free: -free (data); -} - -static void -pretty_print_func_ret(void *data, int size __unused, struct event *event) -{ -unsigned long long rettime, calltime; -unsigned long long duration, depth; -struct format_field *field; -int i; - -if (latency_format) { -print_lat_fmt (data, size); -printf (" | " ); - } - - field =find_field (event,"rettime" ); -if (!field) -die ("can't find rettime in return graph" ); - rettime =read_size (data + field->offset, field->size); - - field =find_field (event,"calltime" ); -if (!field) -die ("can't find calltime in return graph" ); - calltime =read_size (data + field->offset, field->size); - - duration = rettime - calltime; - -/* Overhead */ -print_graph_overhead (duration); - -/* Duration */ -print_graph_duration (duration); - - field =find_field (event,"depth" ); -if (!field) -die ("can't find depth in entry graph" ); - depth =read_size (data + field->offset, field->size); - -/* Function */ -for (i =0 ; i < (int )(depth *TRACE_GRAPH_INDENT ); i++) -printf (" " ); - -printf ("}" ); -} - -static void -pretty_print_func_graph (void *data,int size,struct event *event, -int cpu,int pid) -{ -if (event->flags &EVENT_FL_ISFUNCENT ) -pretty_print_func_ent (data, size, event, cpu, pid); -else if (event->flags &EVENT_FL_ISFUNCRET ) -pretty_print_func_ret (data, size, event); -printf ("\n" ); -} - -void print_trace_event (int cpu,void *data,int size) -{ -struct event *event; -int type; -int pid; - - type =trace_parse_common_type (data); - - event =trace_find_event (type); -if (!event) { -warning ("ug! no event found for type %d" , type); -return ; - } - - pid =trace_parse_common_pid (data); - -if (event->flags & (EVENT_FL_ISFUNCENT |EVENT_FL_ISFUNCRET )) -return pretty_print_func_graph (data, size, event, cpu, pid); - -if (latency_format) -print_lat_fmt (data, size); - -if (event->flags &EVENT_FL_FAILED ) { -printf ("EVENT '%s' FAILED TO PARSE\n" , - event->name); -return ; - } - -pretty_print (data, size, event); -} - -static void print_fields (struct print_flag_sym *field) -{ -printf ("{ %s, %s }" , field->value, field->str); -if (field->next) { -printf (", " ); -print_fields (field->next); - } -} - -static void print_args (struct print_arg *args) -{ -int print_paren =1 ; - -switch (args->type) { -case PRINT_NULL : -printf ("null" ); -break ; -case PRINT_ATOM : -printf ("%s" , args->atom.atom); -break ; -case PRINT_FIELD : -printf ("REC->%s" , args->field.name); -break ; -case PRINT_FLAGS : -printf ("__print_flags(" ); -print_args (args->flags.field); -printf (", %s, " , args->flags.delim); -print_fields (args->flags.flags); -printf (")" ); -break ; -case PRINT_SYMBOL : -printf ("__print_symbolic(" ); -print_args (args->symbol.field); -printf (", " ); -print_fields (args->symbol.symbols); -printf (")" ); -break ; -case PRINT_STRING : -printf ("__get_str(%s)" , args->string.string); -break ;Lines of this file are not shown. View the raw message.
tools/perf/util/trace-parse-events.c new file +3128
-0Lines of this file are not shown. View the raw message.
tools/perf/util/trace-parse-events.h new file +273
-0Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Quoted 13 lines · Steven Rostedt
Quoted 12 lines · David Ahern
Hi Steve:
Quoted 9 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Move the
trace-event-parse.ccode that originally came from trace-cmd into their own files. The new file will be calledtrace-parse-events.c, as the name of trace-cmd's file wasparse-events.ctoo, but it conflicted with theparse-events.cfile in perf that parses the command line.This tries to update the code with mimimal changes.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in
trace-parse-events.candtrace-parse-events.h.What branch should these apply cleanly to?
They are based off of v3.0. You can get these patches from my repo as described in the 0/8 announce email.
Unfortunately I hastily deleted the 0/8 thread while on vacation last week (gmail on Android thing), so I apologize for shifting the discussion.
With a little bit of hacking on top of your patches I was able to get the trace-cmd plugins working with perf. e.g.,
qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0
vec 239 (Fixed|edge)
qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239
qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0
qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESSrip 0xffffffff8101dbe4 info 10b0 0
So, what is the next step for making this a reality -- i.e., getting the common code into a lib in tools?
David
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Quoted 5 lines · David Ahern
Quoted 2 lines
They are based off of v3.0. You can get these patches from my repo as described in the 0/8 announce email.
Unfortunately I hastily deleted the 0/8 thread while on vacation last week (gmail on Android thing), so I apologize for shifting the discussion.
Understood.
Quoted 9 lines
With a little bit of hacking on top of your patches I was able to get the trace-cmd plugins working with perf. e.g.,
qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0 vec 239 (Fixed|edge) qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239 qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0 qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESSrip
0xffffffff8101dbe4info 10b0 0
That's awesome!
Quoted 3 lines
So, what is the next step for making this a reality -- i.e., getting the common code into a lib in tools?
Yeah, once everyone agrees with everything. I personally prefer things to be in tools/lib/... and have all other tools depend on it. For the names of these libraries, I'm game for anything.
Arnaldo, what's your preference, as you were the one that suggested that it not be called libperf?
But I think this is a great step forward in making ftrace and perf work better together :)
-- Steve
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
In reply to David AhernQuoted 33 lines · David Ahern
Quoted 13 lines · Steven Rostedt
Quoted 12 lines · David Ahern
Hi Steve:
Quoted 9 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Move the
trace-event-parse.ccode that originally came from trace-cmd into their own files. The new file will be calledtrace-parse-events.c, as the name of trace-cmd's file wasparse-events.ctoo, but it conflicted with theparse-events.cfile in perf that parses the command line.This tries to update the code with mimimal changes.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in
trace-parse-events.candtrace-parse-events.h.What branch should these apply cleanly to?
They are based off of v3.0. You can get these patches from my repo as described in the 0/8 announce email.
Unfortunately I hastily deleted the 0/8 thread while on vacation last week (gmail on Android thing), so I apologize for shifting the discussion.
With a little bit of hacking on top of your patches I was able to get the trace-cmd plugins working with perf. e.g.,
qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0 vec 239 (Fixed|edge) qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239 qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0 qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESS
Quoted 4 lines
rip
0xffffffff8101dbe4info 10b0 0So, what is the next step for making this a reality -- i.e., getting the common code into a lib in tools?
I hope. Otherwise we'll simply get stuck with a buggy format parsing in perf.
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Quoted 36 lines · Frederic Weisbecker
Quoted 35 lines · David Ahern
Quoted 13 lines · Steven Rostedt
Quoted 12 lines · David Ahern
Hi Steve:
Quoted 9 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
Move the
trace-event-parse.ccode that originally came from trace-cmd into their own files. The new file will be calledtrace-parse-events.c, as the name of trace-cmd's file wasparse-events.ctoo, but it conflicted with theparse-events.cfile in perf that parses the command line.This tries to update the code with mimimal changes.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Perf specific code stays in the trace-event-parse.[ch] files and the common parsing code is now in
trace-parse-events.candtrace-parse-events.h.What branch should these apply cleanly to?
They are based off of v3.0. You can get these patches from my repo as described in the 0/8 announce email.
Unfortunately I hastily deleted the 0/8 thread while on vacation last week (gmail on Android thing), so I apologize for shifting the discussion.
With a little bit of hacking on top of your patches I was able to get the trace-cmd plugins working with perf. e.g.,
qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0 vec 239 (Fixed|edge) qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239 qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0 qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESSrip
0xffffffff8101dbe4info 10b0 0
Quoted 4 lines
Quoted 2 lines
So, what is the next step for making this a reality -- i.e., getting the common code into a lib in tools?
I hope. Otherwise we'll simply get stuck with a buggy format parsing in perf.
I guess to be more specific about next steps:
- should trace-cmd be moved to the tools directory in the kernel repo? that would allow code movement to a lib directory and work to be done on both trace-cmd and perf
- what's the conclusion about the name and path for the common parsing code? seems like libtraceevent or libtraceparse had the fewest collisions
- should the plugin code be moved into its own directory - e.g., tools/lib/trace-plugins. I am working on plugin changes too (eg., resolving guest RIPs to symbols in the kvm plugin).
The current patch set from Steve needs some updates (in addition to what is needed for perf to use the plugins) to handle trace-cmd and perf differences, but this is getting far down the path.
David
Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
Quoted 4 lines · David Ahern
On 08/18/2011 07:51 AM, Frederic Weisbecker wrote:
I guess to be more specific about next steps:
- should trace-cmd be moved to the tools directory in the kernel repo?
Nah, I rather keep it out of the kernel for now.
Quoted 4 lines
that would allow code movement to a lib directory and work to be done on both trace-cmd and perf
- what's the conclusion about the name and path for the common parsing code? seems like libtraceevent or libtraceparse had the fewest collisions
I guess libtraceparse is fine. Or maybe even libtraceparser.
Quoted 3 lines
- should the plugin code be moved into its own directory - e.g.,
tools/lib/trace-plugins. I am working on plugin changes too (eg., resolving guest RIPs to symbols in the kvm plugin).
I think it should have its own directory. Or maybe even have it within the kernel proper itself? Have it install like modules:
/lib/modules/v3.0-rc2/plugins/
??
Quoted 4 lines
The current patch set from Steve needs some updates (in addition to what is needed for perf to use the plugins) to handle trace-cmd and perf differences, but this is getting far down the path.
I'm currently working on other things, and I'm waiting for consensus before I waste more time on it.
Don't worry about trace-cmd. If libtraceparser becomes an installed library, I'll have trace-cmd use it directly. As long as the library stays generic (which it should) this should not cause any issues. For now, trace-cmd will keep its original libparsevents, and I can update that until we have this library in distributions.
Thanks!
-- Steve
RFC PATCH 2/8 tools/events: Add files to create libparsevent.a
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
Copy over the files from trace-cmd to the Linux tools directory such that applications like perf and latencytrace can use the more advanced parsing code.
Because some of the file names of perf conflict with trace-cmd file names, the trace-cmd files have been renamed as follows:
parse-events.c ==> event-parse.c
parse-events.h ==> event-parse.h
utils.h ==> event-utils.h
The files have been updated to handle the changes to the header files but other than that, they are identical to what was in the trace-cmd repository. The history of these files, including authorship is available at the git repo:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git
The Makefile was also copied over, but most of it was removed to focus on the parse-events code first. The parts of the Makefile for the plugins have also been removed, but will be added back when the plugin code is copied over as well. But that may be in its own separate directory.
--- tools/lib/events/Makefile | 303 +++ tools/lib/events/event-parse.c | 4966 +++++++++++++++++++++++++++++++++++++++ tools/lib/events/event-parse.h | 806 +++++++ tools/lib/events/event-utils.h | 64 + tools/lib/events/parse-filter.c | 2262 ++++++++++++++++++ tools/lib/events/parse-utils.c | 110 + tools/lib/events/trace-seq.c | 199 ++ 7 files changed, 8710 insertions(+), 0 deletions(-) create mode 100644 tools/lib/events/Makefile create mode 100644 tools/lib/events/event-parse.c create mode 100644 tools/lib/events/event-parse.h create mode 100644 tools/lib/events/event-utils.h create mode 100644 tools/lib/events/parse-filter.c create mode 100644 tools/lib/events/parse-utils.c create mode 100644 tools/lib/events/trace-seq.c
tools/lib/events/Makefile new file +303 -0
@@ -0,0 +1,303 @@ +# trace-cmd version +EP_VERSION = 1 +EP_PATCHLEVEL = 1 +EP_EXTRAVERSION = 0 + +# file format version +FILE_VERSION = 6 + +MAKEFLAGS += --no-print-directory + + +# Makefiles suck: This macro sets a default value of $(2) for the +# variable named by $(1), unless the variable has been set by +# environment or command line. This is necessary for CC and AR +# because make sets default values, so the simpler ?= approach +# won't work as expected. +define allow-override + $(if $(or $(findstring environment,$(origin $(1))),\ + $(findstring command line,$(origin $(1)))),,\ + $(eval $(1) = $(2))) +endef + +# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. +$(call allow-override,CC,$(CROSS_COMPILE)gcc) +$(call allow-override,AR,$(CROSS_COMPILE)ar) + +EXT = -std=gnu99 +INSTALL = install + +# Use DESTDIR for installing into a different root directory. +# This is useful for building a package. The program will be +# installed in this directory as if it was the root directory. +# Then the build tool can move it later. +DESTDIR ?= +DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' + +prefix ?= /usr/local +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +man_dir = $(prefix)/share/man +man_dir_SQ = '$(subst ','\'',$(man_dir))' +html_install = $(prefix)/share/kernelshark/html +html_install_SQ = '$(subst ','\'',$(html_install))' +img_install = $(prefix)/share/kernelshark/html/images +img_install_SQ = '$(subst ','\'',$(img_install))' + +export man_dir man_dir_SQ html_install html_install_SQ INSTALL +export img_install img_install_SQ +export DESTDIR DESTDIR_SQ + +# copy a bit from Linux kbuild + +ifeq ("$(origin V)", "command line") + VERBOSE = $(V) +endif +ifndef VERBOSE + VERBOSE = 0 +endif + +ifeq ("$(origin O)", "command line") + BUILD_OUTPUT := $(O) +endif + +ifeq ($(BUILD_SRC),) +ifneq ($(BUILD_OUTPUT),) + +define build_output + $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \ + BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 +endef + +saved-output := $(BUILD_OUTPUT) +BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) +$(if $(BUILD_OUTPUT),, \ + $(error output directory "$(saved-output)" does not exist)) + +all: sub-make + +gui: force + $(call build_output, all_cmd) + +$(filter-out gui,$(MAKECMDGOALS)): sub-make + +sub-make: force + $(call build_output, $(MAKECMDGOALS)) + + +# Leave processing to above invocation of make +skip-makefile := 1 + +endif # BUILD_OUTPUT +endif # BUILD_SRC + +# We process the rest of the Makefile if this is the final invocation of make +ifeq ($(skip-makefile),) + +srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)) +objtree := $(CURDIR) +src := $(srctree) +obj := $(objtree) + +export prefix bindir src obj + +# Shell quotes +bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) + +LIB_FILE = libparsevent.a libparsevent.so + +CONFIG_INCLUDES = +CONFIG_LIBS = +CONFIG_FLAGS = + +VERSION = $(EP_VERSION) +PATCHLEVEL = $(EP_PATCHLEVEL) +EXTRAVERSION = $(EP_EXTRAVERSION) + +OBJ = $@ +N = + +export Q VERBOSE + +EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) + +INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES) + +# Set compile option CFLAGS if not set elsewhere +CFLAGS ?= -g -Wall + +# Append required CFLAGS +override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) +override CFLAGS += $(udis86-flags) + +ifeq ($(VERBOSE),1) + Q = + print_compile = + print_app_build = + print_fpic_compile = + print_shared_lib_compile = + print_plugin_obj_compile = + print_plugin_build = + print_install = +else + Q = @ + print_compile = echo ' CC '$(OBJ); + print_app_build = echo ' BUILD '$(OBJ); + print_fpic_compile = echo ' CC FPIC '$(OBJ); + print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); + print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ); + print_plugin_build = echo ' CC PLUGI '$(OBJ); + print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); + print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; +endif + +do_fpic_compile = \ + ($(print_fpic_compile) \ + $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) + +do_app_build = \ + ($(print_app_build) \ + $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) + +do_compile_shared_library = \ + ($(print_shared_lib_compile) \ + $(CC) --shared $^ -o $@) + +do_compile_plugin_obj = \ + ($(print_plugin_obj_compile) \ + $(CC) -c $(CFLAGS) -fPIC -o $@ $<) + +do_plugin_build = \ + ($(print_plugin_build) \ + $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) + +do_build_static_lib = \ + ($(print_static_lib_build) \ + $(RM) $@; $(AR) rcs $@ $^) + + +define do_compile + $(print_compile) \ + $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; +endef + +$(obj)/%.o: $(src)/%.c + $(Q)$(call do_compile) + +%.o: $(src)/%.c + $(Q)$(call do_compile) + +PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o + +ALL_OBJS = $(PEVENT_LIB_OBJS) + +CMD_TARGETS = $(LIB_FILE) + +TARGETS = $(CMD_TARGETS) + + +all: all_cmd + +all_cmd: $(CMD_TARGETS) + +libparsevent.so: $(PEVENT_LIB_OBJS) + $(Q)$(do_compile_shared_library) + +libparsevent.a: $(PEVENT_LIB_OBJS) + $(Q)$(do_build_static_lib) + +$(PEVENT_LIB_OBJS): %.o: $(src)/%.c + $(Q)$(do_fpic_compile) + +define make_version.h + (echo '/* This file is automatically generated. Do not modify. */'; \ + echo \#define VERSION_CODE $(shell \ + expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ + echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ + echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ + echo '#define FILE_VERSION '$(FILE_VERSION); \ + ) > $1 +endef + +define update_version.h + ($(call make_version.h, [email protected]); \ + if [ -r $@ ] && cmp -s $@ [email protected]; then \ + rm -f [email protected]; \ + else \ + echo ' UPDATE $@'; \ + mv -f [email protected] $@; \ + fi); +endef + +ep_version.h: force + $(Q)$(N)$(call update_version.h) + +VERSION_FILES = ep_version.h + +define update_dir + (echo $1 > [email protected]; \ + if [ -r $@ ] && cmp -s $@ [email protected]; then \ + rm -f [email protected]; \ + else \ + echo ' UPDATE $@'; \ + mv -f [email protected] $@; \ + fi); +endef + +## make deps + +all_objs := $(sort $(ALL_OBJS)) +all_deps := $(all_objs:%.o=.%.d) + +define check_deps + $(CC) -M $(CFLAGS) $< > $@; +endef + +$(gui_deps): ks_version.h +$(non_gui_deps): tc_version.h + +$(all_deps): .%.d: $(src)/%.c + $(Q)$(call check_deps) + +$(all_objs) : %.o : .%.d + +dep_includes := $(wildcard $(all_deps)) + +ifneq ($(dep_includes),) + include $(dep_includes) +endif + +tags: force + $(RM) tags + find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px + +TAGS: force + $(RM) TAGS + find . -name '*.[ch]' | xargs etags + +define do_install + $(print_install) \ + if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ + fi; \ + $(INSTALL) $1 '$(DESTDIR_SQ)$2' +endef + +install_lib: all_cmd install_plugins install_python + $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) + +install: install_lib + +clean: + $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d + $(RM) tags TAGS + +endif # skip-makefile + +PHONY += force +force: + +# Declare the contents of the .PHONY variable as phony. We keep that +# information in a variable so we can use it in if_changed and friends. +.PHONY: $(PHONY)
tools/lib/events/event-parse.c new file +4966 -0
2,697 lines not on this page · raw message
tools/lib/events/event-parse.h new file +806 -0
806 lines not on this page · raw message
tools/lib/events/event-utils.h new file +64 -0
64 lines not on this page · raw message
tools/lib/events/parse-filter.c new file +2262 -0
2,262 lines not on this page · raw message
tools/lib/events/parse-utils.c new file +110 -0
110 lines not on this page · raw message
tools/lib/events/trace-seq.c new file +199 -0
199 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.5.4
Part of the diff is not shown here. View the raw message.
RFC PATCH 3/8 perf: Build libparsevent.a
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
Have building perf also build libparsevent.a. Currently, perf does not use the code within libparsevent.a, but it soon will.
--- tools/perf/Makefile | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-)
tools/perf/Makefile +10 -1
@@ -1,5 +1,6 @@ ifeq ("$(origin O)", "command line") OUTPUT := $(O)/ + COMMAND_O := O=$(O) endif # The default target of this Makefile is...
@@ -187,6 +188,9 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) +EVENT_PARSE_DIR = ../lib/events/ +LIBPARSEVENT = $(OUTPUT)$(EVENT_PARSE_DIR)libparsevent.a + # # Single 'perf' binary right now: #
@@ -286,6 +290,7 @@ LIB_H += util/cpumap.h LIB_H += util/top.h LIB_H += $(ARCH_INCLUDE) LIB_H += util/cgroup.h +LIB_H += $(EVENT_PARSE_DIR)event-parse.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o
@@ -663,7 +668,7 @@ $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ -$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) +$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(LIBPARSEVENT) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ $(BUILTIN_OBJS) $(LIBS) -o $@
@@ -756,6 +761,10 @@ $(sort $(dir $(DIRECTORY_DEPS))): $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) +# libparsevent.a +$(LIBPARSEVENT): + make -C $(EVENT_PARSE_DIR) $(COMMAND_O) libparsevent.a + help: @echo 'Perf make targets:' @echo ' doc - make *all* documentation (see below)'
Signature · 1 line
1.7.5.4
RFC PATCH 4/8 events: Update tools/lib/events to work with perf
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
Some of the util functions of libparsevent.a conflict with perf, such as die(), warning() and others. Move them into event-util.h that is not included by the perf tools.
Also, as perf compiles with 'bool' the filter_arg->bool needs to be renamed to filter_arg->boolean.
--- tools/lib/events/event-parse.c | 1 + tools/lib/events/event-parse.h | 20 +++----------------- tools/lib/events/event-utils.h | 16 ++++++++++++++++ tools/lib/events/parse-filter.c | 32 ++++++++++++++++---------------- tools/lib/events/trace-seq.c | 1 + 5 files changed, 37 insertions(+), 33 deletions(-)
tools/lib/events/event-parse.c +1 -0
@@ -33,6 +33,7 @@#include <errno.h> #include "event-parse.h" +#include "event-utils.h" static const char *input_buf;static unsigned long long input_buf_ptr;
tools/lib/events/event-parse.h +3 -17
@@ -167,6 +167,8 @@ enum format_flags {FIELD_IS_STRING =8 ,FIELD_IS_DYNAMIC =16 ,FIELD_IS_LONG =32 , +FIELD_IS_FLAG =64 , + FIELD_IS_SYMBOLIC = 128, }; struct format_field {
@@ -406,22 +408,6 @@ struct pevent {struct event_format *last_event; }; -/* Can be overridden */ -void die (const char *fmt, ...); -void *malloc_or_die (unsigned int size); -void warning (const char *fmt, ...); -void pr_stat (const char *fmt, ...); -void vpr_stat (const char *fmt,va_list ap); - -/* Always available */ -void __die (const char *fmt, ...); -void __warning (const char *fmt, ...); -void __pr_stat (const char *fmt, ...); - -void __vdie (const char *fmt, ...); -void __vwarning (const char *fmt, ...); -void __vpr_stat (const char *fmt, ...); -static inline unsigned short __data2host2 (struct pevent *pevent,unsigned short data) {
@@ -734,7 +720,7 @@ struct filter_arg_str {struct filter_arg {enum filter_arg_type type;union { -struct filter_arg_boolean bool; +struct filter_arg_boolean boolean;struct filter_arg_field field;struct filter_arg_value value;struct filter_arg_op op;
tools/lib/events/event-utils.h +16 -0
@@ -23,6 +23,22 @@#include <ctype.h> +/* Can be overridden */ +void die (const char *fmt, ...); +void *malloc_or_die (unsigned int size); +void warning (const char *fmt, ...); +void pr_stat (const char *fmt, ...); +void vpr_stat (const char *fmt,va_list ap); + +/* Always available */ +void __die (const char *fmt, ...); +void __warning (const char *fmt, ...); +void __pr_stat (const char *fmt, ...); + +void __vdie (const char *fmt, ...); +void __vwarning (const char *fmt, ...); +void __vpr_stat (const char *fmt, ...); +static inline char *strim (char *string) {char *ret;
tools/lib/events/parse-filter.c +16 -16
@@ -359,7 +359,7 @@ create_arg_item(struct event_format *event,if (strcmp (token,COMM ) !=0 ) {/* not a field, Make it false */ arg->type =FILTER_ARG_BOOLEAN ; - arg->bool.value =FILTER_FALSE ; + arg->boolean.value =FILTER_FALSE ;break ; }/* If token is 'COMM' then it is special */
@@ -487,7 +487,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,free_arg (left);free_arg (arg); op->type =FILTER_ARG_BOOLEAN ; - op->bool.value =FILTER_FALSE ; + op->boolean.value =FILTER_FALSE ;break ; }
@@ -772,7 +772,7 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)/* bad case */ case FILTER_ARG_BOOLEAN : -return FILTER_VAL_FALSE + arg->bool.value; +return FILTER_VAL_FALSE + arg->boolean.value;/* good cases: */ case FILTER_ARG_STR :
@@ -871,7 +871,7 @@ static struct filter_arg *collapse_tree(struct filter_arg *arg)free_arg (arg); arg =allocate_arg (); arg->type =FILTER_ARG_BOOLEAN ; - arg->bool.value = ret ==FILTER_VAL_TRUE ; + arg->boolean.value = ret ==FILTER_VAL_TRUE ; }return arg;
@@ -1116,7 +1116,7 @@ process_event(struct event_format *event, const char *filter_str,if (!*parg) { *parg =allocate_arg (); (*parg)->type =FILTER_ARG_BOOLEAN ; - (*parg)->bool.value =FILTER_FALSE ; + (*parg)->boolean.value =FILTER_FALSE ; }return 0 ;
@@ -1139,7 +1139,7 @@ static int filter_event(struct event_filter *filter,/* just add a TRUE arg */ arg =allocate_arg (); arg->type =FILTER_ARG_BOOLEAN ; - arg->bool.value =FILTER_TRUE ; + arg->boolean.value =FILTER_TRUE ; } filter_type =add_filter_type (filter, event->id);
@@ -1369,9 +1369,9 @@ static int copy_filter_type(struct event_filter *filter, arg =allocate_arg (); arg->type =FILTER_ARG_BOOLEAN ;if (strcmp (str,"TRUE" ) ==0 ) - arg->bool.value =1 ; + arg->boolean.value =1 ;else - arg->bool.value =0 ; + arg->boolean.value =0 ; filter_type =add_filter_type (filter, event->id); filter_type->filter = arg;
@@ -1442,8 +1442,8 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source arg = filter_type->filter;if (arg->type !=FILTER_ARG_BOOLEAN )continue ; -if ((arg->bool.value && type ==FILTER_TRIVIAL_FALSE ) || - (!arg->bool.value && type ==FILTER_TRIVIAL_TRUE )) +if ((arg->boolean.value && type ==FILTER_TRIVIAL_FALSE ) || + (!arg->boolean.value && type ==FILTER_TRIVIAL_TRUE ))continue ; event = filter_type->event;
@@ -1497,10 +1497,10 @@ void pevent_filter_clear_trivial(struct event_filter *filter,continue ;switch (type) {case FILTER_TRIVIAL_FALSE : -if (filter_type->filter->bool.value) +if (filter_type->filter->boolean.value)continue ;case FILTER_TRIVIAL_TRUE : -if (!filter_type->filter->bool.value) +if (!filter_type->filter->boolean.value)continue ;default :break ;
@@ -1551,10 +1551,10 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,switch (type) {case FILTER_TRIVIAL_FALSE : -return !filter_type->filter->bool.value; +return !filter_type->filter->boolean.value;case FILTER_TRIVIAL_TRUE : -return filter_type->filter->bool.value; +return filter_type->filter->boolean.value;default :return 1 ; }
@@ -1783,7 +1783,7 @@ static int test_filter(struct event_format *event,switch (arg->type) {case FILTER_ARG_BOOLEAN :/* easy case */ -return arg->bool.value; +return arg->boolean.value;case FILTER_ARG_OP :return test_op (event, arg, record);
@@ -2147,7 +2147,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)switch (arg->type) {case FILTER_ARG_BOOLEAN : str =malloc_or_die (6 ); -if (arg->bool.value) +if (arg->boolean.value)strcpy (str,"TRUE" );else strcpy (str,"FALSE" );
tools/lib/events/trace-seq.c +1 -0
@@ -24,6 +24,7 @@#include <stdarg.h> #include "event-parse.h" +#include "event-utils.h" /* * The TRACE_SEQ_POISON is to catch the use of using
Signature · 1 line
1.7.5.4
RFC PATCH 5/8 perf: Have perf use the new libparsevent.a library
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
The event parsing code in perf was originally copied from trace-cmd but never was kept up-to-date with the changes that was done there. The trace-cmd libparsevent.a code is much more mature than what is currently in perf.
This updates the code to use wrappers to handle the calls to the new event parsing code. The new code requires a handle to be pass around, which removes the global event variables and allows more than one event structure to be read from different files (and different machines).
But perf still has the old global events and the code throughout perf does not yet have a nice way to pass around a handle. A global 'pevent' has been made for perf and the old calls have been created as wrappers to the new event parsing code that uses the global pevent.
With this change, perf can later incorporate the pevent handle into the perf structures and allow more than one file to be read and compared, that contains different events.
--- tools/perf/Makefile | 14 +- tools/perf/builtin-kmem.c | 6 +- tools/perf/builtin-lock.c | 26 +- tools/perf/builtin-sched.c | 42 +- tools/perf/builtin-script.c | 2 +- .../util/scripting-engines/trace-event-python.c | 16 +- tools/perf/util/trace-event-info.c | 4 +- tools/perf/util/trace-event-parse.c | 358 +++- tools/perf/util/trace-event-read.c | 34 +- tools/perf/util/trace-event.h | 50 +- tools/perf/util/trace-parse-events.c | 3128 -------------------- tools/perf/util/trace-parse-events.h | 273 -- 12 files changed, 484 insertions(+), 3469 deletions(-) delete mode 100644 tools/perf/util/trace-parse-events.c delete mode 100644 tools/perf/util/trace-parse-events.h
tools/perf/Makefile +8 -6
@@ -1,6 +1,9 @@ ifeq ("$(origin O)", "command line") OUTPUT := $(O)/ COMMAND_O := O=$(O) + EP_PATH = $(OUTPUT)/ +else + EP_PATH = $(EVENT_PARSE_DIR)/ endif # The default target of this Makefile is...
@@ -162,7 +165,7 @@ endif # Those must not be GNU-specific; they are shared with perl/ which may # be built by a different compiler. (Note that this is an artifact now # but it still might be nice to keep that distinction.) -BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include +BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(EVENT_PARSE_DIR) BASIC_LDFLAGS = # Guard against environment variables
@@ -189,7 +192,8 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) EVENT_PARSE_DIR = ../lib/events/ -LIBPARSEVENT = $(OUTPUT)$(EVENT_PARSE_DIR)libparsevent.a +LIBPARSEVENT = $(EP_PATH)libparsevent.a +EP_LIB := -L$(EP_PATH) -lparsevent # # Single 'perf' binary right now:
@@ -282,7 +286,6 @@ LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h -LIB_H += util/trace-parse-events.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h LIB_H += util/pstack.h
@@ -338,7 +341,6 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o -LIB_OBJS += $(OUTPUT)util/trace-parse-events.o LIB_OBJS += $(OUTPUT)util/svghelper.o LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/hist.o
@@ -380,7 +382,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o BUILTIN_OBJS += $(OUTPUT)builtin-test.o BUILTIN_OBJS += $(OUTPUT)builtin-inject.o -PERFLIBS = $(LIB_FILE) +PERFLIBS = $(LIB_FILE) $(LIBPARSEVENT) # Files needed for the python binding, perf.so # pyrf is just an internal name needed for all those wrappers.
@@ -668,7 +670,7 @@ $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ -$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(LIBPARSEVENT) +$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ $(BUILTIN_OBJS) $(LIBS) -o $@
tools/perf/builtin-kmem.c +3 -3
@@ -189,7 +189,7 @@ static void insert_caller_stat(unsigned long call_site, } static void process_alloc_event(void *data, - struct event *event, + struct event_format *event, int cpu, u64 timestamp __used, struct thread *thread __used,
@@ -250,7 +250,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr, }static void process_free_event (void *data, -struct event *event, +struct event_format *event,int cpu,u64 timestamp__used ,struct thread *thread__used )
@@ -278,7 +278,7 @@ static void process_free_event(void *data,static void process_raw_event (union perf_event *raw_event__used ,void *data,int cpu,u64 timestamp,struct thread *thread) { -struct event *event; +struct event_format *event;int type; type =trace_parse_common_type (data);
tools/perf/builtin-lock.c +13 -13
@@ -355,25 +355,25 @@ struct trace_release_event {struct trace_lock_handler {void (*acquire_event)(struct trace_acquire_event *, -struct event *, +struct event_format *,int cpu,u64 timestamp,struct thread *thread);void (*acquired_event)(struct trace_acquired_event *, -struct event *, +struct event_format *,int cpu,u64 timestamp,struct thread *thread);void (*contended_event)(struct trace_contended_event *, -struct event *, +struct event_format *,int cpu,u64 timestamp,struct thread *thread);void (*release_event)(struct trace_release_event *, -struct event *, +struct event_format *,int cpu,u64 timestamp,struct thread *thread);
@@ -415,7 +415,7 @@ enum acquire_flags {static void report_lock_acquire_event (struct trace_acquire_event *acquire_event, -struct event *__event__used , +struct event_format *__event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -479,7 +479,7 @@ end:static void report_lock_acquired_event (struct trace_acquired_event *acquired_event, -struct event *__event__used , +struct event_format *__event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -535,7 +535,7 @@ end:static void report_lock_contended_event (struct trace_contended_event *contended_event, -struct event *__event__used , +struct event_format *__event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -582,7 +582,7 @@ end:static void report_lock_release_event (struct trace_release_event *release_event, -struct event *__event__used , +struct event_format *__event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -646,7 +646,7 @@ static struct trace_lock_handler *trace_handler;static void process_lock_acquire_event (void *data, -struct event *event__used , +struct event_format *event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -665,7 +665,7 @@ process_lock_acquire_event(void *data,static void process_lock_acquired_event (void *data, -struct event *event__used , +struct event_format *event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -683,7 +683,7 @@ process_lock_acquired_event(void *data,static void process_lock_contended_event (void *data, -struct event *event__used , +struct event_format *event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -701,7 +701,7 @@ process_lock_contended_event(void *data,static void process_lock_release_event (void *data, -struct event *event__used , +struct event_format *event__used ,int cpu__used ,u64 timestamp__used ,struct thread *thread__used )
@@ -720,7 +720,7 @@ process_lock_release_event(void *data,static void process_raw_event (void *data,int cpu,u64 timestamp,struct thread *thread) { -struct event *event; +struct event_format *event;int type; type =trace_parse_common_type (data);
tools/perf/builtin-sched.c +21 -21
167 lines not on this page · raw message
tools/perf/builtin-script.c +1 -1
@@ -221,7 +221,7 @@ static void print_sample_start(struct perf_sample *sample, struct perf_event_attr *attr) {int type; -struct event *event; +struct event_format *event;const char *evname =NULL ;unsigned long secs;unsigned long usecs;
tools/perf/util/scripting-engines/trace-event-python.c +10 -6
@@ -36,7 +36,7 @@ PyMODINIT_FUNC initperf_trace_context(void);#define FTRACE_MAX_EVENT \ ((1 << (sizeof(unsigned short) * 8)) - 1) -struct event *events[FTRACE_MAX_EVENT ]; +struct event_format *events[FTRACE_MAX_EVENT ];#define MAX_FIELDS 64#define N_COMMON_FIELDS 7
@@ -135,7 +135,7 @@ static void define_field(enum print_arg_type field_type,Py_DECREF (t); } -static void define_event_symbols (struct event *event, +static void define_event_symbols (struct event_format *event,const char *ev_name,struct print_arg *args) {
@@ -177,6 +177,10 @@ static void define_event_symbols(struct event *event,define_event_symbols (event, ev_name, args->op.right);break ;default : +/* gcc warns for these? */ +case PRINT_BSTRING : +case PRINT_DYNAMIC_ARRAY : +case PRINT_FUNC :/* we should warn... */ return ; }
@@ -185,10 +189,10 @@ static void define_event_symbols(struct event *event,define_event_symbols (event, ev_name, args->next); } -static inline struct event *find_cache_event (int type) +static inline struct event_format *find_cache_event (int type) {static char ev_name[256 ]; -struct event *event; +struct event_format *event;if (events[type])return events[type];
@@ -215,7 +219,7 @@ static void python_process_event(union perf_event *pevent __unused,struct format_field *field;unsigned long long val;unsigned long s, ns; -struct event *event; +struct event_format *event;unsigned n =0 ;int type;int pid;
@@ -435,7 +439,7 @@ out:static int python_generate_script (const char *outfile) { -struct event *event =NULL ; +struct event_format *event =NULL ;struct format_field *f;char fname[PATH_MAX ];int not_first, count;
tools/perf/util/trace-event-info.c +3 -1
@@ -93,7 +93,7 @@ static void die(const char *fmt, ...)exit (ret); } -void *malloc_or_die (unsigned int size) +static void *malloc_or_die (unsigned int size) {void *data;
@@ -529,6 +529,8 @@ int read_tracing_data(int fd, struct list_head *pattrs)else buf[0 ] =0 ; +read_trace_init (buf[0 ], buf[0 ]); +write_or_die (buf,1 );/* save size of long */
tools/perf/util/trace-event-parse.c +353 -5
371 lines not on this page · raw message
tools/perf/util/trace-event-read.c +23 -11
@@ -53,6 +53,16 @@ static unsigned long page_size;static ssize_t calc_data_size;static bool repipe; +static void *malloc_or_die (int size) +{ +void *ret; + + ret =malloc (size); +if (!ret) +die ("malloc" ); +return ret; +} +static int do_read (int fd,void *buf,int size) {int rsize = size;
@@ -110,7 +120,7 @@ static unsigned int read4(void)unsigned int data;read_or_die (&data,4 ); -return __data2host4 (data); +return __data2host4 (perf_pevent, data); }static unsigned long long read8 (void )
@@ -118,7 +128,7 @@ static unsigned long long read8(void)unsigned long long data;read_or_die (&data,8 ); -return __data2host8 (data); +return __data2host8 (perf_pevent, data); }static char *read_string (void )
@@ -390,15 +400,15 @@ struct record *trace_peek_data(int cpu)/* FIXME: handle header page */ if (header_page_ts_size !=8 )die ("expected a long long type for timestamp" ); - cpu_data[cpu].timestamp =data2host8 (ptr); + cpu_data[cpu].timestamp =data2host8 (perf_pevent, ptr); ptr +=8 ;switch (header_page_size_size) {case 4 : - cpu_data[cpu].page_size =data2host4 (ptr); + cpu_data[cpu].page_size =data2host4 (perf_pevent, ptr); ptr +=4 ;break ;case 8 : - cpu_data[cpu].page_size =data2host8 (ptr); + cpu_data[cpu].page_size =data2host8 (perf_pevent, ptr); ptr +=8 ;break ;default :
@@ -415,7 +425,7 @@ read_again:return trace_peek_data (cpu); } - type_len_ts =data2host4 (ptr); + type_len_ts =data2host4 (perf_pevent, ptr); ptr +=4 ; type_len =type_len4host (type_len_ts);
@@ -425,14 +435,14 @@ read_again:case RINGBUF_TYPE_PADDING :if (!delta)die ("error, hit unexpected end of page" ); - length =data2host4 (ptr); + length =data2host4 (perf_pevent, ptr); ptr +=4 ; length *=4 ; ptr += length; goto read_again;case RINGBUF_TYPE_TIME_EXTEND : - extend =data2host4 (ptr); + extend =data2host4 (perf_pevent, ptr); ptr +=4 ; extend <<=TS_SHIFT ; extend += delta;
@@ -443,7 +453,7 @@ read_again: ptr +=12 ;break ;case 0 : - length =data2host4 (ptr); + length =data2host4 (perf_pevent, ptr); ptr +=4 ;die ("here! length=%d" , length);break ;
@@ -510,6 +520,8 @@ ssize_t trace_report(int fd, bool __repipe) file_bigendian = buf[0 ]; host_bigendian =bigendian (); +read_trace_init (file_bigendian, host_bigendian); +read_or_die (buf,1 ); long_size = buf[0 ];
@@ -527,11 +539,11 @@ ssize_t trace_report(int fd, bool __repipe) repipe = false;if (show_funcs) { -print_funcs (); +pevent_print_funcs (perf_pevent);return size; }if (show_printk) { -print_printk (); +pevent_print_printk (perf_pevent);return size; }
tools/perf/util/trace-event.h +49 -1
58 lines not on this page · raw message
tools/perf/util/trace-parse-events.c deleted +0 -3128
2,042 lines not on this page · raw message
tools/perf/util/trace-parse-events.h deleted +0 -273
273 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.5.4
Part of the diff is not shown here. View the raw message.
RFC PATCH 6/8 perf/events: Add flag to produce nsec output
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
libparsevent library prints out in usecs but perf wants to print out in nsecs. Add a flag that lets the user decide to print out in usec or nsec times.
--- tools/lib/events/event-parse.c | 15 ++++++++++++--- tools/lib/events/event-parse.h | 12 ++++++++++++ tools/perf/util/trace-event-parse.c | 1 + 3 files changed, 25 insertions(+), 3 deletions(-)
tools/lib/events/event-parse.c +12 -3
@@ -3935,15 +3935,16 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,struct event_format *event;unsigned long secs;unsigned long usecs; +unsigned long nsecs;const char *comm;void *data = record->data;int type;int pid;int len; +int p; secs = record->ts /NSECS_PER_SEC ; - usecs = record->ts - secs *NSECS_PER_SEC ; - usecs = (usecs +500 ) /NSECS_PER_USEC ; + nsecs = record->ts - secs *NSECS_PER_SEC ;if (record->size <0 ) {do_warning ("ug! negative record size %d" , record->size);
@@ -3968,7 +3969,15 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, }else trace_seq_printf (s,"%16s-%-5d [%03d]" , comm, pid, record->cpu); -trace_seq_printf (s," %5lu.%06lu: %s: " , secs, usecs, event->name); +if (pevent->flags &PEVENT_NSEC_OUTPUT ) { + usecs = nsecs; + p =9 ; + }else { + usecs = (nsecs +500 ) /NSECS_PER_USEC ; + p =6 ; + } + +trace_seq_printf (s," %5lu.%0*lu: %s: " , secs, p, usecs, event->name);/* Space out the event names evenly. */ len =strlen (event->name);
tools/lib/events/event-parse.h +12 -0
@@ -334,6 +334,10 @@ enum pevent_func_arg_type { PEVENT_FUNC_ARG_MAX_TYPES }; +enum pevent_flag { +PEVENT_NSEC_OUTPUT =1 ,/* output in NSECS */ +}; +struct cmdline ;struct cmdline_list ;struct func_map ;
@@ -373,6 +377,7 @@ struct pevent {struct printk_list *printklist;unsigned int printk_count; +struct event_format **events;int nr_events;struct event_format **sort_events;
@@ -397,6 +402,8 @@ struct pevent {int test_filters; +int flags; +struct format_field *bprint_ip_field;struct format_field *bprint_fmt_field;struct format_field *bprint_buf_field;
@@ -408,6 +415,11 @@ struct pevent {struct event_format *last_event; }; +static inline void pevent_set_flag (struct pevent *pevent,int flag) +{ + pevent->flags |= flag; +} +static inline unsigned short __data2host2 (struct pevent *pevent,unsigned short data) {
tools/perf/util/trace-event-parse.c +1 -0
@@ -47,6 +47,7 @@ int read_trace_init(int file_bigendian, int host_bigendian) perf_pevent =pevent_alloc (); pevent = perf_pevent; +pevent_set_flag (pevent,PEVENT_NSEC_OUTPUT );pevent_set_file_bigendian (pevent, file_bigendian);pevent_set_host_bigendian (pevent, host_bigendian);
Signature · 1 line
1.7.5.4
RFC PATCH 7/8 perf/events: Add flag/symbol format_flags
In reply to Steven RostedtFrom: Tom Zanussi <[email protected]>
This is a port of commit eb9a42caa7a92
perf trace: Add flag/symbolic format_flags
of the old trace-event-parse.c to the new event-parse.c that was written by Tom Zanussi and forward ported by Steven Rostedt.
--- tools/lib/events/event-parse.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
tools/lib/events/event-parse.c +15 -0
@@ -39,6 +39,9 @@ static const char *input_buf;static unsigned long long input_buf_ptr;static unsigned long long input_buf_siz; +static int is_flag_field; +static int is_symbolic_field; +static int show_warning =1 ;#define do_warning (fmt, ...) \
@@ -1789,6 +1792,16 @@ process_entry(struct event_format *event __unused, struct print_arg *arg, arg->type =PRINT_FIELD ; arg->field.name = field; +if (is_flag_field) { + arg->field.field =pevent_find_any_field (event, arg->field.name); + arg->field.field->flags |=FIELD_IS_FLAG ; + is_flag_field =0 ; + }else if (is_symbolic_field) { + arg->field.field =pevent_find_any_field (event, arg->field.name); + arg->field.field->flags |=FIELD_IS_SYMBOLIC ; + is_symbolic_field =0 ; + } + type =read_token (&token); *tok = token;
@@ -2393,10 +2406,12 @@ process_function(struct event_format *event, struct print_arg *arg,if (strcmp (token,"__print_flags" ) ==0 ) {free_token (token); + is_flag_field =1 ;return process_flags (event, arg, tok); }if (strcmp (token,"__print_symbolic" ) ==0 ) {free_token (token); + is_symbolic_field =1 ;return process_symbols (event, arg, tok); }if (strcmp (token,"__get_str" ) ==0 ) {
Signature · 1 line
1.7.5.4
RFC PATCH 8/8 perf/events: Correct size given to memset
In reply to Steven RostedtFrom: Julia Lawall <[email protected]>
This is a forward port of commit 5660ce34241ab
perf tools: Correct size given to memset
written by Julia Lawall and forward ported by Steven Rostedt.
--- tools/lib/events/event-parse.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
tools/lib/events/event-parse.c +1 -1
@@ -2076,7 +2076,7 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char ** goto out_free; field =malloc_or_die (sizeof (*field)); -memset (field,0 ,sizeof (field)); +memset (field,0 ,sizeof (*field)); value =arg_eval (arg); field->value =strdup (value);
Signature · 1 line
1.7.5.4
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation tooling - while previously you agreed that it should be unified. So why not do tools/perf/lib/ as you agreed before?
I'm really not interested in seeing the libdrm/libdri mess repeated. Libraries have their uses when there's some very important external interface, but here it's actively harmful as it complicates and hardcodes APIs into ABIs that are clearly not finished yet.
Really, lets not be stupid here.
Thanks,
Ingo
Quoted 17 lines · Ingo Molnar
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation tooling - while previously you agreed that it should be unified. So why not do
tools/perf/lib/as you agreed before?I'm really not interested in seeing the libdrm/libdri mess repeated. Libraries have their uses when there's some very important external interface, but here it's actively harmful as it complicates and hardcodes APIs into ABIs that are clearly not finished yet.
Quoted 5 lines
Really, lets not be stupid here.
Thanks,
Ingo
The trace events format is a general interface that not only perf and trace-cmd use but also powertop and pytimechart, and may be others?
And given the breakage we had with powertop, for example, that broke because it was relying on an ad-hoc static layout of the trace event, or pytimechart that relies(ed?) on the event string output, I think that library is needed outside perf.
Quoted 24 lines · Frederic Weisbecker
Quoted 17 lines · Ingo Molnar
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation tooling - while previously you agreed that it should be unified. So why not do
tools/perf/lib/as you agreed before?I'm really not interested in seeing the libdrm/libdri mess repeated. Libraries have their uses when there's some very important external interface, but here it's actively harmful as it complicates and hardcodes APIs into ABIs that are clearly not finished yet.
Quoted 5 lines
Really, lets not be stupid here.
Thanks,
Ingo
Quoted 8 lines
The trace events format is a general interface that not only perf and trace-cmd use but also powertop and pytimechart, and may be others?
And given the breakage we had with powertop, for example, that broke because it was relying on an ad-hoc static layout of the trace event, or pytimechart that relies(ed?) on the event string output, I think that library is needed outside perf.
That is why i suggested libperf.so - this will handle the cases you mention, plus any future case - while still allow more flexible code sharing between libperf and the perf tools themselves.
Thanks,
Ingo
Quoted 31 lines · Ingo Molnar
Quoted 28 lines · Frederic Weisbecker
Quoted 17 lines · Ingo Molnar
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation tooling - while previously you agreed that it should be unified. So why not do
tools/perf/lib/as you agreed before?I'm really not interested in seeing the libdrm/libdri mess repeated. Libraries have their uses when there's some very important external interface, but here it's actively harmful as it complicates and hardcodes APIs into ABIs that are clearly not finished yet.
Quoted 5 lines
Really, lets not be stupid here.
Thanks,
Ingo
The trace events format is a general interface that not only perf and trace-cmd use but also powertop and pytimechart, and may be others?
Quoted 8 lines
Quoted 4 lines
And given the breakage we had with powertop, for example, that broke because it was relying on an ad-hoc static layout of the trace event, or pytimechart that relies(ed?) on the event string output, I think that library is needed outside perf.
That is why i suggested libperf.so - this will handle the cases you mention, plus any future case - while still allow more flexible code sharing between libperf and the perf tools themselves.
But what would you want inside libperf.o, further the trace event library?
A message that is not in the archive (sent off-list or not yet received): CAKYOsXw+Q+h2D++LxAoCUJ3tFVEhczBgDWNjwXzuJ0mNDav_Rw@mail.gmail.com
Quoted 12 lines · David Ahern
Quoted 8 lines · Frederic Weisbecker
Quoted 3 lines · Ingo Molnar
That is why i suggested libperf.so - this will handle the cases you mention, plus any future case - while still allow more flexible code sharing between libperf and the perf tools themselves.
But what would you want inside libperf.o, further the trace event library?
Quoted 4 lines
If the library is just for parsing trace events why not call it libtraceparse or libtrace? This isn't perf specific functionality.
David
This is what I don't understand yeah.
Quoted 2 lines · David Ahern
If the library is just for parsing trace events why not call it libtraceparse or libtrace? This isn't perf specific functionality.
Actually, I'm thinking libevents would probably be most appropriate. It has less to do with perf in general, and more about events. Even reading the events goes under this category.
-- Steve
Quoted 1 line
Quoted 8 lines · Ingo Molnar
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation
Ouch!
Ingo, I was trying to do as you said, but to do so would require a lot of restructuring of the perf code base. I started talking with Arnaldo, as he's doing a lot of the work in the tools/perf code, and he's the one that suggested that I do it this way. It made things a lot easier.
Seriously, I wasted Mon-Wed trying to see how it would work in tools/perf. I went through iteration after iteration, and each time I either rewrote the tools/perf/Makefile, or hacked apart the libparsevent code to be strictly perf specific, and not very useful for anything else.
It took me half of Thursday to get something working with this method. It made sense and was easy to do. I don't have much more time to spend on this. Red Hat does not pay me to do tracing/perf work. There's other things that I need to focus on, and there's other aspects of ftrace that needs to get done too (-mfentry for one).
Quoted 2 lines
tooling - while previously you agreed that it should be unified. So why not do
tools/perf/lib/as you agreed before?
Because Arnaldo and Frederic convinced me the tools/lib made more sense.
Quoted 5 lines
I'm really not interested in seeing the libdrm/libdri mess repeated. Libraries have their uses when there's some very important external interface, but here it's actively harmful as it complicates and hardcodes APIs into ABIs that are clearly not finished yet.
What API/ABI is being hardcoded here?
-- Steve
Quoted 5 lines · Steven Rostedt
Ingo, I was trying to do as you said, but to do so would require a lot of restructuring of the perf code base. I started talking with Arnaldo, as he's doing a lot of the work in the
tools/perfcode, and he's the one that suggested that I do it this way. It made things a lot easier.
Could you guys please talk some more and clear it up? There's absolutely no technical reason why tools/perf/lib/ (or tools/perf/libperf/) should be harder than tools/lib/.
Thanks,
Ingo
Quoted 11 lines · Ingo Molnar
Quoted 5 lines · Steven Rostedt
Ingo, I was trying to do as you said, but to do so would require a lot of restructuring of the perf code base. I started talking with Arnaldo, as he's doing a lot of the work in the
tools/perfcode, and he's the one that suggested that I do it this way. It made things a lot easier.Could you guys please talk some more and clear it up? There's absolutely no technical reason why
tools/perf/lib/(ortools/perf/libperf/) should be harder thantools/lib/.
The issue was trying to use the Makefile within perf for the building. There was issues with the warning flags and also the deps that are automatically made with libparsevent.
But you are correct, if I were to just move the pointers over to tools/perf/lib/events instead of tools/lib/events and had it be a separate entity in the build process, then it would not be any different between the two locations.
But there are two non-technical issues with that. Is it wise to have a different type of build process within the tools/perf directory. The libparsevents follows the Linux build system more than the git build system.
The other being, is the parse events a perf only thing? Maybe having a tools/lib would be nice even if it is. Because we can put things in tools/lib that will go as a separate package. perf could depend on tools/lib but there's no reason that tools/lib should depend on perf.
-- Steve
Quoted 17 lines · Steven Rostedt
Quoted 8 lines · Ingo Molnar
Quoted 3 lines · Steven Rostedt
By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
But we want to move tools together, not further apart. Every code activity i see from you is trying to tear apart instrumentation
Ouch!
Ingo, I was trying to do as you said, but to do so would require a lot of restructuring of the perf code base. I started talking with Arnaldo, as he's doing a lot of the work in the
tools/perfcode, and he's the one that suggested that I do it this way. It made things a lot easier.
Quoted 5 lines
Seriously, I wasted Mon-Wed trying to see how it would work in
tools/perf. I went through iteration after iteration, and each time I either rewrote thetools/perf/Makefile, or hacked apart the libparsevent code to be strictly perf specific, and not very useful for anything else.
Now you feel exactly how I felt when preparing the RAS daemon stuff :-)
I think we should first agree on the design of libperf or whatever other libraries and then start working towards it. Then we'd all know where we're going so coding it up would be almost a routine task. And then, other people who've done it for a couple of times already (hint: me) could help so Steve won't have to do it alone.
Thanks.
Signature · 2 lines
Regards/Gruss,
Boris.Quoted 6 lines · Steven Rostedt
Hi All,
I've spent the week working on getting libparsevent.a working with perf. After several rewrites, hacking in both perf and the trace-cmd code, and breaking both beyond repair, I finally got to a point that it just works.
Does this version allow use of the trace-cmd plugins with perf? Specifically, kvm tracing is not compatible with perf (perf barfs on the kvm_exit traces); I suspect the plugins would fix that - as well as have the pretty format for the exit reasons.
I want to try out the patch set, but will not have time until the week of the kvm forum/linuxcon.
David
Quoted 83 lines
The library was originally going to be called libperf.so, but after talking with Arnaldo, he wants the functionality of the libraries separated more, not combined all in one binary. As this code deals only with the parsing the event formats and creating a way to read the binary data from it, we both agreed that it is best to keep its original name that was in trace-cmd and call it libparsevent.so.
Note, because perf installs in the user's ~/bin and I did not want to make it a requirement to add ~/bin to
LD_LIBRARY_PATH, I kept the library as a .a that is linked directly into perf.In the beginning, I tried to work with the library code within the
tools/perfdirectory, and because of the CFLAGS of perf, it made compiling the library code very nasty (namely the -Wswitch-enum). I also talked with Arnaldo and Frederic about the placement of this code, and we all agreed thattools/lib/eventsis a good place to put it.By keeping the code separate from perf, made the transition from trace-cmd to tools much easier. I've wasted too many days trying to get other ways working, and I don't want to rewrite perf to do so.
Thus, this is what I ended up with.
This patch set just gets the libparsevent.a/so working with perf. New code would be required to get it packaged for distributions to ship as a library itself. Once it gets there, I'll work on getting this code to work with code like latencytrace.
Anyway, this is still in the RFC phase. Lets hear what people have to say.
(some of the patches are quite large as they either insert full files or remove them, and probably will not make LKML due to the size constraint.)
This patches can be viewed from:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
tip/perf/parse-eventsHead SHA1:
781d261ff8241243173cf996ceb068cb19bd5874Julia Lawall (1):
perf/events: Correct size given to memsetSteven Rostedt (6):
perf: Separate out trace-cmd parse-events from perf filestools/events: Add files to create libparsevent.a
perf: Build libparsevent.a
events: Updatetools/lib/eventsto work with perf
perf: Have perf use the new libparsevent.a library perf/events: Add flag to produce nsec outputTom Zanussi (1):
perf/events: Add flag/symbolformat_flags----
tools/lib/events/Makefile | 303 ++ tools/lib/events/event-parse.c | 4991 ++++++++++++++++++++ tools/lib/events/event-parse.h | 804 ++++ tools/lib/events/event-utils.h | 80 + tools/lib/events/parse-filter.c | 2262 +++++++++ tools/lib/events/parse-utils.c | 110 + tools/lib/events/trace-seq.c | 200 + tools/perf/Makefile | 17 +- tools/perf/builtin-kmem.c | 6 +- tools/perf/builtin-lock.c | 26 +- tools/perf/builtin-sched.c | 42 +- tools/perf/builtin-script.c | 2 +- .../util/scripting-engines/trace-event-python.c | 16 +- tools/perf/util/trace-event-info.c | 4 +- tools/perf/util/trace-event-parse.c | 3188 +------------ tools/perf/util/trace-event-read.c | 34 +- tools/perf/util/trace-event.h | 268 +- 17 files changed, 9070 insertions(+), 3283 deletions(-)--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Quoted 8 lines · David Ahern
Quoted 6 lines · Steven Rostedt
Hi All,
I've spent the week working on getting libparsevent.a working with perf. After several rewrites, hacking in both perf and the trace-cmd code, and breaking both beyond repair, I finally got to a point that it just works.
Quoted 8 lines
Does this version allow use of the trace-cmd plugins with perf? Specifically, kvm tracing is not compatible with perf (perf barfs on the
kvm_exittraces); I suspect the plugins would fix that - as well as have the pretty format for the exit reasons.I want to try out the patch set, but will not have time until the week of the kvm forum/linuxcon.
I posted this patch set as an RFC as I don't have time to waste on doing more work, and I knew it would cause some controversy.
That said, this patch set does not yet add the plugins, but it lays the ground work for adding plugins to perf in the next step. I probably could get plugins working with perf by next week. If we keep going in this direction, otherwise, probably not till next year.
-- Steve
Quoted 4 lines · Steven Rostedt
Note, because perf installs in the user's ~/bin and I did not want to make it a requirement to add ~/bin to
LD_LIBRARY_PATH, I kept the library as a .a that is linked directly into perf.
Note you can add an rpath to avoid having to modify LD_LIBRARY_PATH; rpath is just better for this kind of thing. As a general rule of thumb, if you're installing somewhere outside of the target system's /etc/ld.so.conf, add an rpath. And for this purpose ignore e.g. Fedora's broken tendency to put private libraries in /etc/ld.so.conf.d.