xref: /linux/tools/perf/scripts/python/export-to-sqlite.py (revision ff61f0791ce969d2db6c9f3b71d74ceec0a2e958)
1 # export-to-sqlite.py: export perf data to a sqlite3 database
2 # Copyright (c) 2017, Intel Corporation.
3 #
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms and conditions of the GNU General Public License,
6 # version 2, as published by the Free Software Foundation.
7 #
8 # This program is distributed in the hope it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11 # more details.
12 
13 from __future__ import print_function
14 
15 import os
16 import sys
17 import struct
18 import datetime
19 
20 # To use this script you will need to have installed package python-pyside which
21 # provides LGPL-licensed Python bindings for Qt.  You will also need the package
22 # libqt4-sql-sqlite for Qt sqlite3 support.
23 #
24 # Examples of installing pyside:
25 #
26 # ubuntu:
27 #
28 #	$ sudo apt-get install python-pyside.qtsql libqt4-sql-psql
29 #
30 #	Alternately, to use Python3 and/or pyside 2, one of the following:
31 #
32 #		$ sudo apt-get install python3-pyside.qtsql libqt4-sql-psql
33 #		$ sudo apt-get install python-pyside2.qtsql libqt5sql5-psql
34 #		$ sudo apt-get install python3-pyside2.qtsql libqt5sql5-psql
35 # fedora:
36 #
37 #	$ sudo yum install python-pyside
38 #
39 #	Alternately, to use Python3 and/or pyside 2, one of the following:
40 #		$ sudo yum install python3-pyside
41 #		$ pip install --user PySide2
42 #		$ pip3 install --user PySide2
43 #
44 # An example of using this script with Intel PT:
45 #
46 #	$ perf record -e intel_pt//u ls
47 #	$ perf script -s ~/libexec/perf-core/scripts/python/export-to-sqlite.py pt_example branches calls
48 #	2017-07-31 14:26:07.326913 Creating database...
49 #	2017-07-31 14:26:07.538097 Writing records...
50 #	2017-07-31 14:26:09.889292 Adding indexes
51 #	2017-07-31 14:26:09.958746 Done
52 #
53 # To browse the database, sqlite3 can be used e.g.
54 #
55 #	$ sqlite3 pt_example
56 #	sqlite> .header on
57 #	sqlite> select * from samples_view where id < 10;
58 #	sqlite> .mode column
59 #	sqlite> select * from samples_view where id < 10;
60 #	sqlite> .tables
61 #	sqlite> .schema samples_view
62 #	sqlite> .quit
63 #
64 # An example of using the database is provided by the script
65 # exported-sql-viewer.py.  Refer to that script for details.
66 #
67 # The database structure is practically the same as created by the script
68 # export-to-postgresql.py. Refer to that script for details.  A notable
69 # difference is  the 'transaction' column of the 'samples' table which is
70 # renamed 'transaction_' in sqlite because 'transaction' is a reserved word.
71 
72 pyside_version_1 = True
73 if not "pyside-version-1" in sys.argv:
74 	try:
75 		from PySide2.QtSql import *
76 		pyside_version_1 = False
77 	except:
78 		pass
79 
80 if pyside_version_1:
81 	from PySide.QtSql import *
82 
83 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
84 	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
85 
86 # These perf imports are not used at present
87 #from perf_trace_context import *
88 #from Core import *
89 
90 perf_db_export_mode = True
91 perf_db_export_calls = False
92 perf_db_export_callchains = False
93 
94 def printerr(*args, **keyword_args):
95 	print(*args, file=sys.stderr, **keyword_args)
96 
97 def printdate(*args, **kw_args):
98         print(datetime.datetime.today(), *args, sep=' ', **kw_args)
99 
100 def usage():
101 	printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>] [<pyside-version-1>]");
102 	printerr("where:  columns            'all' or 'branches'");
103 	printerr("        calls              'calls' => create calls and call_paths table");
104 	printerr("        callchains         'callchains' => create call_paths table");
105 	printerr("        pyside-version-1   'pyside-version-1' => use pyside version 1");
106 	raise Exception("Too few or bad arguments")
107 
108 if (len(sys.argv) < 2):
109 	usage()
110 
111 dbname = sys.argv[1]
112 
113 if (len(sys.argv) >= 3):
114 	columns = sys.argv[2]
115 else:
116 	columns = "all"
117 
118 if columns not in ("all", "branches"):
119 	usage()
120 
121 branches = (columns == "branches")
122 
123 for i in range(3,len(sys.argv)):
124 	if (sys.argv[i] == "calls"):
125 		perf_db_export_calls = True
126 	elif (sys.argv[i] == "callchains"):
127 		perf_db_export_callchains = True
128 	elif (sys.argv[i] == "pyside-version-1"):
129 		pass
130 	else:
131 		usage()
132 
133 def do_query(q, s):
134 	if (q.exec_(s)):
135 		return
136 	raise Exception("Query failed: " + q.lastError().text())
137 
138 def do_query_(q):
139 	if (q.exec_()):
140 		return
141 	raise Exception("Query failed: " + q.lastError().text())
142 
143 printdate("Creating database ...")
144 
145 db_exists = False
146 try:
147 	f = open(dbname)
148 	f.close()
149 	db_exists = True
150 except:
151 	pass
152 
153 if db_exists:
154 	raise Exception(dbname + " already exists")
155 
156 db = QSqlDatabase.addDatabase('QSQLITE')
157 db.setDatabaseName(dbname)
158 db.open()
159 
160 query = QSqlQuery(db)
161 
162 do_query(query, 'PRAGMA journal_mode = OFF')
163 do_query(query, 'BEGIN TRANSACTION')
164 
165 do_query(query, 'CREATE TABLE selected_events ('
166 		'id		integer		NOT NULL	PRIMARY KEY,'
167 		'name		varchar(80))')
168 do_query(query, 'CREATE TABLE machines ('
169 		'id		integer		NOT NULL	PRIMARY KEY,'
170 		'pid		integer,'
171 		'root_dir 	varchar(4096))')
172 do_query(query, 'CREATE TABLE threads ('
173 		'id		integer		NOT NULL	PRIMARY KEY,'
174 		'machine_id	bigint,'
175 		'process_id	bigint,'
176 		'pid		integer,'
177 		'tid		integer)')
178 do_query(query, 'CREATE TABLE comms ('
179 		'id		integer		NOT NULL	PRIMARY KEY,'
180 		'comm		varchar(16),'
181 		'c_thread_id	bigint,'
182 		'c_time		bigint,'
183 		'exec_flag	boolean)')
184 do_query(query, 'CREATE TABLE comm_threads ('
185 		'id		integer		NOT NULL	PRIMARY KEY,'
186 		'comm_id	bigint,'
187 		'thread_id	bigint)')
188 do_query(query, 'CREATE TABLE dsos ('
189 		'id		integer		NOT NULL	PRIMARY KEY,'
190 		'machine_id	bigint,'
191 		'short_name	varchar(256),'
192 		'long_name	varchar(4096),'
193 		'build_id	varchar(64))')
194 do_query(query, 'CREATE TABLE symbols ('
195 		'id		integer		NOT NULL	PRIMARY KEY,'
196 		'dso_id		bigint,'
197 		'sym_start	bigint,'
198 		'sym_end	bigint,'
199 		'binding	integer,'
200 		'name		varchar(2048))')
201 do_query(query, 'CREATE TABLE branch_types ('
202 		'id		integer		NOT NULL	PRIMARY KEY,'
203 		'name		varchar(80))')
204 
205 if branches:
206 	do_query(query, 'CREATE TABLE samples ('
207 		'id		integer		NOT NULL	PRIMARY KEY,'
208 		'evsel_id	bigint,'
209 		'machine_id	bigint,'
210 		'thread_id	bigint,'
211 		'comm_id	bigint,'
212 		'dso_id		bigint,'
213 		'symbol_id	bigint,'
214 		'sym_offset	bigint,'
215 		'ip		bigint,'
216 		'time		bigint,'
217 		'cpu		integer,'
218 		'to_dso_id	bigint,'
219 		'to_symbol_id	bigint,'
220 		'to_sym_offset	bigint,'
221 		'to_ip		bigint,'
222 		'branch_type	integer,'
223 		'in_tx		boolean,'
224 		'call_path_id	bigint,'
225 		'insn_count	bigint,'
226 		'cyc_count	bigint,'
227 		'flags		integer)')
228 else:
229 	do_query(query, 'CREATE TABLE samples ('
230 		'id		integer		NOT NULL	PRIMARY KEY,'
231 		'evsel_id	bigint,'
232 		'machine_id	bigint,'
233 		'thread_id	bigint,'
234 		'comm_id	bigint,'
235 		'dso_id		bigint,'
236 		'symbol_id	bigint,'
237 		'sym_offset	bigint,'
238 		'ip		bigint,'
239 		'time		bigint,'
240 		'cpu		integer,'
241 		'to_dso_id	bigint,'
242 		'to_symbol_id	bigint,'
243 		'to_sym_offset	bigint,'
244 		'to_ip		bigint,'
245 		'period		bigint,'
246 		'weight		bigint,'
247 		'transaction_	bigint,'
248 		'data_src	bigint,'
249 		'branch_type	integer,'
250 		'in_tx		boolean,'
251 		'call_path_id	bigint,'
252 		'insn_count	bigint,'
253 		'cyc_count	bigint,'
254 		'flags		integer)')
255 
256 if perf_db_export_calls or perf_db_export_callchains:
257 	do_query(query, 'CREATE TABLE call_paths ('
258 		'id		integer		NOT NULL	PRIMARY KEY,'
259 		'parent_id	bigint,'
260 		'symbol_id	bigint,'
261 		'ip		bigint)')
262 if perf_db_export_calls:
263 	do_query(query, 'CREATE TABLE calls ('
264 		'id		integer		NOT NULL	PRIMARY KEY,'
265 		'thread_id	bigint,'
266 		'comm_id	bigint,'
267 		'call_path_id	bigint,'
268 		'call_time	bigint,'
269 		'return_time	bigint,'
270 		'branch_count	bigint,'
271 		'call_id	bigint,'
272 		'return_id	bigint,'
273 		'parent_call_path_id	bigint,'
274 		'flags		integer,'
275 		'parent_id	bigint,'
276 		'insn_count	bigint,'
277 		'cyc_count	bigint)')
278 
279 do_query(query, 'CREATE TABLE ptwrite ('
280 		'id		integer		NOT NULL	PRIMARY KEY,'
281 		'payload	bigint,'
282 		'exact_ip	integer)')
283 
284 do_query(query, 'CREATE TABLE cbr ('
285 		'id		integer		NOT NULL	PRIMARY KEY,'
286 		'cbr		integer,'
287 		'mhz		integer,'
288 		'percent	integer)')
289 
290 do_query(query, 'CREATE TABLE mwait ('
291 		'id		integer		NOT NULL	PRIMARY KEY,'
292 		'hints		integer,'
293 		'extensions	integer)')
294 
295 do_query(query, 'CREATE TABLE pwre ('
296 		'id		integer		NOT NULL	PRIMARY KEY,'
297 		'cstate		integer,'
298 		'subcstate	integer,'
299 		'hw		integer)')
300 
301 do_query(query, 'CREATE TABLE exstop ('
302 		'id		integer		NOT NULL	PRIMARY KEY,'
303 		'exact_ip	integer)')
304 
305 do_query(query, 'CREATE TABLE pwrx ('
306 		'id		integer		NOT NULL	PRIMARY KEY,'
307 		'deepest_cstate	integer,'
308 		'last_cstate	integer,'
309 		'wake_reason	integer)')
310 
311 do_query(query, 'CREATE TABLE context_switches ('
312 		'id		integer		NOT NULL	PRIMARY KEY,'
313 		'machine_id	bigint,'
314 		'time		bigint,'
315 		'cpu		integer,'
316 		'thread_out_id	bigint,'
317 		'comm_out_id	bigint,'
318 		'thread_in_id	bigint,'
319 		'comm_in_id	bigint,'
320 		'flags		integer)')
321 
322 # printf was added to sqlite in version 3.8.3
323 sqlite_has_printf = False
324 try:
325 	do_query(query, 'SELECT printf("") FROM machines')
326 	sqlite_has_printf = True
327 except:
328 	pass
329 
330 def emit_to_hex(x):
331 	if sqlite_has_printf:
332 		return 'printf("%x", ' + x + ')'
333 	else:
334 		return x
335 
336 do_query(query, 'CREATE VIEW machines_view AS '
337 	'SELECT '
338 		'id,'
339 		'pid,'
340 		'root_dir,'
341 		'CASE WHEN id=0 THEN \'unknown\' WHEN pid=-1 THEN \'host\' ELSE \'guest\' END AS host_or_guest'
342 	' FROM machines')
343 
344 do_query(query, 'CREATE VIEW dsos_view AS '
345 	'SELECT '
346 		'id,'
347 		'machine_id,'
348 		'(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,'
349 		'short_name,'
350 		'long_name,'
351 		'build_id'
352 	' FROM dsos')
353 
354 do_query(query, 'CREATE VIEW symbols_view AS '
355 	'SELECT '
356 		'id,'
357 		'name,'
358 		'(SELECT short_name FROM dsos WHERE id=dso_id) AS dso,'
359 		'dso_id,'
360 		'sym_start,'
361 		'sym_end,'
362 		'CASE WHEN binding=0 THEN \'local\' WHEN binding=1 THEN \'global\' ELSE \'weak\' END AS binding'
363 	' FROM symbols')
364 
365 do_query(query, 'CREATE VIEW threads_view AS '
366 	'SELECT '
367 		'id,'
368 		'machine_id,'
369 		'(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,'
370 		'process_id,'
371 		'pid,'
372 		'tid'
373 	' FROM threads')
374 
375 do_query(query, 'CREATE VIEW comm_threads_view AS '
376 	'SELECT '
377 		'comm_id,'
378 		'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
379 		'thread_id,'
380 		'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
381 		'(SELECT tid FROM threads WHERE id = thread_id) AS tid'
382 	' FROM comm_threads')
383 
384 if perf_db_export_calls or perf_db_export_callchains:
385 	do_query(query, 'CREATE VIEW call_paths_view AS '
386 		'SELECT '
387 			'c.id,'
388 			+ emit_to_hex('c.ip') + ' AS ip,'
389 			'c.symbol_id,'
390 			'(SELECT name FROM symbols WHERE id = c.symbol_id) AS symbol,'
391 			'(SELECT dso_id FROM symbols WHERE id = c.symbol_id) AS dso_id,'
392 			'(SELECT dso FROM symbols_view  WHERE id = c.symbol_id) AS dso_short_name,'
393 			'c.parent_id,'
394 			+ emit_to_hex('p.ip') + ' AS parent_ip,'
395 			'p.symbol_id AS parent_symbol_id,'
396 			'(SELECT name FROM symbols WHERE id = p.symbol_id) AS parent_symbol,'
397 			'(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,'
398 			'(SELECT dso FROM symbols_view  WHERE id = p.symbol_id) AS parent_dso_short_name'
399 		' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id')
400 if perf_db_export_calls:
401 	do_query(query, 'CREATE VIEW calls_view AS '
402 		'SELECT '
403 			'calls.id,'
404 			'thread_id,'
405 			'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
406 			'(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
407 			'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
408 			'call_path_id,'
409 			+ emit_to_hex('ip') + ' AS ip,'
410 			'symbol_id,'
411 			'(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
412 			'call_time,'
413 			'return_time,'
414 			'return_time - call_time AS elapsed_time,'
415 			'branch_count,'
416 			'insn_count,'
417 			'cyc_count,'
418 			'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC,'
419 			'call_id,'
420 			'return_id,'
421 			'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
422 			'parent_call_path_id,'
423 			'calls.parent_id'
424 		' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
425 
426 do_query(query, 'CREATE VIEW samples_view AS '
427 	'SELECT '
428 		'id,'
429 		'time,'
430 		'cpu,'
431 		'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
432 		'(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
433 		'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
434 		'(SELECT name FROM selected_events WHERE id = evsel_id) AS event,'
435 		+ emit_to_hex('ip') + ' AS ip_hex,'
436 		'(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
437 		'sym_offset,'
438 		'(SELECT short_name FROM dsos WHERE id = dso_id) AS dso_short_name,'
439 		+ emit_to_hex('to_ip') + ' AS to_ip_hex,'
440 		'(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
441 		'to_sym_offset,'
442 		'(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
443 		'(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
444 		'in_tx,'
445 		'insn_count,'
446 		'cyc_count,'
447 		'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC,'
448 		'flags'
449 	' FROM samples')
450 
451 do_query(query, 'CREATE VIEW ptwrite_view AS '
452 	'SELECT '
453 		'ptwrite.id,'
454 		'time,'
455 		'cpu,'
456 		+ emit_to_hex('payload') + ' AS payload_hex,'
457 		'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
458 	' FROM ptwrite'
459 	' INNER JOIN samples ON samples.id = ptwrite.id')
460 
461 do_query(query, 'CREATE VIEW cbr_view AS '
462 	'SELECT '
463 		'cbr.id,'
464 		'time,'
465 		'cpu,'
466 		'cbr,'
467 		'mhz,'
468 		'percent'
469 	' FROM cbr'
470 	' INNER JOIN samples ON samples.id = cbr.id')
471 
472 do_query(query, 'CREATE VIEW mwait_view AS '
473 	'SELECT '
474 		'mwait.id,'
475 		'time,'
476 		'cpu,'
477 		+ emit_to_hex('hints') + ' AS hints_hex,'
478 		+ emit_to_hex('extensions') + ' AS extensions_hex'
479 	' FROM mwait'
480 	' INNER JOIN samples ON samples.id = mwait.id')
481 
482 do_query(query, 'CREATE VIEW pwre_view AS '
483 	'SELECT '
484 		'pwre.id,'
485 		'time,'
486 		'cpu,'
487 		'cstate,'
488 		'subcstate,'
489 		'CASE WHEN hw=0 THEN \'False\' ELSE \'True\' END AS hw'
490 	' FROM pwre'
491 	' INNER JOIN samples ON samples.id = pwre.id')
492 
493 do_query(query, 'CREATE VIEW exstop_view AS '
494 	'SELECT '
495 		'exstop.id,'
496 		'time,'
497 		'cpu,'
498 		'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
499 	' FROM exstop'
500 	' INNER JOIN samples ON samples.id = exstop.id')
501 
502 do_query(query, 'CREATE VIEW pwrx_view AS '
503 	'SELECT '
504 		'pwrx.id,'
505 		'time,'
506 		'cpu,'
507 		'deepest_cstate,'
508 		'last_cstate,'
509 		'CASE     WHEN wake_reason=1 THEN \'Interrupt\''
510 			' WHEN wake_reason=2 THEN \'Timer Deadline\''
511 			' WHEN wake_reason=4 THEN \'Monitored Address\''
512 			' WHEN wake_reason=8 THEN \'HW\''
513 			' ELSE wake_reason '
514 		'END AS wake_reason'
515 	' FROM pwrx'
516 	' INNER JOIN samples ON samples.id = pwrx.id')
517 
518 do_query(query, 'CREATE VIEW power_events_view AS '
519 	'SELECT '
520 		'samples.id,'
521 		'time,'
522 		'cpu,'
523 		'selected_events.name AS event,'
524 		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT cbr FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS cbr,'
525 		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT mhz FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS mhz,'
526 		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT percent FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS percent,'
527 		'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('hints') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS hints_hex,'
528 		'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('extensions') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS extensions_hex,'
529 		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT cstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS cstate,'
530 		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT subcstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS subcstate,'
531 		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT hw FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS hw,'
532 		'CASE WHEN selected_events.name=\'exstop\' THEN (SELECT exact_ip FROM exstop WHERE exstop.id = samples.id) ELSE "" END AS exact_ip,'
533 		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT deepest_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS deepest_cstate,'
534 		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT last_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS last_cstate,'
535 		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT '
536 			'CASE     WHEN wake_reason=1 THEN \'Interrupt\''
537 				' WHEN wake_reason=2 THEN \'Timer Deadline\''
538 				' WHEN wake_reason=4 THEN \'Monitored Address\''
539 				' WHEN wake_reason=8 THEN \'HW\''
540 				' ELSE wake_reason '
541 			'END'
542 		' FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS wake_reason'
543 	' FROM samples'
544 	' INNER JOIN selected_events ON selected_events.id = evsel_id'
545 	' WHERE selected_events.name IN (\'cbr\',\'mwait\',\'exstop\',\'pwre\',\'pwrx\')')
546 
547 do_query(query, 'CREATE VIEW context_switches_view AS '
548 	'SELECT '
549 		'context_switches.id,'
550 		'context_switches.machine_id,'
551 		'context_switches.time,'
552 		'context_switches.cpu,'
553 		'th_out.pid AS pid_out,'
554 		'th_out.tid AS tid_out,'
555 		'comm_out.comm AS comm_out,'
556 		'th_in.pid AS pid_in,'
557 		'th_in.tid AS tid_in,'
558 		'comm_in.comm AS comm_in,'
559 		'CASE	  WHEN context_switches.flags = 0 THEN \'in\''
560 			' WHEN context_switches.flags = 1 THEN \'out\''
561 			' WHEN context_switches.flags = 3 THEN \'out preempt\''
562 			' ELSE context_switches.flags '
563 		'END AS flags'
564 	' FROM context_switches'
565 	' INNER JOIN threads AS th_out ON th_out.id   = context_switches.thread_out_id'
566 	' INNER JOIN threads AS th_in  ON th_in.id    = context_switches.thread_in_id'
567 	' INNER JOIN comms AS comm_out ON comm_out.id = context_switches.comm_out_id'
568 	' INNER JOIN comms AS comm_in  ON comm_in.id  = context_switches.comm_in_id')
569 
570 do_query(query, 'END TRANSACTION')
571 
572 evsel_query = QSqlQuery(db)
573 evsel_query.prepare("INSERT INTO selected_events VALUES (?, ?)")
574 machine_query = QSqlQuery(db)
575 machine_query.prepare("INSERT INTO machines VALUES (?, ?, ?)")
576 thread_query = QSqlQuery(db)
577 thread_query.prepare("INSERT INTO threads VALUES (?, ?, ?, ?, ?)")
578 comm_query = QSqlQuery(db)
579 comm_query.prepare("INSERT INTO comms VALUES (?, ?, ?, ?, ?)")
580 comm_thread_query = QSqlQuery(db)
581 comm_thread_query.prepare("INSERT INTO comm_threads VALUES (?, ?, ?)")
582 dso_query = QSqlQuery(db)
583 dso_query.prepare("INSERT INTO dsos VALUES (?, ?, ?, ?, ?)")
584 symbol_query = QSqlQuery(db)
585 symbol_query.prepare("INSERT INTO symbols VALUES (?, ?, ?, ?, ?, ?)")
586 branch_type_query = QSqlQuery(db)
587 branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)")
588 sample_query = QSqlQuery(db)
589 if branches:
590 	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
591 else:
592 	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
593 if perf_db_export_calls or perf_db_export_callchains:
594 	call_path_query = QSqlQuery(db)
595 	call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)")
596 if perf_db_export_calls:
597 	call_query = QSqlQuery(db)
598 	call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
599 ptwrite_query = QSqlQuery(db)
600 ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)")
601 cbr_query = QSqlQuery(db)
602 cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)")
603 mwait_query = QSqlQuery(db)
604 mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)")
605 pwre_query = QSqlQuery(db)
606 pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)")
607 exstop_query = QSqlQuery(db)
608 exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
609 pwrx_query = QSqlQuery(db)
610 pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
611 context_switch_query = QSqlQuery(db)
612 context_switch_query.prepare("INSERT INTO context_switches VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
613 
614 def trace_begin():
615 	printdate("Writing records...")
616 	do_query(query, 'BEGIN TRANSACTION')
617 	# id == 0 means unknown.  It is easier to create records for them than replace the zeroes with NULLs
618 	evsel_table(0, "unknown")
619 	machine_table(0, 0, "unknown")
620 	thread_table(0, 0, 0, -1, -1)
621 	comm_table(0, "unknown", 0, 0, 0)
622 	dso_table(0, 0, "unknown", "unknown", "")
623 	symbol_table(0, 0, 0, 0, 0, "unknown")
624 	sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
625 	if perf_db_export_calls or perf_db_export_callchains:
626 		call_path_table(0, 0, 0, 0)
627 		call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
628 
629 unhandled_count = 0
630 
631 def is_table_empty(table_name):
632 	do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
633 	if query.next():
634 		return False
635 	return True
636 
637 def drop(table_name):
638 	do_query(query, 'DROP VIEW ' + table_name + '_view');
639 	do_query(query, 'DROP TABLE ' + table_name);
640 
641 def trace_end():
642 	do_query(query, 'END TRANSACTION')
643 
644 	printdate("Adding indexes")
645 	if perf_db_export_calls:
646 		do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
647 		do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
648 		do_query(query, 'ALTER TABLE comms ADD has_calls boolean')
649 		do_query(query, 'UPDATE comms SET has_calls = 1 WHERE comms.id IN (SELECT DISTINCT comm_id FROM calls)')
650 
651 	printdate("Dropping unused tables")
652 	if is_table_empty("ptwrite"):
653 		drop("ptwrite")
654 	if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
655 		do_query(query, 'DROP VIEW power_events_view');
656 		drop("mwait")
657 		drop("pwre")
658 		drop("exstop")
659 		drop("pwrx")
660 		if is_table_empty("cbr"):
661 			drop("cbr")
662 	if is_table_empty("context_switches"):
663 		drop("context_switches")
664 
665 	if (unhandled_count):
666 		printdate("Warning: ", unhandled_count, " unhandled events")
667 	printdate("Done")
668 
669 def trace_unhandled(event_name, context, event_fields_dict):
670 	global unhandled_count
671 	unhandled_count += 1
672 
673 def sched__sched_switch(*x):
674 	pass
675 
676 def bind_exec(q, n, x):
677 	for xx in x[0:n]:
678 		q.addBindValue(str(xx))
679 	do_query_(q)
680 
681 def evsel_table(*x):
682 	bind_exec(evsel_query, 2, x)
683 
684 def machine_table(*x):
685 	bind_exec(machine_query, 3, x)
686 
687 def thread_table(*x):
688 	bind_exec(thread_query, 5, x)
689 
690 def comm_table(*x):
691 	bind_exec(comm_query, 5, x)
692 
693 def comm_thread_table(*x):
694 	bind_exec(comm_thread_query, 3, x)
695 
696 def dso_table(*x):
697 	bind_exec(dso_query, 5, x)
698 
699 def symbol_table(*x):
700 	bind_exec(symbol_query, 6, x)
701 
702 def branch_type_table(*x):
703 	bind_exec(branch_type_query, 2, x)
704 
705 def sample_table(*x):
706 	if branches:
707 		for xx in x[0:15]:
708 			sample_query.addBindValue(str(xx))
709 		for xx in x[19:25]:
710 			sample_query.addBindValue(str(xx))
711 		do_query_(sample_query)
712 	else:
713 		bind_exec(sample_query, 25, x)
714 
715 def call_path_table(*x):
716 	bind_exec(call_path_query, 4, x)
717 
718 def call_return_table(*x):
719 	bind_exec(call_query, 14, x)
720 
721 def ptwrite(id, raw_buf):
722 	data = struct.unpack_from("<IQ", raw_buf)
723 	flags = data[0]
724 	payload = data[1]
725 	exact_ip = flags & 1
726 	ptwrite_query.addBindValue(str(id))
727 	ptwrite_query.addBindValue(str(payload))
728 	ptwrite_query.addBindValue(str(exact_ip))
729 	do_query_(ptwrite_query)
730 
731 def cbr(id, raw_buf):
732 	data = struct.unpack_from("<BBBBII", raw_buf)
733 	cbr = data[0]
734 	MHz = (data[4] + 500) / 1000
735 	percent = ((cbr * 1000 / data[2]) + 5) / 10
736 	cbr_query.addBindValue(str(id))
737 	cbr_query.addBindValue(str(cbr))
738 	cbr_query.addBindValue(str(MHz))
739 	cbr_query.addBindValue(str(percent))
740 	do_query_(cbr_query)
741 
742 def mwait(id, raw_buf):
743 	data = struct.unpack_from("<IQ", raw_buf)
744 	payload = data[1]
745 	hints = payload & 0xff
746 	extensions = (payload >> 32) & 0x3
747 	mwait_query.addBindValue(str(id))
748 	mwait_query.addBindValue(str(hints))
749 	mwait_query.addBindValue(str(extensions))
750 	do_query_(mwait_query)
751 
752 def pwre(id, raw_buf):
753 	data = struct.unpack_from("<IQ", raw_buf)
754 	payload = data[1]
755 	hw = (payload >> 7) & 1
756 	cstate = (payload >> 12) & 0xf
757 	subcstate = (payload >> 8) & 0xf
758 	pwre_query.addBindValue(str(id))
759 	pwre_query.addBindValue(str(cstate))
760 	pwre_query.addBindValue(str(subcstate))
761 	pwre_query.addBindValue(str(hw))
762 	do_query_(pwre_query)
763 
764 def exstop(id, raw_buf):
765 	data = struct.unpack_from("<I", raw_buf)
766 	flags = data[0]
767 	exact_ip = flags & 1
768 	exstop_query.addBindValue(str(id))
769 	exstop_query.addBindValue(str(exact_ip))
770 	do_query_(exstop_query)
771 
772 def pwrx(id, raw_buf):
773 	data = struct.unpack_from("<IQ", raw_buf)
774 	payload = data[1]
775 	deepest_cstate = payload & 0xf
776 	last_cstate = (payload >> 4) & 0xf
777 	wake_reason = (payload >> 8) & 0xf
778 	pwrx_query.addBindValue(str(id))
779 	pwrx_query.addBindValue(str(deepest_cstate))
780 	pwrx_query.addBindValue(str(last_cstate))
781 	pwrx_query.addBindValue(str(wake_reason))
782 	do_query_(pwrx_query)
783 
784 def synth_data(id, config, raw_buf, *x):
785 	if config == 0:
786 		ptwrite(id, raw_buf)
787 	elif config == 1:
788 		mwait(id, raw_buf)
789 	elif config == 2:
790 		pwre(id, raw_buf)
791 	elif config == 3:
792 		exstop(id, raw_buf)
793 	elif config == 4:
794 		pwrx(id, raw_buf)
795 	elif config == 5:
796 		cbr(id, raw_buf)
797 
798 def context_switch_table(*x):
799 	bind_exec(context_switch_query, 9, x)
800