Export cycle and instruction counts on samples and calls tables. Committer testing: First runs some workload collecting intel_pt with the 'cyc' ter just for userspace: [root@quaco adrian.hunter]# perf record -o simple-retpoline.perf.data -e intel_pt/cyc/u ./simple-retpoline [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.035 MB simple-retpoline.perf.data ] [root@quaco adrian.hunter]# Then use the export-to-sqlite.py script to see if the changes in this cset don't make it to break and if the changes in the db schema are the ones expected: [root@quaco adrian.hunter]# perf script -i simple-retpoline.perf.data --itrace=be -s ~acme/libexec/perf-core/scripts/python/export-to-sqlite.py simple-retpoline.db branches calls 2019-05-31 11:50:46.942710 Creating database ... 2019-05-31 11:50:46.949663 Writing records... 2019-05-31 11:50:47.224033 Adding indexes 2019-05-31 11:50:47.231599 Done [root@quaco adrian.hunter]# Now lets use the db: [root@quaco adrian.hunter]# sqlite3 simple-retpoline.db SQLite version 3.26.0 2018-12-01 12:34:55 Enter ".help" for usage hints. sqlite> .schema samples CREATE TABLE samples (id integer NOT NULL PRIMARY KEY,evsel_id bigint,machine_id bigint,thread_id bigint,comm_id bigint,dso_id bigint,symbol_id bigint,sym_offset bigint,ip bigint,time bigint,cpuinteger,to_dso_id bigint,to_symbol_id bigint,to_sym_offset bigint,to_ip bigint,branch_type integer,in_tx boolean,call_path_id bigint,insn_count bigint,cyc_count bigint); sqlite> Cool, the 'insn_count' and 'cyc_count' are there, now lets see if we can use them in a query: sqlite> select insn_count,cyc_count from samples where cyc_count > 1500 and insn_count < 10; 6|1507 sqlite> select insn_count,cyc_count from samples where cyc_count > 1500; 118|2210 140|1516 3783|1861 132|1521 6|1507 sqlite> Seems to work :-)
Showing the changes to tools/perf/scripts/python/export-to-sqlite.py (1 of 1 file). Show all
Unified · Split
| @@ -218,7 +218,9 @@ if branches: · 217 unmodified lines | ||
| 218 | 218 | 'to_ip bigint,' |
| 219 | 219 | 'branch_type integer,' |
| 220 | 220 | 'in_tx boolean,' |
| 221 | − 'call_path_id bigint)') | |
| 221 | + 'call_path_id bigint,' | |
| 222 | + 'insn_count bigint,' | |
| 223 | + 'cyc_count bigint)') | |
| 222 | 224 | else: |
| 223 | 225 | do_query(query, 'CREATE TABLE samples (' |
| 224 | 226 | 'id integer NOT NULL PRIMARY KEY,' |
| @@ -242,7 +244,9 @@ else: · 17 unmodified lines | ||
| 242 | 244 | 'data_src bigint,' |
| 243 | 245 | 'branch_type integer,' |
| 244 | 246 | 'in_tx boolean,' |
| 245 | − 'call_path_id bigint)') | |
| 247 | + 'call_path_id bigint,' | |
| 248 | + 'insn_count bigint,' | |
| 249 | + 'cyc_count bigint)') | |
| 246 | 250 | |
| 247 | 251 | if perf_db_export_calls or perf_db_export_callchains: |
| 248 | 252 | do_query(query, 'CREATE TABLE call_paths (' |
| @@ -263,7 +267,9 @@ if perf_db_export_calls: · 14 unmodified lines | ||
| 263 | 267 | 'return_id bigint,' |
| 264 | 268 | 'parent_call_path_id bigint,' |
| 265 | 269 | 'flags integer,' |
| 266 | − 'parent_id bigint)') | |
| 270 | + 'parent_id bigint,' | |
| 271 | + 'insn_count bigint,' | |
| 272 | + 'cyc_count bigint)') | |
| 267 | 273 | |
| 268 | 274 | # printf was added to sqlite in version 3.8.3 |
| 269 | 275 | sqlite_has_printf = False |
| @@ -359,6 +365,9 @@ if perf_db_export_calls: · 89 unmodified lines | ||
| 359 | 365 | 'return_time,' |
| 360 | 366 | 'return_time - call_time AS elapsed_time,' |
| 361 | 367 | 'branch_count,' |
| 368 | + 'insn_count,' | |
| 369 | + 'cyc_count,' | |
| 370 | + 'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC,' | |
| 362 | 371 | 'call_id,' |
| 363 | 372 | 'return_id,' |
| 364 | 373 | '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,' |
| @@ -384,7 +393,10 @@ do_query(query, 'CREATE VIEW samples_view AS ' · 19 unmodified lines | ||
| 384 | 393 | 'to_sym_offset,' |
| 385 | 394 | '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,' |
| 386 | 395 | '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,' |
| 387 | − 'in_tx' | |
| 396 | + 'in_tx,' | |
| 397 | + 'insn_count,' | |
| 398 | + 'cyc_count,' | |
| 399 | + 'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC' | |
| 388 | 400 | ' FROM samples') |
| 389 | 401 | |
| 390 | 402 | do_query(query, 'END TRANSACTION') |
| @@ -407,15 +419,15 @@ branch_type_query = QSqlQuery(db) · 16 unmodified lines | ||
| 407 | 419 | branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)") |
| 408 | 420 | sample_query = QSqlQuery(db) |
| 409 | 421 | if branches: |
| 410 | − sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 422 | + sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 411 | 423 | else: |
| 412 | − sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 424 | + sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 413 | 425 | if perf_db_export_calls or perf_db_export_callchains: |
| 414 | 426 | call_path_query = QSqlQuery(db) |
| 415 | 427 | call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)") |
| 416 | 428 | if perf_db_export_calls: |
| 417 | 429 | call_query = QSqlQuery(db) |
| 418 | − call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 430 | + call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | |
| 419 | 431 | |
| 420 | 432 | def trace_begin(): |
| 421 | 433 | printdate("Writing records...") |
| @@ -427,10 +439,10 @@ def trace_begin(): · 5 unmodified lines | ||
| 427 | 439 | comm_table(0, "unknown") |
| 428 | 440 | dso_table(0, 0, "unknown", "unknown", "") |
| 429 | 441 | symbol_table(0, 0, 0, 0, 0, "unknown") |
| 430 | − sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 442 | + 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) | |
| 431 | 443 | if perf_db_export_calls or perf_db_export_callchains: |
| 432 | 444 | call_path_table(0, 0, 0, 0) |
| 433 | − call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 445 | + call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
| 434 | 446 | |
| 435 | 447 | unhandled_count = 0 |
| 436 | 448 | |
| @@ -486,14 +498,14 @@ def sample_table(*x): · 49 unmodified lines | ||
| 486 | 498 | if branches: |
| 487 | 499 | for xx in x[0:15]: |
| 488 | 500 | sample_query.addBindValue(str(xx)) |
| 489 | − for xx in x[19:22]: | |
| 501 | + for xx in x[19:24]: | |
| 490 | 502 | sample_query.addBindValue(str(xx)) |
| 491 | 503 | do_query_(sample_query) |
| 492 | 504 | else: |
| 493 | − bind_exec(sample_query, 22, x) | |
| 505 | + bind_exec(sample_query, 24, x) | |
| 494 | 506 | |
| 495 | 507 | def call_path_table(*x): |
| 496 | 508 | bind_exec(call_path_query, 4, x) |
| 497 | 509 | |
| 498 | 510 | def call_return_table(*x): |
| 499 | − bind_exec(call_query, 12, x) | |
| 511 | + bind_exec(call_query, 14, x) | |