187b6a3adSFeng Tang# event_analyzing_sample.py: general event handler in python 2*b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0 30076d546SFeng Tang# 487b6a3adSFeng Tang# Current perf report is already very powerful with the annotation integrated, 50076d546SFeng Tang# and this script is not trying to be as powerful as perf report, but 60076d546SFeng Tang# providing end user/developer a flexible way to analyze the events other 70076d546SFeng Tang# than trace points. 80076d546SFeng Tang# 90076d546SFeng Tang# The 2 database related functions in this script just show how to gather 100076d546SFeng Tang# the basic information, and users can modify and write their own functions 1187b6a3adSFeng Tang# according to their specific requirement. 120076d546SFeng Tang# 1387b6a3adSFeng Tang# The first function "show_general_events" just does a basic grouping for all 140076d546SFeng Tang# generic events with the help of sqlite, and the 2nd one "show_pebs_ll" is 150076d546SFeng Tang# for a x86 HW PMU event: PEBS with load latency data. 160076d546SFeng Tang# 170076d546SFeng Tang 180076d546SFeng Tangimport os 190076d546SFeng Tangimport sys 200076d546SFeng Tangimport math 210076d546SFeng Tangimport struct 220076d546SFeng Tangimport sqlite3 230076d546SFeng Tang 240076d546SFeng Tangsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 250076d546SFeng Tang '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 260076d546SFeng Tang 270076d546SFeng Tangfrom perf_trace_context import * 280076d546SFeng Tangfrom EventClass import * 290076d546SFeng Tang 300076d546SFeng Tang# 310076d546SFeng Tang# If the perf.data has a big number of samples, then the insert operation 320076d546SFeng Tang# will be very time consuming (about 10+ minutes for 10000 samples) if the 330076d546SFeng Tang# .db database is on disk. Move the .db file to RAM based FS to speedup 340076d546SFeng Tang# the handling, which will cut the time down to several seconds. 350076d546SFeng Tang# 360076d546SFeng Tangcon = sqlite3.connect("/dev/shm/perf.db") 370076d546SFeng Tangcon.isolation_level = None 380076d546SFeng Tang 390076d546SFeng Tangdef trace_begin(): 400076d546SFeng Tang print "In trace_begin:\n" 410076d546SFeng Tang 420076d546SFeng Tang # 430076d546SFeng Tang # Will create several tables at the start, pebs_ll is for PEBS data with 440076d546SFeng Tang # load latency info, while gen_events is for general event. 450076d546SFeng Tang # 460076d546SFeng Tang con.execute(""" 470076d546SFeng Tang create table if not exists gen_events ( 480076d546SFeng Tang name text, 490076d546SFeng Tang symbol text, 500076d546SFeng Tang comm text, 510076d546SFeng Tang dso text 520076d546SFeng Tang );""") 530076d546SFeng Tang con.execute(""" 540076d546SFeng Tang create table if not exists pebs_ll ( 550076d546SFeng Tang name text, 560076d546SFeng Tang symbol text, 570076d546SFeng Tang comm text, 580076d546SFeng Tang dso text, 590076d546SFeng Tang flags integer, 600076d546SFeng Tang ip integer, 610076d546SFeng Tang status integer, 620076d546SFeng Tang dse integer, 630076d546SFeng Tang dla integer, 640076d546SFeng Tang lat integer 650076d546SFeng Tang );""") 660076d546SFeng Tang 670076d546SFeng Tang# 680076d546SFeng Tang# Create and insert event object to a database so that user could 690076d546SFeng Tang# do more analysis with simple database commands. 700076d546SFeng Tang# 710076d546SFeng Tangdef process_event(param_dict): 720076d546SFeng Tang event_attr = param_dict["attr"] 730076d546SFeng Tang sample = param_dict["sample"] 740076d546SFeng Tang raw_buf = param_dict["raw_buf"] 750076d546SFeng Tang comm = param_dict["comm"] 760076d546SFeng Tang name = param_dict["ev_name"] 770076d546SFeng Tang 780076d546SFeng Tang # Symbol and dso info are not always resolved 790076d546SFeng Tang if (param_dict.has_key("dso")): 800076d546SFeng Tang dso = param_dict["dso"] 810076d546SFeng Tang else: 820076d546SFeng Tang dso = "Unknown_dso" 830076d546SFeng Tang 840076d546SFeng Tang if (param_dict.has_key("symbol")): 850076d546SFeng Tang symbol = param_dict["symbol"] 860076d546SFeng Tang else: 870076d546SFeng Tang symbol = "Unknown_symbol" 880076d546SFeng Tang 8987b6a3adSFeng Tang # Create the event object and insert it to the right table in database 900076d546SFeng Tang event = create_event(name, comm, dso, symbol, raw_buf) 910076d546SFeng Tang insert_db(event) 920076d546SFeng Tang 930076d546SFeng Tangdef insert_db(event): 940076d546SFeng Tang if event.ev_type == EVTYPE_GENERIC: 950076d546SFeng Tang con.execute("insert into gen_events values(?, ?, ?, ?)", 960076d546SFeng Tang (event.name, event.symbol, event.comm, event.dso)) 970076d546SFeng Tang elif event.ev_type == EVTYPE_PEBS_LL: 980076d546SFeng Tang event.ip &= 0x7fffffffffffffff 990076d546SFeng Tang event.dla &= 0x7fffffffffffffff 1000076d546SFeng Tang con.execute("insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1010076d546SFeng Tang (event.name, event.symbol, event.comm, event.dso, event.flags, 1020076d546SFeng Tang event.ip, event.status, event.dse, event.dla, event.lat)) 1030076d546SFeng Tang 1040076d546SFeng Tangdef trace_end(): 1050076d546SFeng Tang print "In trace_end:\n" 1060076d546SFeng Tang # We show the basic info for the 2 type of event classes 1070076d546SFeng Tang show_general_events() 1080076d546SFeng Tang show_pebs_ll() 1090076d546SFeng Tang con.close() 1100076d546SFeng Tang 1110076d546SFeng Tang# 1120076d546SFeng Tang# As the event number may be very big, so we can't use linear way 11387b6a3adSFeng Tang# to show the histogram in real number, but use a log2 algorithm. 1140076d546SFeng Tang# 1150076d546SFeng Tang 1160076d546SFeng Tangdef num2sym(num): 1170076d546SFeng Tang # Each number will have at least one '#' 1180076d546SFeng Tang snum = '#' * (int)(math.log(num, 2) + 1) 1190076d546SFeng Tang return snum 1200076d546SFeng Tang 1210076d546SFeng Tangdef show_general_events(): 1220076d546SFeng Tang 1230076d546SFeng Tang # Check the total record number in the table 1240076d546SFeng Tang count = con.execute("select count(*) from gen_events") 1250076d546SFeng Tang for t in count: 1260076d546SFeng Tang print "There is %d records in gen_events table" % t[0] 1270076d546SFeng Tang if t[0] == 0: 1280076d546SFeng Tang return 1290076d546SFeng Tang 1300076d546SFeng Tang print "Statistics about the general events grouped by thread/symbol/dso: \n" 1310076d546SFeng Tang 1320076d546SFeng Tang # Group by thread 1330076d546SFeng Tang commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)") 13487b6a3adSFeng Tang print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42) 1350076d546SFeng Tang for row in commq: 1360076d546SFeng Tang print "%16s %8d %s" % (row[0], row[1], num2sym(row[1])) 1370076d546SFeng Tang 1380076d546SFeng Tang # Group by symbol 13987b6a3adSFeng Tang print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58) 1400076d546SFeng Tang symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)") 1410076d546SFeng Tang for row in symbolq: 1420076d546SFeng Tang print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) 1430076d546SFeng Tang 1440076d546SFeng Tang # Group by dso 14587b6a3adSFeng Tang print "\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74) 1460076d546SFeng Tang dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)") 1470076d546SFeng Tang for row in dsoq: 1480076d546SFeng Tang print "%40s %8d %s" % (row[0], row[1], num2sym(row[1])) 1490076d546SFeng Tang 1500076d546SFeng Tang# 1510076d546SFeng Tang# This function just shows the basic info, and we could do more with the 1520076d546SFeng Tang# data in the tables, like checking the function parameters when some 1530076d546SFeng Tang# big latency events happen. 1540076d546SFeng Tang# 1550076d546SFeng Tangdef show_pebs_ll(): 1560076d546SFeng Tang 1570076d546SFeng Tang count = con.execute("select count(*) from pebs_ll") 1580076d546SFeng Tang for t in count: 1590076d546SFeng Tang print "There is %d records in pebs_ll table" % t[0] 1600076d546SFeng Tang if t[0] == 0: 1610076d546SFeng Tang return 1620076d546SFeng Tang 1630076d546SFeng Tang print "Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n" 1640076d546SFeng Tang 1650076d546SFeng Tang # Group by thread 1660076d546SFeng Tang commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)") 16787b6a3adSFeng Tang print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42) 1680076d546SFeng Tang for row in commq: 1690076d546SFeng Tang print "%16s %8d %s" % (row[0], row[1], num2sym(row[1])) 1700076d546SFeng Tang 1710076d546SFeng Tang # Group by symbol 17287b6a3adSFeng Tang print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58) 1730076d546SFeng Tang symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)") 1740076d546SFeng Tang for row in symbolq: 1750076d546SFeng Tang print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) 1760076d546SFeng Tang 1770076d546SFeng Tang # Group by dse 1780076d546SFeng Tang dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)") 17987b6a3adSFeng Tang print "\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58) 1800076d546SFeng Tang for row in dseq: 1810076d546SFeng Tang print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) 1820076d546SFeng Tang 1830076d546SFeng Tang # Group by latency 1840076d546SFeng Tang latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat") 18587b6a3adSFeng Tang print "\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58) 1860076d546SFeng Tang for row in latq: 1870076d546SFeng Tang print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) 1880076d546SFeng Tang 1890076d546SFeng Tangdef trace_unhandled(event_name, context, event_fields_dict): 1900076d546SFeng Tang print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) 191