2012-04-06 02:47:56 +04:00
/*
* Copyright ( C ) 2009 , Steven Rostedt < srostedt @ redhat . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License ( not later ! )
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <errno.h>
2009-08-28 05:09:58 +04:00
# include "../perf.h"
2009-08-17 18:18:07 +04:00
# include "util.h"
# include "trace-event.h"
2017-04-17 22:10:49 +03:00
# include "sane_ctype.h"
2012-04-06 02:47:56 +04:00
static int get_common_field ( struct scripting_context * context ,
int * offset , int * size , const char * type )
2010-01-27 11:27:54 +03:00
{
2012-06-27 20:08:42 +04:00
struct pevent * pevent = context - > pevent ;
2012-04-06 02:47:56 +04:00
struct event_format * event ;
struct format_field * field ;
if ( ! * size ) {
if ( ! pevent - > events )
return 0 ;
event = pevent - > events [ 0 ] ;
field = pevent_find_common_field ( event , type ) ;
if ( ! field )
return 0 ;
* offset = field - > offset ;
* size = field - > size ;
}
return pevent_read_number ( pevent , context - > event_data + * offset , * size ) ;
2010-01-27 11:27:54 +03:00
}
int common_lock_depth ( struct scripting_context * context )
{
2012-04-06 02:47:56 +04:00
static int offset ;
static int size ;
int ret ;
ret = get_common_field ( context , & size , & offset ,
" common_lock_depth " ) ;
if ( ret < 0 )
return - 1 ;
return ret ;
}
int common_flags ( struct scripting_context * context )
{
static int offset ;
static int size ;
int ret ;
ret = get_common_field ( context , & size , & offset ,
" common_flags " ) ;
if ( ret < 0 )
return - 1 ;
return ret ;
}
int common_pc ( struct scripting_context * context )
{
static int offset ;
static int size ;
int ret ;
ret = get_common_field ( context , & size , & offset ,
" common_preempt_count " ) ;
if ( ret < 0 )
return - 1 ;
return ret ;
}
unsigned long long
raw_field_value ( struct event_format * event , const char * name , void * data )
{
struct format_field * field ;
unsigned long long val ;
field = pevent_find_any_field ( event , name ) ;
if ( ! field )
return 0ULL ;
pevent_read_number_field ( field , data , & val ) ;
return val ;
}
2012-08-08 06:50:21 +04:00
unsigned long long read_size ( struct event_format * event , void * ptr , int size )
2012-04-06 02:47:56 +04:00
{
2012-08-08 06:50:21 +04:00
return pevent_read_number ( event - > pevent , ptr , size ) ;
2012-04-06 02:47:56 +04:00
}
2015-02-03 18:46:58 +03:00
void event_format__fprintf ( struct event_format * event ,
int cpu , void * data , int size , FILE * fp )
2012-04-06 02:47:56 +04:00
{
2012-04-06 02:48:06 +04:00
struct pevent_record record ;
2012-04-06 02:47:56 +04:00
struct trace_seq s ;
memset ( & record , 0 , sizeof ( record ) ) ;
record . cpu = cpu ;
record . size = size ;
record . data = data ;
trace_seq_init ( & s ) ;
2012-06-14 22:36:17 +04:00
pevent_event_info ( & s , event , & record ) ;
2015-02-03 18:46:58 +03:00
trace_seq_do_fprintf ( & s , fp ) ;
2014-02-03 01:38:49 +04:00
trace_seq_destroy ( & s ) ;
2012-04-06 02:47:56 +04:00
}
2015-02-03 18:46:58 +03:00
void event_format__print ( struct event_format * event ,
int cpu , void * data , int size )
{
return event_format__fprintf ( event , cpu , data , size , stdout ) ;
}
2012-06-27 20:08:42 +04:00
void parse_ftrace_printk ( struct pevent * pevent ,
2012-09-11 02:15:03 +04:00
char * file , unsigned int size __maybe_unused )
2012-04-06 02:47:56 +04:00
{
unsigned long long addr ;
char * printk ;
char * line ;
char * next = NULL ;
char * addr_str ;
2015-05-26 17:41:37 +03:00
char * fmt = NULL ;
2012-04-06 02:47:56 +04:00
line = strtok_r ( file , " \n " , & next ) ;
while ( line ) {
addr_str = strtok_r ( line , " : " , & fmt ) ;
if ( ! addr_str ) {
warning ( " printk format with empty entry " ) ;
break ;
}
addr = strtoull ( addr_str , NULL , 16 ) ;
/* fmt still has a space, skip it */
printk = strdup ( fmt + 1 ) ;
line = strtok_r ( NULL , " \n " , & next ) ;
pevent_register_print_string ( pevent , printk , addr ) ;
}
}
2013-04-11 12:25:04 +04:00
void parse_saved_cmdline ( struct pevent * pevent ,
char * file , unsigned int size __maybe_unused )
{
char * comm ;
char * line ;
char * next = NULL ;
int pid ;
line = strtok_r ( file , " \n " , & next ) ;
while ( line ) {
sscanf ( line , " %d %ms " , & pid , & comm ) ;
pevent_register_comm ( pevent , comm , pid ) ;
free ( comm ) ;
line = strtok_r ( NULL , " \n " , & next ) ;
}
}
2012-06-27 20:08:42 +04:00
int parse_ftrace_file ( struct pevent * pevent , char * buf , unsigned long size )
2012-04-06 02:47:56 +04:00
{
return pevent_parse_event ( pevent , buf , size , " ftrace " ) ;
}
2012-06-27 20:08:42 +04:00
int parse_event_file ( struct pevent * pevent ,
char * buf , unsigned long size , char * sys )
2012-04-06 02:47:56 +04:00
{
return pevent_parse_event ( pevent , buf , size , sys ) ;
}
2012-06-27 20:08:42 +04:00
struct event_format * trace_find_next_event ( struct pevent * pevent ,
struct event_format * event )
2012-04-06 02:47:56 +04:00
{
static int idx ;
2012-08-14 05:57:03 +04:00
if ( ! pevent | | ! pevent - > events )
2012-04-06 02:47:56 +04:00
return NULL ;
if ( ! event ) {
idx = 0 ;
return pevent - > events [ 0 ] ;
}
if ( idx < pevent - > nr_events & & event = = pevent - > events [ idx ] ) {
idx + + ;
if ( idx = = pevent - > nr_events )
return NULL ;
return pevent - > events [ idx ] ;
}
for ( idx = 1 ; idx < pevent - > nr_events ; idx + + ) {
if ( event = = pevent - > events [ idx - 1 ] )
return pevent - > events [ idx ] ;
}
return NULL ;
}
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 } ,
2015-11-10 16:56:14 +03:00
{ " IRQ_POLL_SOFTIRQ " , 5 } ,
2012-04-06 02:47:56 +04:00
{ " 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 ;
2010-01-27 11:27:54 +03:00
}