Add some comments to the script and some 'views' to the created database that better illustrate the database structure and how it can be used.
Showing the changes to tools/perf/scripts/python/export-to-postgresql.py (1 of 1 file). Show all
Unified · Split
| @@ -61,6 +61,142 @@ import datetime · 60 unmodified lines | ||
| 61 | 61 | # |
| 62 | 62 | # An example of using the database is provided by the script |
| 63 | 63 | # call-graph-from-postgresql.py. Refer to that script for details. |
| 64 | +# | |
| 65 | +# Tables: | |
| 66 | +# | |
| 67 | +# The tables largely correspond to perf tools' data structures. They are largely self-explanatory. | |
| 68 | +# | |
| 69 | +# samples | |
| 70 | +# | |
| 71 | +# 'samples' is the main table. It represents what instruction was executing at a point in time | |
| 72 | +# when something (a selected event) happened. The memory address is the instruction pointer or 'ip'. | |
| 73 | +# | |
| 74 | +# calls | |
| 75 | +# | |
| 76 | +# 'calls' represents function calls and is related to 'samples' by 'call_id' and 'return_id'. | |
| 77 | +# 'calls' is only created when the 'calls' option to this script is specified. | |
| 78 | +# | |
| 79 | +# call_paths | |
| 80 | +# | |
| 81 | +# 'call_paths' represents all the call stacks. Each 'call' has an associated record in 'call_paths'. | |
| 82 | +# 'calls_paths' is only created when the 'calls' option to this script is specified. | |
| 83 | +# | |
| 84 | +# branch_types | |
| 85 | +# | |
| 86 | +# 'branch_types' provides descriptions for each type of branch. | |
| 87 | +# | |
| 88 | +# comm_threads | |
| 89 | +# | |
| 90 | +# 'comm_threads' shows how 'comms' relates to 'threads'. | |
| 91 | +# | |
| 92 | +# comms | |
| 93 | +# | |
| 94 | +# 'comms' contains a record for each 'comm' - the name given to the executable that is running. | |
| 95 | +# | |
| 96 | +# dsos | |
| 97 | +# | |
| 98 | +# 'dsos' contains a record for each executable file or library. | |
| 99 | +# | |
| 100 | +# machines | |
| 101 | +# | |
| 102 | +# 'machines' can be used to distinguish virtual machines if virtualization is supported. | |
| 103 | +# | |
| 104 | +# selected_events | |
| 105 | +# | |
| 106 | +# 'selected_events' contains a record for each kind of event that has been sampled. | |
| 107 | +# | |
| 108 | +# symbols | |
| 109 | +# | |
| 110 | +# 'symbols' contains a record for each symbol. Only symbols that have samples are present. | |
| 111 | +# | |
| 112 | +# threads | |
| 113 | +# | |
| 114 | +# 'threads' contains a record for each thread. | |
| 115 | +# | |
| 116 | +# Views: | |
| 117 | +# | |
| 118 | +# Most of the tables have views for more friendly display. The views are: | |
| 119 | +# | |
| 120 | +# calls_view | |
| 121 | +# call_paths_view | |
| 122 | +# comm_threads_view | |
| 123 | +# dsos_view | |
| 124 | +# machines_view | |
| 125 | +# samples_view | |
| 126 | +# symbols_view | |
| 127 | +# threads_view | |
| 128 | +# | |
| 129 | +# More examples of browsing the database with psql: | |
| 130 | +# Note that some of the examples are not the most optimal SQL query. | |
| 131 | +# Note that call information is only available if the script's 'calls' option has been used. | |
| 132 | +# | |
| 133 | +# Top 10 function calls (not aggregated by symbol): | |
| 134 | +# | |
| 135 | +# SELECT * FROM calls_view ORDER BY elapsed_time DESC LIMIT 10; | |
| 136 | +# | |
| 137 | +# Top 10 function calls (aggregated by symbol): | |
| 138 | +# | |
| 139 | +# SELECT symbol_id,(SELECT name FROM symbols WHERE id = symbol_id) AS symbol, | |
| 140 | +# SUM(elapsed_time) AS tot_elapsed_time,SUM(branch_count) AS tot_branch_count | |
| 141 | +# FROM calls_view GROUP BY symbol_id ORDER BY tot_elapsed_time DESC LIMIT 10; | |
| 142 | +# | |
| 143 | +# Note that the branch count gives a rough estimation of cpu usage, so functions | |
| 144 | +# that took a long time but have a relatively low branch count must have spent time | |
| 145 | +# waiting. | |
| 146 | +# | |
| 147 | +# Find symbols by pattern matching on part of the name (e.g. names containing 'alloc'): | |
| 148 | +# | |
| 149 | +# SELECT * FROM symbols_view WHERE name LIKE '%alloc%'; | |
| 150 | +# | |
| 151 | +# Top 10 function calls for a specific symbol (e.g. whose symbol_id is 187): | |
| 152 | +# | |
| 153 | +# SELECT * FROM calls_view WHERE symbol_id = 187 ORDER BY elapsed_time DESC LIMIT 10; | |
| 154 | +# | |
| 155 | +# Show function calls made by function in the same context (i.e. same call path) (e.g. one with call_path_id 254): | |
| 156 | +# | |
| 157 | +# SELECT * FROM calls_view WHERE parent_call_path_id = 254; | |
| 158 | +# | |
| 159 | +# Show branches made during a function call (e.g. where call_id is 29357 and return_id is 29370 and tid is 29670) | |
| 160 | +# | |
| 161 | +# SELECT * FROM samples_view WHERE id >= 29357 AND id <= 29370 AND tid = 29670 AND event LIKE 'branches%'; | |
| 162 | +# | |
| 163 | +# Show transactions: | |
| 164 | +# | |
| 165 | +# SELECT * FROM samples_view WHERE event = 'transactions'; | |
| 166 | +# | |
| 167 | +# Note transaction start has 'in_tx' true whereas, transaction end has 'in_tx' false. | |
| 168 | +# Transaction aborts have branch_type_name 'transaction abort' | |
| 169 | +# | |
| 170 | +# Show transaction aborts: | |
| 171 | +# | |
| 172 | +# SELECT * FROM samples_view WHERE event = 'transactions' AND branch_type_name = 'transaction abort'; | |
| 173 | +# | |
| 174 | +# To print a call stack requires walking the call_paths table. For example this python script: | |
| 175 | +# #!/usr/bin/python2 | |
| 176 | +# | |
| 177 | +# import sys | |
| 178 | +# from PySide.QtSql import * | |
| 179 | +# | |
| 180 | +# if __name__ == '__main__': | |
| 181 | +# if (len(sys.argv) < 3): | |
| 182 | +# print >> sys.stderr, "Usage is: printcallstack.py <database name> <call_path_id>" | |
| 183 | +# raise Exception("Too few arguments") | |
| 184 | +# dbname = sys.argv[1] | |
| 185 | +# call_path_id = sys.argv[2] | |
| 186 | +# db = QSqlDatabase.addDatabase('QPSQL') | |
| 187 | +# db.setDatabaseName(dbname) | |
| 188 | +# if not db.open(): | |
| 189 | +# raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) | |
| 190 | +# query = QSqlQuery(db) | |
| 191 | +# print " id ip symbol_id symbol dso_id dso_short_name" | |
| 192 | +# while call_path_id != 0 and call_path_id != 1: | |
| 193 | +# ret = query.exec_('SELECT * FROM call_paths_view WHERE id = ' + str(call_path_id)) | |
| 194 | +# if not ret: | |
| 195 | +# raise Exception("Query failed: " + query.lastError().text()) | |
| 196 | +# if not query.next(): | |
| 197 | +# raise Exception("Query failed") | |
| 198 | +# print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5)) | |
| 199 | +# call_path_id = query.value(6) | |
| 64 | 200 | |
| 65 | 201 | from PySide.QtSql import * |
| 66 | 202 | |
| @@ -244,6 +380,91 @@ if perf_db_export_calls: · 177 unmodified lines | ||
| 244 | 380 | 'parent_call_path_id bigint,' |
| 245 | 381 | 'flags integer)') |
| 246 | 382 | |
| 383 | +do_query(query, 'CREATE VIEW machines_view AS ' | |
| 384 | + 'SELECT ' | |
| 385 | + 'id,' | |
| 386 | + 'pid,' | |
| 387 | + 'root_dir,' | |
| 388 | + 'CASE WHEN id=0 THEN \'unknown\' WHEN pid=-1 THEN \'host\' ELSE \'guest\' END AS host_or_guest' | |
| 389 | + ' FROM machines') | |
| 390 | + | |
| 391 | +do_query(query, 'CREATE VIEW dsos_view AS ' | |
| 392 | + 'SELECT ' | |
| 393 | + 'id,' | |
| 394 | + 'machine_id,' | |
| 395 | + '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' | |
| 396 | + 'short_name,' | |
| 397 | + 'long_name,' | |
| 398 | + 'build_id' | |
| 399 | + ' FROM dsos') | |
| 400 | + | |
| 401 | +do_query(query, 'CREATE VIEW symbols_view AS ' | |
| 402 | + 'SELECT ' | |
| 403 | + 'id,' | |
| 404 | + 'name,' | |
| 405 | + '(SELECT short_name FROM dsos WHERE id=dso_id) AS dso,' | |
| 406 | + 'dso_id,' | |
| 407 | + 'sym_start,' | |
| 408 | + 'sym_end,' | |
| 409 | + 'CASE WHEN binding=0 THEN \'local\' WHEN binding=1 THEN \'global\' ELSE \'weak\' END AS binding' | |
| 410 | + ' FROM symbols') | |
| 411 | + | |
| 412 | +do_query(query, 'CREATE VIEW threads_view AS ' | |
| 413 | + 'SELECT ' | |
| 414 | + 'id,' | |
| 415 | + 'machine_id,' | |
| 416 | + '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' | |
| 417 | + 'process_id,' | |
| 418 | + 'pid,' | |
| 419 | + 'tid' | |
| 420 | + ' FROM threads') | |
| 421 | + | |
| 422 | +do_query(query, 'CREATE VIEW comm_threads_view AS ' | |
| 423 | + 'SELECT ' | |
| 424 | + 'comm_id,' | |
| 425 | + '(SELECT comm FROM comms WHERE id = comm_id) AS command,' | |
| 426 | + 'thread_id,' | |
| 427 | + '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' | |
| 428 | + '(SELECT tid FROM threads WHERE id = thread_id) AS tid' | |
| 429 | + ' FROM comm_threads') | |
| 430 | + | |
| 431 | +if perf_db_export_calls: | |
| 432 | + do_query(query, 'CREATE VIEW call_paths_view AS ' | |
| 433 | + 'SELECT ' | |
| 434 | + 'c.id,' | |
| 435 | + 'to_hex(c.ip) AS ip,' | |
| 436 | + 'c.symbol_id,' | |
| 437 | + '(SELECT name FROM symbols WHERE id = c.symbol_id) AS symbol,' | |
| 438 | + '(SELECT dso_id FROM symbols WHERE id = c.symbol_id) AS dso_id,' | |
| 439 | + '(SELECT dso FROM symbols_view WHERE id = c.symbol_id) AS dso_short_name,' | |
| 440 | + 'c.parent_id,' | |
| 441 | + 'to_hex(p.ip) AS parent_ip,' | |
| 442 | + 'p.symbol_id AS parent_symbol_id,' | |
| 443 | + '(SELECT name FROM symbols WHERE id = p.symbol_id) AS parent_symbol,' | |
| 444 | + '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' | |
| 445 | + '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' | |
| 446 | + ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') | |
| 447 | + do_query(query, 'CREATE VIEW calls_view AS ' | |
| 448 | + 'SELECT ' | |
| 449 | + 'calls.id,' | |
| 450 | + 'thread_id,' | |
| 451 | + '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' | |
| 452 | + '(SELECT tid FROM threads WHERE id = thread_id) AS tid,' | |
| 453 | + '(SELECT comm FROM comms WHERE id = comm_id) AS command,' | |
| 454 | + 'call_path_id,' | |
| 455 | + 'to_hex(ip) AS ip,' | |
| 456 | + 'symbol_id,' | |
| 457 | + '(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,' | |
| 458 | + 'call_time,' | |
| 459 | + 'return_time,' | |
| 460 | + 'return_time - call_time AS elapsed_time,' | |
| 461 | + 'branch_count,' | |
| 462 | + 'call_id,' | |
| 463 | + 'return_id,' | |
| 464 | + 'CASE WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' ELSE \'\' END AS flags,' | |
| 465 | + 'parent_call_path_id' | |
| 466 | + ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') | |
| 467 | + | |
| 247 | 468 | do_query(query, 'CREATE VIEW samples_view AS ' |
| 248 | 469 | 'SELECT ' |
| 249 | 470 | 'id,' |