xref: /openbmc/linux/tools/perf/scripts/python/event_analyzing_sample.py (revision 597473720f4dc69749542bfcfed4a927a43d935e)
187b6a3adSFeng Tang# event_analyzing_sample.py: general event handler in python
2b2441318SGreg 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
18*c253c72eSTony Jonesfrom __future__ import print_function
19*c253c72eSTony Jones
200076d546SFeng Tangimport os
210076d546SFeng Tangimport sys
220076d546SFeng Tangimport math
230076d546SFeng Tangimport struct
240076d546SFeng Tangimport sqlite3
250076d546SFeng Tang
260076d546SFeng Tangsys.path.append(os.environ['PERF_EXEC_PATH'] + \
270076d546SFeng Tang        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
280076d546SFeng Tang
290076d546SFeng Tangfrom perf_trace_context import *
300076d546SFeng Tangfrom EventClass import *
310076d546SFeng Tang
320076d546SFeng Tang#
330076d546SFeng Tang# If the perf.data has a big number of samples, then the insert operation
340076d546SFeng Tang# will be very time consuming (about 10+ minutes for 10000 samples) if the
350076d546SFeng Tang# .db database is on disk. Move the .db file to RAM based FS to speedup
360076d546SFeng Tang# the handling, which will cut the time down to several seconds.
370076d546SFeng Tang#
380076d546SFeng Tangcon = sqlite3.connect("/dev/shm/perf.db")
390076d546SFeng Tangcon.isolation_level = None
400076d546SFeng Tang
410076d546SFeng Tangdef trace_begin():
42*c253c72eSTony Jones        print("In trace_begin:\n")
430076d546SFeng Tang
440076d546SFeng Tang        #
450076d546SFeng Tang        # Will create several tables at the start, pebs_ll is for PEBS data with
460076d546SFeng Tang        # load latency info, while gen_events is for general event.
470076d546SFeng Tang        #
480076d546SFeng Tang        con.execute("""
490076d546SFeng Tang                create table if not exists gen_events (
500076d546SFeng Tang                        name text,
510076d546SFeng Tang                        symbol text,
520076d546SFeng Tang                        comm text,
530076d546SFeng Tang                        dso text
540076d546SFeng Tang                );""")
550076d546SFeng Tang        con.execute("""
560076d546SFeng Tang                create table if not exists pebs_ll (
570076d546SFeng Tang                        name text,
580076d546SFeng Tang                        symbol text,
590076d546SFeng Tang                        comm text,
600076d546SFeng Tang                        dso text,
610076d546SFeng Tang                        flags integer,
620076d546SFeng Tang                        ip integer,
630076d546SFeng Tang                        status integer,
640076d546SFeng Tang                        dse integer,
650076d546SFeng Tang                        dla integer,
660076d546SFeng Tang                        lat integer
670076d546SFeng Tang                );""")
680076d546SFeng Tang
690076d546SFeng Tang#
700076d546SFeng Tang# Create and insert event object to a database so that user could
710076d546SFeng Tang# do more analysis with simple database commands.
720076d546SFeng Tang#
730076d546SFeng Tangdef process_event(param_dict):
740076d546SFeng Tang        event_attr = param_dict["attr"]
750076d546SFeng Tang        sample     = param_dict["sample"]
760076d546SFeng Tang        raw_buf    = param_dict["raw_buf"]
770076d546SFeng Tang        comm       = param_dict["comm"]
780076d546SFeng Tang        name       = param_dict["ev_name"]
790076d546SFeng Tang
800076d546SFeng Tang        # Symbol and dso info are not always resolved
81*c253c72eSTony Jones        if ("dso" in param_dict):
820076d546SFeng Tang                dso = param_dict["dso"]
830076d546SFeng Tang        else:
840076d546SFeng Tang                dso = "Unknown_dso"
850076d546SFeng Tang
86*c253c72eSTony Jones        if ("symbol" in param_dict):
870076d546SFeng Tang                symbol = param_dict["symbol"]
880076d546SFeng Tang        else:
890076d546SFeng Tang                symbol = "Unknown_symbol"
900076d546SFeng Tang
9187b6a3adSFeng Tang        # Create the event object and insert it to the right table in database
920076d546SFeng Tang        event = create_event(name, comm, dso, symbol, raw_buf)
930076d546SFeng Tang        insert_db(event)
940076d546SFeng Tang
950076d546SFeng Tangdef insert_db(event):
960076d546SFeng Tang        if event.ev_type == EVTYPE_GENERIC:
970076d546SFeng Tang                con.execute("insert into gen_events values(?, ?, ?, ?)",
980076d546SFeng Tang                                (event.name, event.symbol, event.comm, event.dso))
990076d546SFeng Tang        elif event.ev_type == EVTYPE_PEBS_LL:
1000076d546SFeng Tang                event.ip &= 0x7fffffffffffffff
1010076d546SFeng Tang                event.dla &= 0x7fffffffffffffff
1020076d546SFeng Tang                con.execute("insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
1030076d546SFeng Tang                        (event.name, event.symbol, event.comm, event.dso, event.flags,
1040076d546SFeng Tang                                event.ip, event.status, event.dse, event.dla, event.lat))
1050076d546SFeng Tang
1060076d546SFeng Tangdef trace_end():
107*c253c72eSTony Jones        print("In trace_end:\n")
1080076d546SFeng Tang        # We show the basic info for the 2 type of event classes
1090076d546SFeng Tang        show_general_events()
1100076d546SFeng Tang        show_pebs_ll()
1110076d546SFeng Tang        con.close()
1120076d546SFeng Tang
1130076d546SFeng Tang#
1140076d546SFeng Tang# As the event number may be very big, so we can't use linear way
11587b6a3adSFeng Tang# to show the histogram in real number, but use a log2 algorithm.
1160076d546SFeng Tang#
1170076d546SFeng Tang
1180076d546SFeng Tangdef num2sym(num):
1190076d546SFeng Tang        # Each number will have at least one '#'
1200076d546SFeng Tang        snum = '#' * (int)(math.log(num, 2) + 1)
1210076d546SFeng Tang        return snum
1220076d546SFeng Tang
1230076d546SFeng Tangdef show_general_events():
1240076d546SFeng Tang
1250076d546SFeng Tang        # Check the total record number in the table
1260076d546SFeng Tang        count = con.execute("select count(*) from gen_events")
1270076d546SFeng Tang        for t in count:
128*c253c72eSTony Jones                print("There is %d records in gen_events table" % t[0])
1290076d546SFeng Tang                if t[0] == 0:
1300076d546SFeng Tang                        return
1310076d546SFeng Tang
132*c253c72eSTony Jones        print("Statistics about the general events grouped by thread/symbol/dso: \n")
1330076d546SFeng Tang
1340076d546SFeng Tang         # Group by thread
1350076d546SFeng Tang        commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)")
136*c253c72eSTony Jones        print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42))
1370076d546SFeng Tang        for row in commq:
138*c253c72eSTony Jones             print("%16s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1390076d546SFeng Tang
1400076d546SFeng Tang        # Group by symbol
141*c253c72eSTony Jones        print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58))
1420076d546SFeng Tang        symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)")
1430076d546SFeng Tang        for row in symbolq:
144*c253c72eSTony Jones             print("%32s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1450076d546SFeng Tang
1460076d546SFeng Tang        # Group by dso
147*c253c72eSTony Jones        print("\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74))
1480076d546SFeng Tang        dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)")
1490076d546SFeng Tang        for row in dsoq:
150*c253c72eSTony Jones             print("%40s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1510076d546SFeng Tang
1520076d546SFeng Tang#
1530076d546SFeng Tang# This function just shows the basic info, and we could do more with the
1540076d546SFeng Tang# data in the tables, like checking the function parameters when some
1550076d546SFeng Tang# big latency events happen.
1560076d546SFeng Tang#
1570076d546SFeng Tangdef show_pebs_ll():
1580076d546SFeng Tang
1590076d546SFeng Tang        count = con.execute("select count(*) from pebs_ll")
1600076d546SFeng Tang        for t in count:
161*c253c72eSTony Jones                print("There is %d records in pebs_ll table" % t[0])
1620076d546SFeng Tang                if t[0] == 0:
1630076d546SFeng Tang                        return
1640076d546SFeng Tang
165*c253c72eSTony Jones        print("Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n")
1660076d546SFeng Tang
1670076d546SFeng Tang        # Group by thread
1680076d546SFeng Tang        commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)")
169*c253c72eSTony Jones        print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42))
1700076d546SFeng Tang        for row in commq:
171*c253c72eSTony Jones             print("%16s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1720076d546SFeng Tang
1730076d546SFeng Tang        # Group by symbol
174*c253c72eSTony Jones        print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58))
1750076d546SFeng Tang        symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)")
1760076d546SFeng Tang        for row in symbolq:
177*c253c72eSTony Jones             print("%32s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1780076d546SFeng Tang
1790076d546SFeng Tang        # Group by dse
1800076d546SFeng Tang        dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)")
181*c253c72eSTony Jones        print("\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58))
1820076d546SFeng Tang        for row in dseq:
183*c253c72eSTony Jones             print("%32s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1840076d546SFeng Tang
1850076d546SFeng Tang        # Group by latency
1860076d546SFeng Tang        latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat")
187*c253c72eSTony Jones        print("\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58))
1880076d546SFeng Tang        for row in latq:
189*c253c72eSTony Jones             print("%32s %8d     %s" % (row[0], row[1], num2sym(row[1])))
1900076d546SFeng Tang
1910076d546SFeng Tangdef trace_unhandled(event_name, context, event_fields_dict):
192*c253c72eSTony Jones        print (' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]))
193