2012-08-09 13:46:13 +08:00
# event_analyzing_sample.py: general event handler in python
2012-08-08 17:57:55 +08:00
#
2012-08-09 13:46:13 +08:00
# Current perf report is already very powerful with the annotation integrated,
2012-08-08 17:57:55 +08:00
# and this script is not trying to be as powerful as perf report, but
# providing end user/developer a flexible way to analyze the events other
# than trace points.
#
# The 2 database related functions in this script just show how to gather
# the basic information, and users can modify and write their own functions
2012-08-09 13:46:13 +08:00
# according to their specific requirement.
2012-08-08 17:57:55 +08:00
#
2012-08-09 13:46:13 +08:00
# The first function "show_general_events" just does a basic grouping for all
2012-08-08 17:57:55 +08:00
# generic events with the help of sqlite, and the 2nd one "show_pebs_ll" is
# for a x86 HW PMU event: PEBS with load latency data.
#
import os
import sys
import math
import struct
import sqlite3
sys . path . append ( os . environ [ ' PERF_EXEC_PATH ' ] + \
' /scripts/python/Perf-Trace-Util/lib/Perf/Trace ' )
from perf_trace_context import *
from EventClass import *
#
# If the perf.data has a big number of samples, then the insert operation
# will be very time consuming (about 10+ minutes for 10000 samples) if the
# .db database is on disk. Move the .db file to RAM based FS to speedup
# the handling, which will cut the time down to several seconds.
#
con = sqlite3 . connect ( " /dev/shm/perf.db " )
con . isolation_level = None
def trace_begin ( ) :
print " In trace_begin: \n "
#
# Will create several tables at the start, pebs_ll is for PEBS data with
# load latency info, while gen_events is for general event.
#
con . execute ( """
create table if not exists gen_events (
name text ,
symbol text ,
comm text ,
dso text
) ; """ )
con . execute ( """
create table if not exists pebs_ll (
name text ,
symbol text ,
comm text ,
dso text ,
flags integer ,
ip integer ,
status integer ,
dse integer ,
dla integer ,
lat integer
) ; """ )
#
# Create and insert event object to a database so that user could
# do more analysis with simple database commands.
#
def process_event ( param_dict ) :
event_attr = param_dict [ " attr " ]
sample = param_dict [ " sample " ]
raw_buf = param_dict [ " raw_buf " ]
comm = param_dict [ " comm " ]
name = param_dict [ " ev_name " ]
# Symbol and dso info are not always resolved
if ( param_dict . has_key ( " dso " ) ) :
dso = param_dict [ " dso " ]
else :
dso = " Unknown_dso "
if ( param_dict . has_key ( " symbol " ) ) :
symbol = param_dict [ " symbol " ]
else :
symbol = " Unknown_symbol "
2012-08-09 13:46:13 +08:00
# Create the event object and insert it to the right table in database
2012-08-08 17:57:55 +08:00
event = create_event ( name , comm , dso , symbol , raw_buf )
insert_db ( event )
def insert_db ( event ) :
if event . ev_type == EVTYPE_GENERIC :
con . execute ( " insert into gen_events values(?, ?, ?, ?) " ,
( event . name , event . symbol , event . comm , event . dso ) )
elif event . ev_type == EVTYPE_PEBS_LL :
event . ip & = 0x7fffffffffffffff
event . dla & = 0x7fffffffffffffff
con . execute ( " insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " ,
( event . name , event . symbol , event . comm , event . dso , event . flags ,
event . ip , event . status , event . dse , event . dla , event . lat ) )
def trace_end ( ) :
print " In trace_end: \n "
# We show the basic info for the 2 type of event classes
show_general_events ( )
show_pebs_ll ( )
con . close ( )
#
# As the event number may be very big, so we can't use linear way
2012-08-09 13:46:13 +08:00
# to show the histogram in real number, but use a log2 algorithm.
2012-08-08 17:57:55 +08:00
#
def num2sym ( num ) :
# Each number will have at least one '#'
snum = ' # ' * ( int ) ( math . log ( num , 2 ) + 1 )
return snum
def show_general_events ( ) :
# Check the total record number in the table
count = con . execute ( " select count(*) from gen_events " )
for t in count :
print " There is %d records in gen_events table " % t [ 0 ]
if t [ 0 ] == 0 :
return
print " Statistics about the general events grouped by thread/symbol/dso: \n "
# Group by thread
commq = con . execute ( " select comm, count(comm) from gen_events group by comm order by -count(comm) " )
2012-08-09 13:46:13 +08:00
print " \n %16s %8s %16s \n %s " % ( " comm " , " number " , " histogram " , " = " * 42 )
2012-08-08 17:57:55 +08:00
for row in commq :
print " %16s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
# Group by symbol
2012-08-09 13:46:13 +08:00
print " \n %32s %8s %16s \n %s " % ( " symbol " , " number " , " histogram " , " = " * 58 )
2012-08-08 17:57:55 +08:00
symbolq = con . execute ( " select symbol, count(symbol) from gen_events group by symbol order by -count(symbol) " )
for row in symbolq :
print " %32s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
# Group by dso
2012-08-09 13:46:13 +08:00
print " \n %40s %8s %16s \n %s " % ( " dso " , " number " , " histogram " , " = " * 74 )
2012-08-08 17:57:55 +08:00
dsoq = con . execute ( " select dso, count(dso) from gen_events group by dso order by -count(dso) " )
for row in dsoq :
print " %40s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
#
# This function just shows the basic info, and we could do more with the
# data in the tables, like checking the function parameters when some
# big latency events happen.
#
def show_pebs_ll ( ) :
count = con . execute ( " select count(*) from pebs_ll " )
for t in count :
print " There is %d records in pebs_ll table " % t [ 0 ]
if t [ 0 ] == 0 :
return
print " Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n "
# Group by thread
commq = con . execute ( " select comm, count(comm) from pebs_ll group by comm order by -count(comm) " )
2012-08-09 13:46:13 +08:00
print " \n %16s %8s %16s \n %s " % ( " comm " , " number " , " histogram " , " = " * 42 )
2012-08-08 17:57:55 +08:00
for row in commq :
print " %16s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
# Group by symbol
2012-08-09 13:46:13 +08:00
print " \n %32s %8s %16s \n %s " % ( " symbol " , " number " , " histogram " , " = " * 58 )
2012-08-08 17:57:55 +08:00
symbolq = con . execute ( " select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol) " )
for row in symbolq :
print " %32s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
# Group by dse
dseq = con . execute ( " select dse, count(dse) from pebs_ll group by dse order by -count(dse) " )
2012-08-09 13:46:13 +08:00
print " \n %32s %8s %16s \n %s " % ( " dse " , " number " , " histogram " , " = " * 58 )
2012-08-08 17:57:55 +08:00
for row in dseq :
print " %32s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
# Group by latency
latq = con . execute ( " select lat, count(lat) from pebs_ll group by lat order by lat " )
2012-08-09 13:46:13 +08:00
print " \n %32s %8s %16s \n %s " % ( " latency " , " number " , " histogram " , " = " * 58 )
2012-08-08 17:57:55 +08:00
for row in latq :
print " %32s %8d %s " % ( row [ 0 ] , row [ 1 ] , num2sym ( row [ 1 ] ) )
def trace_unhandled ( event_name , context , event_fields_dict ) :
print ' ' . join ( [ ' %s = %s ' % ( k , str ( v ) ) for k , v in sorted ( event_fields_dict . items ( ) ) ] )