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