1*4882a593Smuzhiyun# event_analyzing_sample.py: general event handler in python 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Current perf report is already very powerful with the annotation integrated, 5*4882a593Smuzhiyun# and this script is not trying to be as powerful as perf report, but 6*4882a593Smuzhiyun# providing end user/developer a flexible way to analyze the events other 7*4882a593Smuzhiyun# than trace points. 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# The 2 database related functions in this script just show how to gather 10*4882a593Smuzhiyun# the basic information, and users can modify and write their own functions 11*4882a593Smuzhiyun# according to their specific requirement. 12*4882a593Smuzhiyun# 13*4882a593Smuzhiyun# The first function "show_general_events" just does a basic grouping for all 14*4882a593Smuzhiyun# generic events with the help of sqlite, and the 2nd one "show_pebs_ll" is 15*4882a593Smuzhiyun# for a x86 HW PMU event: PEBS with load latency data. 16*4882a593Smuzhiyun# 17*4882a593Smuzhiyun 18*4882a593Smuzhiyunfrom __future__ import print_function 19*4882a593Smuzhiyun 20*4882a593Smuzhiyunimport os 21*4882a593Smuzhiyunimport sys 22*4882a593Smuzhiyunimport math 23*4882a593Smuzhiyunimport struct 24*4882a593Smuzhiyunimport sqlite3 25*4882a593Smuzhiyun 26*4882a593Smuzhiyunsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 27*4882a593Smuzhiyun '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 28*4882a593Smuzhiyun 29*4882a593Smuzhiyunfrom perf_trace_context import * 30*4882a593Smuzhiyunfrom EventClass import * 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun# 33*4882a593Smuzhiyun# If the perf.data has a big number of samples, then the insert operation 34*4882a593Smuzhiyun# will be very time consuming (about 10+ minutes for 10000 samples) if the 35*4882a593Smuzhiyun# .db database is on disk. Move the .db file to RAM based FS to speedup 36*4882a593Smuzhiyun# the handling, which will cut the time down to several seconds. 37*4882a593Smuzhiyun# 38*4882a593Smuzhiyuncon = sqlite3.connect("/dev/shm/perf.db") 39*4882a593Smuzhiyuncon.isolation_level = None 40*4882a593Smuzhiyun 41*4882a593Smuzhiyundef trace_begin(): 42*4882a593Smuzhiyun print("In trace_begin:\n") 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun # 45*4882a593Smuzhiyun # Will create several tables at the start, pebs_ll is for PEBS data with 46*4882a593Smuzhiyun # load latency info, while gen_events is for general event. 47*4882a593Smuzhiyun # 48*4882a593Smuzhiyun con.execute(""" 49*4882a593Smuzhiyun create table if not exists gen_events ( 50*4882a593Smuzhiyun name text, 51*4882a593Smuzhiyun symbol text, 52*4882a593Smuzhiyun comm text, 53*4882a593Smuzhiyun dso text 54*4882a593Smuzhiyun );""") 55*4882a593Smuzhiyun con.execute(""" 56*4882a593Smuzhiyun create table if not exists pebs_ll ( 57*4882a593Smuzhiyun name text, 58*4882a593Smuzhiyun symbol text, 59*4882a593Smuzhiyun comm text, 60*4882a593Smuzhiyun dso text, 61*4882a593Smuzhiyun flags integer, 62*4882a593Smuzhiyun ip integer, 63*4882a593Smuzhiyun status integer, 64*4882a593Smuzhiyun dse integer, 65*4882a593Smuzhiyun dla integer, 66*4882a593Smuzhiyun lat integer 67*4882a593Smuzhiyun );""") 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun# 70*4882a593Smuzhiyun# Create and insert event object to a database so that user could 71*4882a593Smuzhiyun# do more analysis with simple database commands. 72*4882a593Smuzhiyun# 73*4882a593Smuzhiyundef process_event(param_dict): 74*4882a593Smuzhiyun event_attr = param_dict["attr"] 75*4882a593Smuzhiyun sample = param_dict["sample"] 76*4882a593Smuzhiyun raw_buf = param_dict["raw_buf"] 77*4882a593Smuzhiyun comm = param_dict["comm"] 78*4882a593Smuzhiyun name = param_dict["ev_name"] 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun # Symbol and dso info are not always resolved 81*4882a593Smuzhiyun if ("dso" in param_dict): 82*4882a593Smuzhiyun dso = param_dict["dso"] 83*4882a593Smuzhiyun else: 84*4882a593Smuzhiyun dso = "Unknown_dso" 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun if ("symbol" in param_dict): 87*4882a593Smuzhiyun symbol = param_dict["symbol"] 88*4882a593Smuzhiyun else: 89*4882a593Smuzhiyun symbol = "Unknown_symbol" 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun # Create the event object and insert it to the right table in database 92*4882a593Smuzhiyun event = create_event(name, comm, dso, symbol, raw_buf) 93*4882a593Smuzhiyun insert_db(event) 94*4882a593Smuzhiyun 95*4882a593Smuzhiyundef insert_db(event): 96*4882a593Smuzhiyun if event.ev_type == EVTYPE_GENERIC: 97*4882a593Smuzhiyun con.execute("insert into gen_events values(?, ?, ?, ?)", 98*4882a593Smuzhiyun (event.name, event.symbol, event.comm, event.dso)) 99*4882a593Smuzhiyun elif event.ev_type == EVTYPE_PEBS_LL: 100*4882a593Smuzhiyun event.ip &= 0x7fffffffffffffff 101*4882a593Smuzhiyun event.dla &= 0x7fffffffffffffff 102*4882a593Smuzhiyun con.execute("insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 103*4882a593Smuzhiyun (event.name, event.symbol, event.comm, event.dso, event.flags, 104*4882a593Smuzhiyun event.ip, event.status, event.dse, event.dla, event.lat)) 105*4882a593Smuzhiyun 106*4882a593Smuzhiyundef trace_end(): 107*4882a593Smuzhiyun print("In trace_end:\n") 108*4882a593Smuzhiyun # We show the basic info for the 2 type of event classes 109*4882a593Smuzhiyun show_general_events() 110*4882a593Smuzhiyun show_pebs_ll() 111*4882a593Smuzhiyun con.close() 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun# 114*4882a593Smuzhiyun# As the event number may be very big, so we can't use linear way 115*4882a593Smuzhiyun# to show the histogram in real number, but use a log2 algorithm. 116*4882a593Smuzhiyun# 117*4882a593Smuzhiyun 118*4882a593Smuzhiyundef num2sym(num): 119*4882a593Smuzhiyun # Each number will have at least one '#' 120*4882a593Smuzhiyun snum = '#' * (int)(math.log(num, 2) + 1) 121*4882a593Smuzhiyun return snum 122*4882a593Smuzhiyun 123*4882a593Smuzhiyundef show_general_events(): 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun # Check the total record number in the table 126*4882a593Smuzhiyun count = con.execute("select count(*) from gen_events") 127*4882a593Smuzhiyun for t in count: 128*4882a593Smuzhiyun print("There is %d records in gen_events table" % t[0]) 129*4882a593Smuzhiyun if t[0] == 0: 130*4882a593Smuzhiyun return 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun print("Statistics about the general events grouped by thread/symbol/dso: \n") 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun # Group by thread 135*4882a593Smuzhiyun commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)") 136*4882a593Smuzhiyun print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)) 137*4882a593Smuzhiyun for row in commq: 138*4882a593Smuzhiyun print("%16s %8d %s" % (row[0], row[1], num2sym(row[1]))) 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun # Group by symbol 141*4882a593Smuzhiyun print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)) 142*4882a593Smuzhiyun symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)") 143*4882a593Smuzhiyun for row in symbolq: 144*4882a593Smuzhiyun print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun # Group by dso 147*4882a593Smuzhiyun print("\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74)) 148*4882a593Smuzhiyun dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)") 149*4882a593Smuzhiyun for row in dsoq: 150*4882a593Smuzhiyun print("%40s %8d %s" % (row[0], row[1], num2sym(row[1]))) 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun# 153*4882a593Smuzhiyun# This function just shows the basic info, and we could do more with the 154*4882a593Smuzhiyun# data in the tables, like checking the function parameters when some 155*4882a593Smuzhiyun# big latency events happen. 156*4882a593Smuzhiyun# 157*4882a593Smuzhiyundef show_pebs_ll(): 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun count = con.execute("select count(*) from pebs_ll") 160*4882a593Smuzhiyun for t in count: 161*4882a593Smuzhiyun print("There is %d records in pebs_ll table" % t[0]) 162*4882a593Smuzhiyun if t[0] == 0: 163*4882a593Smuzhiyun return 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun print("Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n") 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun # Group by thread 168*4882a593Smuzhiyun commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)") 169*4882a593Smuzhiyun print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)) 170*4882a593Smuzhiyun for row in commq: 171*4882a593Smuzhiyun print("%16s %8d %s" % (row[0], row[1], num2sym(row[1]))) 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun # Group by symbol 174*4882a593Smuzhiyun print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)) 175*4882a593Smuzhiyun symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)") 176*4882a593Smuzhiyun for row in symbolq: 177*4882a593Smuzhiyun print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun # Group by dse 180*4882a593Smuzhiyun dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)") 181*4882a593Smuzhiyun print("\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58)) 182*4882a593Smuzhiyun for row in dseq: 183*4882a593Smuzhiyun print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun # Group by latency 186*4882a593Smuzhiyun latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat") 187*4882a593Smuzhiyun print("\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58)) 188*4882a593Smuzhiyun for row in latq: 189*4882a593Smuzhiyun print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) 190*4882a593Smuzhiyun 191*4882a593Smuzhiyundef trace_unhandled(event_name, context, event_fields_dict): 192*4882a593Smuzhiyun print (' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])) 193