Linux Audio

Check our new training course

Loading...
v5.14.15
  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
 13from __future__ import print_function
 14
 15import os
 16import sys
 17import struct
 18import 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
 72pyside_version_1 = True
 73if not "pyside-version-1" in sys.argv:
 74	try:
 75		from PySide2.QtSql import *
 76		pyside_version_1 = False
 77	except:
 78		pass
 79
 80if pyside_version_1:
 81	from PySide.QtSql import *
 82
 83sys.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
 90perf_db_export_mode = True
 91perf_db_export_calls = False
 92perf_db_export_callchains = False
 93
 94def printerr(*args, **keyword_args):
 95	print(*args, file=sys.stderr, **keyword_args)
 96
 97def printdate(*args, **kw_args):
 98        print(datetime.datetime.today(), *args, sep=' ', **kw_args)
 99
100def 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
108if (len(sys.argv) < 2):
109	usage()
110
111dbname = sys.argv[1]
112
113if (len(sys.argv) >= 3):
114	columns = sys.argv[2]
115else:
116	columns = "all"
117
118if columns not in ("all", "branches"):
119	usage()
120
121branches = (columns == "branches")
122
123for 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
133def do_query(q, s):
134	if (q.exec_(s)):
135		return
136	raise Exception("Query failed: " + q.lastError().text())
137
138def do_query_(q):
139	if (q.exec_()):
140		return
141	raise Exception("Query failed: " + q.lastError().text())
142
143printdate("Creating database ...")
144
145db_exists = False
146try:
147	f = open(dbname)
148	f.close()
149	db_exists = True
150except:
151	pass
152
153if db_exists:
154	raise Exception(dbname + " already exists")
155
156db = QSqlDatabase.addDatabase('QSQLITE')
157db.setDatabaseName(dbname)
158db.open()
159
160query = QSqlQuery(db)
161
162do_query(query, 'PRAGMA journal_mode = OFF')
163do_query(query, 'BEGIN TRANSACTION')
164
165do_query(query, 'CREATE TABLE selected_events ('
166		'id		integer		NOT NULL	PRIMARY KEY,'
167		'name		varchar(80))')
168do_query(query, 'CREATE TABLE machines ('
169		'id		integer		NOT NULL	PRIMARY KEY,'
170		'pid		integer,'
171		'root_dir 	varchar(4096))')
172do_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)')
178do_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)')
184do_query(query, 'CREATE TABLE comm_threads ('
185		'id		integer		NOT NULL	PRIMARY KEY,'
186		'comm_id	bigint,'
187		'thread_id	bigint)')
188do_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))')
194do_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))')
201do_query(query, 'CREATE TABLE branch_types ('
202		'id		integer		NOT NULL	PRIMARY KEY,'
203		'name		varchar(80))')
204
205if 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)')
 
227else:
228	do_query(query, 'CREATE TABLE samples ('
229		'id		integer		NOT NULL	PRIMARY KEY,'
230		'evsel_id	bigint,'
231		'machine_id	bigint,'
232		'thread_id	bigint,'
233		'comm_id	bigint,'
234		'dso_id		bigint,'
235		'symbol_id	bigint,'
236		'sym_offset	bigint,'
237		'ip		bigint,'
238		'time		bigint,'
239		'cpu		integer,'
240		'to_dso_id	bigint,'
241		'to_symbol_id	bigint,'
242		'to_sym_offset	bigint,'
243		'to_ip		bigint,'
244		'period		bigint,'
245		'weight		bigint,'
246		'transaction_	bigint,'
247		'data_src	bigint,'
248		'branch_type	integer,'
249		'in_tx		boolean,'
250		'call_path_id	bigint,'
251		'insn_count	bigint,'
252		'cyc_count	bigint)')
 
253
254if perf_db_export_calls or perf_db_export_callchains:
255	do_query(query, 'CREATE TABLE call_paths ('
256		'id		integer		NOT NULL	PRIMARY KEY,'
257		'parent_id	bigint,'
258		'symbol_id	bigint,'
259		'ip		bigint)')
260if perf_db_export_calls:
261	do_query(query, 'CREATE TABLE calls ('
262		'id		integer		NOT NULL	PRIMARY KEY,'
263		'thread_id	bigint,'
264		'comm_id	bigint,'
265		'call_path_id	bigint,'
266		'call_time	bigint,'
267		'return_time	bigint,'
268		'branch_count	bigint,'
269		'call_id	bigint,'
270		'return_id	bigint,'
271		'parent_call_path_id	bigint,'
272		'flags		integer,'
273		'parent_id	bigint,'
274		'insn_count	bigint,'
275		'cyc_count	bigint)')
276
277do_query(query, 'CREATE TABLE ptwrite ('
278		'id		integer		NOT NULL	PRIMARY KEY,'
279		'payload	bigint,'
280		'exact_ip	integer)')
281
282do_query(query, 'CREATE TABLE cbr ('
283		'id		integer		NOT NULL	PRIMARY KEY,'
284		'cbr		integer,'
285		'mhz		integer,'
286		'percent	integer)')
287
288do_query(query, 'CREATE TABLE mwait ('
289		'id		integer		NOT NULL	PRIMARY KEY,'
290		'hints		integer,'
291		'extensions	integer)')
292
293do_query(query, 'CREATE TABLE pwre ('
294		'id		integer		NOT NULL	PRIMARY KEY,'
295		'cstate		integer,'
296		'subcstate	integer,'
297		'hw		integer)')
298
299do_query(query, 'CREATE TABLE exstop ('
300		'id		integer		NOT NULL	PRIMARY KEY,'
301		'exact_ip	integer)')
302
303do_query(query, 'CREATE TABLE pwrx ('
304		'id		integer		NOT NULL	PRIMARY KEY,'
305		'deepest_cstate	integer,'
306		'last_cstate	integer,'
307		'wake_reason	integer)')
308
309do_query(query, 'CREATE TABLE context_switches ('
310		'id		integer		NOT NULL	PRIMARY KEY,'
311		'machine_id	bigint,'
312		'time		bigint,'
313		'cpu		integer,'
314		'thread_out_id	bigint,'
315		'comm_out_id	bigint,'
316		'thread_in_id	bigint,'
317		'comm_in_id	bigint,'
318		'flags		integer)')
319
320# printf was added to sqlite in version 3.8.3
321sqlite_has_printf = False
322try:
323	do_query(query, 'SELECT printf("") FROM machines')
324	sqlite_has_printf = True
325except:
326	pass
327
328def emit_to_hex(x):
329	if sqlite_has_printf:
330		return 'printf("%x", ' + x + ')'
331	else:
332		return x
333
334do_query(query, 'CREATE VIEW machines_view AS '
335	'SELECT '
336		'id,'
337		'pid,'
338		'root_dir,'
339		'CASE WHEN id=0 THEN \'unknown\' WHEN pid=-1 THEN \'host\' ELSE \'guest\' END AS host_or_guest'
340	' FROM machines')
341
342do_query(query, 'CREATE VIEW dsos_view AS '
343	'SELECT '
344		'id,'
345		'machine_id,'
346		'(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,'
347		'short_name,'
348		'long_name,'
349		'build_id'
350	' FROM dsos')
351
352do_query(query, 'CREATE VIEW symbols_view AS '
353	'SELECT '
354		'id,'
355		'name,'
356		'(SELECT short_name FROM dsos WHERE id=dso_id) AS dso,'
357		'dso_id,'
358		'sym_start,'
359		'sym_end,'
360		'CASE WHEN binding=0 THEN \'local\' WHEN binding=1 THEN \'global\' ELSE \'weak\' END AS binding'
361	' FROM symbols')
362
363do_query(query, 'CREATE VIEW threads_view AS '
364	'SELECT '
365		'id,'
366		'machine_id,'
367		'(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,'
368		'process_id,'
369		'pid,'
370		'tid'
371	' FROM threads')
372
373do_query(query, 'CREATE VIEW comm_threads_view AS '
374	'SELECT '
375		'comm_id,'
376		'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
377		'thread_id,'
378		'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
379		'(SELECT tid FROM threads WHERE id = thread_id) AS tid'
380	' FROM comm_threads')
381
382if perf_db_export_calls or perf_db_export_callchains:
383	do_query(query, 'CREATE VIEW call_paths_view AS '
384		'SELECT '
385			'c.id,'
386			+ emit_to_hex('c.ip') + ' AS ip,'
387			'c.symbol_id,'
388			'(SELECT name FROM symbols WHERE id = c.symbol_id) AS symbol,'
389			'(SELECT dso_id FROM symbols WHERE id = c.symbol_id) AS dso_id,'
390			'(SELECT dso FROM symbols_view  WHERE id = c.symbol_id) AS dso_short_name,'
391			'c.parent_id,'
392			+ emit_to_hex('p.ip') + ' AS parent_ip,'
393			'p.symbol_id AS parent_symbol_id,'
394			'(SELECT name FROM symbols WHERE id = p.symbol_id) AS parent_symbol,'
395			'(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,'
396			'(SELECT dso FROM symbols_view  WHERE id = p.symbol_id) AS parent_dso_short_name'
397		' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id')
398if perf_db_export_calls:
399	do_query(query, 'CREATE VIEW calls_view AS '
400		'SELECT '
401			'calls.id,'
402			'thread_id,'
403			'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
404			'(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
405			'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
406			'call_path_id,'
407			+ emit_to_hex('ip') + ' AS ip,'
408			'symbol_id,'
409			'(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
410			'call_time,'
411			'return_time,'
412			'return_time - call_time AS elapsed_time,'
413			'branch_count,'
414			'insn_count,'
415			'cyc_count,'
416			'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC,'
417			'call_id,'
418			'return_id,'
419			'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,'
420			'parent_call_path_id,'
421			'calls.parent_id'
422		' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
423
424do_query(query, 'CREATE VIEW samples_view AS '
425	'SELECT '
426		'id,'
427		'time,'
428		'cpu,'
429		'(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
430		'(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
431		'(SELECT comm FROM comms WHERE id = comm_id) AS command,'
432		'(SELECT name FROM selected_events WHERE id = evsel_id) AS event,'
433		+ emit_to_hex('ip') + ' AS ip_hex,'
434		'(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
435		'sym_offset,'
436		'(SELECT short_name FROM dsos WHERE id = dso_id) AS dso_short_name,'
437		+ emit_to_hex('to_ip') + ' AS to_ip_hex,'
438		'(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
439		'to_sym_offset,'
440		'(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
441		'(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
442		'in_tx,'
443		'insn_count,'
444		'cyc_count,'
445		'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC'
 
446	' FROM samples')
447
448do_query(query, 'CREATE VIEW ptwrite_view AS '
449	'SELECT '
450		'ptwrite.id,'
451		'time,'
452		'cpu,'
453		+ emit_to_hex('payload') + ' AS payload_hex,'
454		'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
455	' FROM ptwrite'
456	' INNER JOIN samples ON samples.id = ptwrite.id')
457
458do_query(query, 'CREATE VIEW cbr_view AS '
459	'SELECT '
460		'cbr.id,'
461		'time,'
462		'cpu,'
463		'cbr,'
464		'mhz,'
465		'percent'
466	' FROM cbr'
467	' INNER JOIN samples ON samples.id = cbr.id')
468
469do_query(query, 'CREATE VIEW mwait_view AS '
470	'SELECT '
471		'mwait.id,'
472		'time,'
473		'cpu,'
474		+ emit_to_hex('hints') + ' AS hints_hex,'
475		+ emit_to_hex('extensions') + ' AS extensions_hex'
476	' FROM mwait'
477	' INNER JOIN samples ON samples.id = mwait.id')
478
479do_query(query, 'CREATE VIEW pwre_view AS '
480	'SELECT '
481		'pwre.id,'
482		'time,'
483		'cpu,'
484		'cstate,'
485		'subcstate,'
486		'CASE WHEN hw=0 THEN \'False\' ELSE \'True\' END AS hw'
487	' FROM pwre'
488	' INNER JOIN samples ON samples.id = pwre.id')
489
490do_query(query, 'CREATE VIEW exstop_view AS '
491	'SELECT '
492		'exstop.id,'
493		'time,'
494		'cpu,'
495		'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
496	' FROM exstop'
497	' INNER JOIN samples ON samples.id = exstop.id')
498
499do_query(query, 'CREATE VIEW pwrx_view AS '
500	'SELECT '
501		'pwrx.id,'
502		'time,'
503		'cpu,'
504		'deepest_cstate,'
505		'last_cstate,'
506		'CASE     WHEN wake_reason=1 THEN \'Interrupt\''
507			' WHEN wake_reason=2 THEN \'Timer Deadline\''
508			' WHEN wake_reason=4 THEN \'Monitored Address\''
509			' WHEN wake_reason=8 THEN \'HW\''
510			' ELSE wake_reason '
511		'END AS wake_reason'
512	' FROM pwrx'
513	' INNER JOIN samples ON samples.id = pwrx.id')
514
515do_query(query, 'CREATE VIEW power_events_view AS '
516	'SELECT '
517		'samples.id,'
518		'time,'
519		'cpu,'
520		'selected_events.name AS event,'
521		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT cbr FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS cbr,'
522		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT mhz FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS mhz,'
523		'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT percent FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS percent,'
524		'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('hints') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS hints_hex,'
525		'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('extensions') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS extensions_hex,'
526		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT cstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS cstate,'
527		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT subcstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS subcstate,'
528		'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT hw FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS hw,'
529		'CASE WHEN selected_events.name=\'exstop\' THEN (SELECT exact_ip FROM exstop WHERE exstop.id = samples.id) ELSE "" END AS exact_ip,'
530		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT deepest_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS deepest_cstate,'
531		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT last_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS last_cstate,'
532		'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT '
533			'CASE     WHEN wake_reason=1 THEN \'Interrupt\''
534				' WHEN wake_reason=2 THEN \'Timer Deadline\''
535				' WHEN wake_reason=4 THEN \'Monitored Address\''
536				' WHEN wake_reason=8 THEN \'HW\''
537				' ELSE wake_reason '
538			'END'
539		' FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS wake_reason'
540	' FROM samples'
541	' INNER JOIN selected_events ON selected_events.id = evsel_id'
542	' WHERE selected_events.name IN (\'cbr\',\'mwait\',\'exstop\',\'pwre\',\'pwrx\')')
543
544do_query(query, 'CREATE VIEW context_switches_view AS '
545	'SELECT '
546		'context_switches.id,'
547		'context_switches.machine_id,'
548		'context_switches.time,'
549		'context_switches.cpu,'
550		'th_out.pid AS pid_out,'
551		'th_out.tid AS tid_out,'
552		'comm_out.comm AS comm_out,'
553		'th_in.pid AS pid_in,'
554		'th_in.tid AS tid_in,'
555		'comm_in.comm AS comm_in,'
556		'CASE	  WHEN context_switches.flags = 0 THEN \'in\''
557			' WHEN context_switches.flags = 1 THEN \'out\''
558			' WHEN context_switches.flags = 3 THEN \'out preempt\''
559			' ELSE context_switches.flags '
560		'END AS flags'
561	' FROM context_switches'
562	' INNER JOIN threads AS th_out ON th_out.id   = context_switches.thread_out_id'
563	' INNER JOIN threads AS th_in  ON th_in.id    = context_switches.thread_in_id'
564	' INNER JOIN comms AS comm_out ON comm_out.id = context_switches.comm_out_id'
565	' INNER JOIN comms AS comm_in  ON comm_in.id  = context_switches.comm_in_id')
566
567do_query(query, 'END TRANSACTION')
568
569evsel_query = QSqlQuery(db)
570evsel_query.prepare("INSERT INTO selected_events VALUES (?, ?)")
571machine_query = QSqlQuery(db)
572machine_query.prepare("INSERT INTO machines VALUES (?, ?, ?)")
573thread_query = QSqlQuery(db)
574thread_query.prepare("INSERT INTO threads VALUES (?, ?, ?, ?, ?)")
575comm_query = QSqlQuery(db)
576comm_query.prepare("INSERT INTO comms VALUES (?, ?, ?, ?, ?)")
577comm_thread_query = QSqlQuery(db)
578comm_thread_query.prepare("INSERT INTO comm_threads VALUES (?, ?, ?)")
579dso_query = QSqlQuery(db)
580dso_query.prepare("INSERT INTO dsos VALUES (?, ?, ?, ?, ?)")
581symbol_query = QSqlQuery(db)
582symbol_query.prepare("INSERT INTO symbols VALUES (?, ?, ?, ?, ?, ?)")
583branch_type_query = QSqlQuery(db)
584branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)")
585sample_query = QSqlQuery(db)
586if branches:
587	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
588else:
589	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
590if perf_db_export_calls or perf_db_export_callchains:
591	call_path_query = QSqlQuery(db)
592	call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)")
593if perf_db_export_calls:
594	call_query = QSqlQuery(db)
595	call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
596ptwrite_query = QSqlQuery(db)
597ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)")
598cbr_query = QSqlQuery(db)
599cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)")
600mwait_query = QSqlQuery(db)
601mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)")
602pwre_query = QSqlQuery(db)
603pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)")
604exstop_query = QSqlQuery(db)
605exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
606pwrx_query = QSqlQuery(db)
607pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
608context_switch_query = QSqlQuery(db)
609context_switch_query.prepare("INSERT INTO context_switches VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
610
611def trace_begin():
612	printdate("Writing records...")
613	do_query(query, 'BEGIN TRANSACTION')
614	# id == 0 means unknown.  It is easier to create records for them than replace the zeroes with NULLs
615	evsel_table(0, "unknown")
616	machine_table(0, 0, "unknown")
617	thread_table(0, 0, 0, -1, -1)
618	comm_table(0, "unknown", 0, 0, 0)
619	dso_table(0, 0, "unknown", "unknown", "")
620	symbol_table(0, 0, 0, 0, 0, "unknown")
621	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)
622	if perf_db_export_calls or perf_db_export_callchains:
623		call_path_table(0, 0, 0, 0)
624		call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
625
626unhandled_count = 0
627
628def is_table_empty(table_name):
629	do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
630	if query.next():
631		return False
632	return True
633
634def drop(table_name):
635	do_query(query, 'DROP VIEW ' + table_name + '_view');
636	do_query(query, 'DROP TABLE ' + table_name);
637
638def trace_end():
639	do_query(query, 'END TRANSACTION')
640
641	printdate("Adding indexes")
642	if perf_db_export_calls:
643		do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
644		do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
645		do_query(query, 'ALTER TABLE comms ADD has_calls boolean')
646		do_query(query, 'UPDATE comms SET has_calls = 1 WHERE comms.id IN (SELECT DISTINCT comm_id FROM calls)')
647
648	printdate("Dropping unused tables")
649	if is_table_empty("ptwrite"):
650		drop("ptwrite")
651	if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
652		do_query(query, 'DROP VIEW power_events_view');
653		drop("mwait")
654		drop("pwre")
655		drop("exstop")
656		drop("pwrx")
657		if is_table_empty("cbr"):
658			drop("cbr")
659	if is_table_empty("context_switches"):
660		drop("context_switches")
661
662	if (unhandled_count):
663		printdate("Warning: ", unhandled_count, " unhandled events")
664	printdate("Done")
665
666def trace_unhandled(event_name, context, event_fields_dict):
667	global unhandled_count
668	unhandled_count += 1
669
670def sched__sched_switch(*x):
671	pass
672
673def bind_exec(q, n, x):
674	for xx in x[0:n]:
675		q.addBindValue(str(xx))
676	do_query_(q)
677
678def evsel_table(*x):
679	bind_exec(evsel_query, 2, x)
680
681def machine_table(*x):
682	bind_exec(machine_query, 3, x)
683
684def thread_table(*x):
685	bind_exec(thread_query, 5, x)
686
687def comm_table(*x):
688	bind_exec(comm_query, 5, x)
689
690def comm_thread_table(*x):
691	bind_exec(comm_thread_query, 3, x)
692
693def dso_table(*x):
694	bind_exec(dso_query, 5, x)
695
696def symbol_table(*x):
697	bind_exec(symbol_query, 6, x)
698
699def branch_type_table(*x):
700	bind_exec(branch_type_query, 2, x)
701
702def sample_table(*x):
703	if branches:
704		for xx in x[0:15]:
705			sample_query.addBindValue(str(xx))
706		for xx in x[19:24]:
707			sample_query.addBindValue(str(xx))
708		do_query_(sample_query)
709	else:
710		bind_exec(sample_query, 24, x)
711
712def call_path_table(*x):
713	bind_exec(call_path_query, 4, x)
714
715def call_return_table(*x):
716	bind_exec(call_query, 14, x)
717
718def ptwrite(id, raw_buf):
719	data = struct.unpack_from("<IQ", raw_buf)
720	flags = data[0]
721	payload = data[1]
722	exact_ip = flags & 1
723	ptwrite_query.addBindValue(str(id))
724	ptwrite_query.addBindValue(str(payload))
725	ptwrite_query.addBindValue(str(exact_ip))
726	do_query_(ptwrite_query)
727
728def cbr(id, raw_buf):
729	data = struct.unpack_from("<BBBBII", raw_buf)
730	cbr = data[0]
731	MHz = (data[4] + 500) / 1000
732	percent = ((cbr * 1000 / data[2]) + 5) / 10
733	cbr_query.addBindValue(str(id))
734	cbr_query.addBindValue(str(cbr))
735	cbr_query.addBindValue(str(MHz))
736	cbr_query.addBindValue(str(percent))
737	do_query_(cbr_query)
738
739def mwait(id, raw_buf):
740	data = struct.unpack_from("<IQ", raw_buf)
741	payload = data[1]
742	hints = payload & 0xff
743	extensions = (payload >> 32) & 0x3
744	mwait_query.addBindValue(str(id))
745	mwait_query.addBindValue(str(hints))
746	mwait_query.addBindValue(str(extensions))
747	do_query_(mwait_query)
748
749def pwre(id, raw_buf):
750	data = struct.unpack_from("<IQ", raw_buf)
751	payload = data[1]
752	hw = (payload >> 7) & 1
753	cstate = (payload >> 12) & 0xf
754	subcstate = (payload >> 8) & 0xf
755	pwre_query.addBindValue(str(id))
756	pwre_query.addBindValue(str(cstate))
757	pwre_query.addBindValue(str(subcstate))
758	pwre_query.addBindValue(str(hw))
759	do_query_(pwre_query)
760
761def exstop(id, raw_buf):
762	data = struct.unpack_from("<I", raw_buf)
763	flags = data[0]
764	exact_ip = flags & 1
765	exstop_query.addBindValue(str(id))
766	exstop_query.addBindValue(str(exact_ip))
767	do_query_(exstop_query)
768
769def pwrx(id, raw_buf):
770	data = struct.unpack_from("<IQ", raw_buf)
771	payload = data[1]
772	deepest_cstate = payload & 0xf
773	last_cstate = (payload >> 4) & 0xf
774	wake_reason = (payload >> 8) & 0xf
775	pwrx_query.addBindValue(str(id))
776	pwrx_query.addBindValue(str(deepest_cstate))
777	pwrx_query.addBindValue(str(last_cstate))
778	pwrx_query.addBindValue(str(wake_reason))
779	do_query_(pwrx_query)
780
781def synth_data(id, config, raw_buf, *x):
782	if config == 0:
783		ptwrite(id, raw_buf)
784	elif config == 1:
785		mwait(id, raw_buf)
786	elif config == 2:
787		pwre(id, raw_buf)
788	elif config == 3:
789		exstop(id, raw_buf)
790	elif config == 4:
791		pwrx(id, raw_buf)
792	elif config == 5:
793		cbr(id, raw_buf)
794
795def context_switch_table(*x):
796	bind_exec(context_switch_query, 9, x)
v6.2
  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
 13from __future__ import print_function
 14
 15import os
 16import sys
 17import struct
 18import 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
 72pyside_version_1 = True
 73if not "pyside-version-1" in sys.argv:
 74	try:
 75		from PySide2.QtSql import *
 76		pyside_version_1 = False
 77	except:
 78		pass
 79
 80if pyside_version_1:
 81	from PySide.QtSql import *
 82
 83sys.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
 90perf_db_export_mode = True
 91perf_db_export_calls = False
 92perf_db_export_callchains = False
 93
 94def printerr(*args, **keyword_args):
 95	print(*args, file=sys.stderr, **keyword_args)
 96
 97def printdate(*args, **kw_args):
 98        print(datetime.datetime.today(), *args, sep=' ', **kw_args)
 99
100def 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
108if (len(sys.argv) < 2):
109	usage()
110
111dbname = sys.argv[1]
112
113if (len(sys.argv) >= 3):
114	columns = sys.argv[2]
115else:
116	columns = "all"
117
118if columns not in ("all", "branches"):
119	usage()
120
121branches = (columns == "branches")
122
123for 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
133def do_query(q, s):
134	if (q.exec_(s)):
135		return
136	raise Exception("Query failed: " + q.lastError().text())
137
138def do_query_(q):
139	if (q.exec_()):
140		return
141	raise Exception("Query failed: " + q.lastError().text())
142
143printdate("Creating database ...")
144
145db_exists = False
146try:
147	f = open(dbname)
148	f.close()
149	db_exists = True
150except:
151	pass
152
153if db_exists:
154	raise Exception(dbname + " already exists")
155
156db = QSqlDatabase.addDatabase('QSQLITE')
157db.setDatabaseName(dbname)
158db.open()
159
160query = QSqlQuery(db)
161
162do_query(query, 'PRAGMA journal_mode = OFF')
163do_query(query, 'BEGIN TRANSACTION')
164
165do_query(query, 'CREATE TABLE selected_events ('
166		'id		integer		NOT NULL	PRIMARY KEY,'
167		'name		varchar(80))')
168do_query(query, 'CREATE TABLE machines ('
169		'id		integer		NOT NULL	PRIMARY KEY,'
170		'pid		integer,'
171		'root_dir 	varchar(4096))')
172do_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)')
178do_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)')
184do_query(query, 'CREATE TABLE comm_threads ('
185		'id		integer		NOT NULL	PRIMARY KEY,'
186		'comm_id	bigint,'
187		'thread_id	bigint)')
188do_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))')
194do_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))')
201do_query(query, 'CREATE TABLE branch_types ('
202		'id		integer		NOT NULL	PRIMARY KEY,'
203		'name		varchar(80))')
204
205if 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)')
228else:
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
256if 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)')
262if 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
279do_query(query, 'CREATE TABLE ptwrite ('
280		'id		integer		NOT NULL	PRIMARY KEY,'
281		'payload	bigint,'
282		'exact_ip	integer)')
283
284do_query(query, 'CREATE TABLE cbr ('
285		'id		integer		NOT NULL	PRIMARY KEY,'
286		'cbr		integer,'
287		'mhz		integer,'
288		'percent	integer)')
289
290do_query(query, 'CREATE TABLE mwait ('
291		'id		integer		NOT NULL	PRIMARY KEY,'
292		'hints		integer,'
293		'extensions	integer)')
294
295do_query(query, 'CREATE TABLE pwre ('
296		'id		integer		NOT NULL	PRIMARY KEY,'
297		'cstate		integer,'
298		'subcstate	integer,'
299		'hw		integer)')
300
301do_query(query, 'CREATE TABLE exstop ('
302		'id		integer		NOT NULL	PRIMARY KEY,'
303		'exact_ip	integer)')
304
305do_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
311do_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
323sqlite_has_printf = False
324try:
325	do_query(query, 'SELECT printf("") FROM machines')
326	sqlite_has_printf = True
327except:
328	pass
329
330def emit_to_hex(x):
331	if sqlite_has_printf:
332		return 'printf("%x", ' + x + ')'
333	else:
334		return x
335
336do_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
344do_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
354do_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
365do_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
375do_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
384if 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')
400if 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
426do_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
451do_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
461do_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
472do_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
482do_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
493do_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
502do_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
518do_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
547do_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
570do_query(query, 'END TRANSACTION')
571
572evsel_query = QSqlQuery(db)
573evsel_query.prepare("INSERT INTO selected_events VALUES (?, ?)")
574machine_query = QSqlQuery(db)
575machine_query.prepare("INSERT INTO machines VALUES (?, ?, ?)")
576thread_query = QSqlQuery(db)
577thread_query.prepare("INSERT INTO threads VALUES (?, ?, ?, ?, ?)")
578comm_query = QSqlQuery(db)
579comm_query.prepare("INSERT INTO comms VALUES (?, ?, ?, ?, ?)")
580comm_thread_query = QSqlQuery(db)
581comm_thread_query.prepare("INSERT INTO comm_threads VALUES (?, ?, ?)")
582dso_query = QSqlQuery(db)
583dso_query.prepare("INSERT INTO dsos VALUES (?, ?, ?, ?, ?)")
584symbol_query = QSqlQuery(db)
585symbol_query.prepare("INSERT INTO symbols VALUES (?, ?, ?, ?, ?, ?)")
586branch_type_query = QSqlQuery(db)
587branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)")
588sample_query = QSqlQuery(db)
589if branches:
590	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
591else:
592	sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
593if 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 (?, ?, ?, ?)")
596if perf_db_export_calls:
597	call_query = QSqlQuery(db)
598	call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
599ptwrite_query = QSqlQuery(db)
600ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)")
601cbr_query = QSqlQuery(db)
602cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)")
603mwait_query = QSqlQuery(db)
604mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)")
605pwre_query = QSqlQuery(db)
606pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)")
607exstop_query = QSqlQuery(db)
608exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
609pwrx_query = QSqlQuery(db)
610pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
611context_switch_query = QSqlQuery(db)
612context_switch_query.prepare("INSERT INTO context_switches VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
613
614def 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
629unhandled_count = 0
630
631def 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
637def drop(table_name):
638	do_query(query, 'DROP VIEW ' + table_name + '_view');
639	do_query(query, 'DROP TABLE ' + table_name);
640
641def 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
669def trace_unhandled(event_name, context, event_fields_dict):
670	global unhandled_count
671	unhandled_count += 1
672
673def sched__sched_switch(*x):
674	pass
675
676def bind_exec(q, n, x):
677	for xx in x[0:n]:
678		q.addBindValue(str(xx))
679	do_query_(q)
680
681def evsel_table(*x):
682	bind_exec(evsel_query, 2, x)
683
684def machine_table(*x):
685	bind_exec(machine_query, 3, x)
686
687def thread_table(*x):
688	bind_exec(thread_query, 5, x)
689
690def comm_table(*x):
691	bind_exec(comm_query, 5, x)
692
693def comm_thread_table(*x):
694	bind_exec(comm_thread_query, 3, x)
695
696def dso_table(*x):
697	bind_exec(dso_query, 5, x)
698
699def symbol_table(*x):
700	bind_exec(symbol_query, 6, x)
701
702def branch_type_table(*x):
703	bind_exec(branch_type_query, 2, x)
704
705def 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
715def call_path_table(*x):
716	bind_exec(call_path_query, 4, x)
717
718def call_return_table(*x):
719	bind_exec(call_query, 14, x)
720
721def 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
731def 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
742def 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
752def 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
764def 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
772def 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
784def 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
798def context_switch_table(*x):
799	bind_exec(context_switch_query, 9, x)