xref: /OK3568_Linux_fs/kernel/tools/perf/scripts/python/event_analyzing_sample.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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