1#!/usr/bin/env python3 2# Copyright (C) 2023 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License a 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from python.generators.diff_tests.testing import Path, DataPath, Metric 17from python.generators.diff_tests.testing import Csv, Json, TextProto 18from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector 19from python.generators.diff_tests.testing import TestSuite 20 21 22class Tables(TestSuite): 23 # Contains tests for the handling of tables by trace processor. The focus of 24 # here is to check that trace processor is correctly returning and handling 25 # on the really important tables in trace processor. Note: It's generally 26 # advisable to add tests here. Check the guidance provided by 27 # for choosing which folder to add a new test to. Window table 28 def test_android_sched_and_ps_smoke_window(self): 29 return DiffTestBlueprint( 30 trace=DataPath('android_sched_and_ps.pb'), 31 query=""" 32 SELECT * FROM "window"; 33 """, 34 out=Csv(""" 35 "ts","dur","quantum_ts" 36 0,9223372036854775807,0 37 """)) 38 39 def test_simple_interval_intersect_rev(self): 40 return DiffTestBlueprint( 41 trace=TextProto(""), 42 query=""" 43 44 CREATE PERFETTO TABLE A AS 45 WITH data(id, ts, ts_end, c0, c1) AS ( 46 VALUES 47 (0, 1, 7, 10, 3) 48 ) 49 SELECT * FROM data; 50 51 CREATE PERFETTO TABLE B AS 52 WITH data(id, ts, ts_end, c0, c2) AS ( 53 VALUES 54 (0, 0, 2, 10, 100), 55 (1, 3, 5, 10, 200), 56 (2, 6, 8, 20, 300) 57 ) 58 SELECT * FROM data; 59 60 SELECT a.id AS a_id, b.id AS b_id 61 FROM __intrinsic_ii_with_interval_tree('A', 'c0, c1') a 62 JOIN __intrinsic_ii_with_interval_tree('B', 'c0, c2') b 63 WHERE a.ts < b.ts_end AND a.ts_end > b.ts 64 """, 65 out=Csv(""" 66 "a_id","b_id" 67 0,1 68 0,0 69 0,2 70 """)) 71 72 def test_compare_with_ii_macro(self): 73 return DiffTestBlueprint( 74 trace=DataPath('example_android_trace_30s.pb'), 75 query=""" 76 INCLUDE PERFETTO MODULE intervals.intersect; 77 78 CREATE PERFETTO TABLE big_foo AS 79 SELECT 80 ts, 81 ts + dur as ts_end, 82 id * 10 AS id 83 FROM sched 84 WHERE utid == 1; 85 86 CREATE PERFETTO TABLE small_foo AS 87 SELECT 88 ts + 1000 AS ts, 89 ts + dur + 1000 AS ts_end, 90 id 91 FROM sched 92 WHERE utid == 1; 93 94 CREATE PERFETTO TABLE small_foo_for_ii AS 95 SELECT id, ts, ts_end - ts AS dur 96 FROM small_foo; 97 98 CREATE PERFETTO TABLE big_foo_for_ii AS 99 SELECT id, ts, ts_end - ts AS dur 100 FROM big_foo; 101 102 CREATE PERFETTO TABLE both AS 103 SELECT 104 left_id, 105 right_id, 106 cat, 107 count() AS c, 108 MAX(ts) AS max_ts, MAX(dur) AS max_dur 109 FROM ( 110 SELECT a.id AS left_id, b.id AS right_id, 0 AS ts, 0 AS dur, "it" AS cat 111 FROM __intrinsic_ii_with_interval_tree('big_foo', '') a 112 JOIN __intrinsic_ii_with_interval_tree('small_foo', '') b 113 WHERE a.ts < b.ts_end AND a.ts_end > b.ts 114 UNION 115 SELECT left_id, right_id, ts, dur, "ii" AS cat 116 FROM _interval_intersect!(big_foo_for_ii, small_foo_for_ii) 117 WHERE dur != 0 118 ) 119 GROUP BY left_id, right_id; 120 121 SELECT 122 SUM(c) FILTER (WHERE c == 2) AS good, 123 SUM(c) FILTER (WHERE c != 2) AS bad 124 FROM both; 125 """, 126 out=Csv(""" 127 "good","bad" 128 314,"[NULL]" 129 """)) 130 131 def test_compare_with_span_join(self): 132 return DiffTestBlueprint( 133 trace=DataPath('example_android_trace_30s.pb'), 134 query=""" 135 INCLUDE PERFETTO MODULE intervals.intersect; 136 137 CREATE PERFETTO TABLE big_foo AS 138 SELECT 139 ts, 140 ts + dur as ts_end, 141 id * 10 AS id, 142 cpu AS c0 143 FROM sched 144 WHERE dur != -1; 145 146 CREATE PERFETTO TABLE small_foo AS 147 SELECT 148 ts + 1000 AS ts, 149 ts + dur + 1000 AS ts_end, 150 id, 151 cpu AS c0 152 FROM sched 153 WHERE dur != -1; 154 155 CREATE PERFETTO TABLE small_foo_for_sj AS 156 SELECT 157 id AS small_id, 158 ts, 159 ts_end - ts AS dur, 160 c0 161 FROM small_foo 162 WHERE dur != 0; 163 164 CREATE PERFETTO TABLE big_foo_for_sj AS 165 SELECT 166 id AS big_id, 167 ts, 168 ts_end - ts AS dur, 169 c0 170 FROM big_foo 171 WHERE dur != 0; 172 173 CREATE VIRTUAL TABLE sj_res 174 USING SPAN_JOIN( 175 small_foo_for_sj PARTITIONED c0, 176 big_foo_for_sj PARTITIONED c0); 177 178 CREATE PERFETTO TABLE both AS 179 SELECT 180 left_id, 181 right_id, 182 cat, 183 count() AS c, 184 MAX(ts) AS max_ts, MAX(dur) AS max_dur 185 FROM ( 186 SELECT a.id AS left_id, b.id AS right_id, 0 AS ts, 0 AS dur, "it" AS cat 187 FROM __intrinsic_ii_with_interval_tree('big_foo', 'c0') a 188 JOIN __intrinsic_ii_with_interval_tree('small_foo', 'c0') b 189 USING (c0) 190 WHERE a.ts < b.ts_end AND a.ts_end > b.ts 191 UNION 192 SELECT big_id AS left_id, small_id AS right_id, ts, dur, "sj" AS cat FROM sj_res 193 ) 194 GROUP BY left_id, right_id; 195 196 SELECT 197 SUM(c) FILTER (WHERE c == 2) AS good, 198 SUM(c) FILTER (WHERE c != 2) AS bad 199 FROM both; 200 """, 201 out=Csv(""" 202 "good","bad" 203 1538288,"[NULL]" 204 """)) 205 206 def test_ii_partitioned_big(self): 207 return DiffTestBlueprint( 208 trace=DataPath('example_android_trace_30s.pb'), 209 query=""" 210 INCLUDE PERFETTO MODULE intervals.intersect; 211 212 CREATE PERFETTO TABLE big_foo AS 213 SELECT 214 ts, 215 ts + dur as ts_end, 216 id * 10 AS id, 217 cpu AS c0 218 FROM sched 219 WHERE dur != -1; 220 221 CREATE PERFETTO TABLE small_foo AS 222 SELECT 223 ts + 1000 AS ts, 224 ts + dur + 1000 AS ts_end, 225 id, 226 cpu AS c0 227 FROM sched 228 WHERE dur != -1; 229 230 CREATE PERFETTO TABLE res AS 231 SELECT a.id AS a_id, b.id AS b_id 232 FROM __intrinsic_ii_with_interval_tree('small_foo', 'c0') a 233 JOIN __intrinsic_ii_with_interval_tree('big_foo', 'c0') b 234 USING (c0) 235 WHERE a.ts < b.ts_end AND a.ts_end > b.ts; 236 237 SELECT * FROM res 238 ORDER BY a_id, b_id 239 LIMIT 10; 240 """, 241 out=Csv(""" 242 "a_id","b_id" 243 0,0 244 0,10 245 1,10 246 1,430 247 2,20 248 2,30 249 3,30 250 3,40 251 4,40 252 4,50 253 """)) 254 255 256 def test_ii_operator_big(self): 257 return DiffTestBlueprint( 258 trace=DataPath('example_android_trace_30s.pb'), 259 query=""" 260 CREATE PERFETTO TABLE big_foo AS 261 SELECT 262 id, 263 ts, 264 ts+dur AS ts_end 265 FROM sched 266 WHERE dur != -1 267 ORDER BY ts; 268 269 CREATE PERFETTO TABLE small_foo AS 270 SELECT 271 id * 10 AS id, 272 ts + 1000 AS ts, 273 ts_end + 1000 AS ts_end 274 FROM big_foo 275 LIMIT 10 276 OFFSET 5; 277 278 CREATE PERFETTO TABLE res AS 279 SELECT a.id AS a_id, b.id AS b_id 280 FROM __intrinsic_ii_with_interval_tree('small_foo', '') a 281 JOIN __intrinsic_ii_with_interval_tree('big_foo', '') b 282 WHERE a.ts < b.ts_end AND a.ts_end > b.ts; 283 284 SELECT * FROM res 285 ORDER BY a_id, b_id 286 LIMIT 10; 287 """, 288 out=Csv(""" 289 "a_id","b_id" 290 50,1 291 50,5 292 50,6 293 60,1 294 60,6 295 60,7 296 60,8 297 70,1 298 70,6 299 70,7 300 """)) 301 302 # Null printing 303 def test_nulls(self): 304 return DiffTestBlueprint( 305 trace=Path('../common/synth_1.py'), 306 query=""" 307 CREATE TABLE null_test ( 308 primary_key INTEGER PRIMARY KEY, 309 int_nulls INTEGER, 310 string_nulls STRING, 311 double_nulls DOUBLE, 312 start_int_nulls INTEGER, 313 start_string_nulls STRING, 314 start_double_nulls DOUBLE, 315 all_nulls INTEGER 316 ); 317 318 INSERT INTO null_test( 319 int_nulls, 320 string_nulls, 321 double_nulls, 322 start_int_nulls, 323 start_string_nulls, 324 start_double_nulls 325 ) 326 VALUES 327 (1, "test", 2.0, NULL, NULL, NULL), 328 (2, NULL, NULL, NULL, "test", NULL), 329 (1, "other", NULL, NULL, NULL, NULL), 330 (4, NULL, NULL, NULL, NULL, 1.0), 331 (NULL, "test", 1.0, 1, NULL, NULL); 332 333 SELECT * FROM null_test; 334 """, 335 out=Path('nulls.out')) 336 337 # Thread table 338 def test_thread_main_thread(self): 339 return DiffTestBlueprint( 340 trace=TextProto(r""" 341 packet { 342 timestamp: 1 343 process_tree { 344 processes { 345 pid: 5 346 ppid: 1 347 cmdline: "com.google.pid5" 348 } 349 threads { 350 tid: 5 351 tgid: 5 352 } 353 threads { 354 tid: 7 355 tgid: 5 356 name: "tid7" 357 } 358 processes { 359 pid: 11 360 ppid: 1 361 cmdline: "com.google.pid11" 362 } 363 threads { 364 tid: 11 365 tgid: 11 366 name: "tid11" 367 } 368 threads { 369 tid: 12 370 tgid: 11 371 name: "tid12" 372 } 373 } 374 } 375 packet { 376 timestamp: 2 377 ftrace_events { 378 cpu: 0 379 event { 380 timestamp: 2 381 pid: 99 382 lowmemory_kill { 383 pid: 99 384 } 385 } 386 } 387 } 388 """), 389 query=""" 390 SELECT 391 tid, 392 is_main_thread 393 FROM thread 394 WHERE tid IN (5, 7, 11, 12, 99) 395 ORDER BY tid; 396 """, 397 out=Csv(""" 398 "tid","is_main_thread" 399 5,1 400 7,0 401 11,1 402 12,0 403 99,"[NULL]" 404 """)) 405 406 # Json output 407 def test_trace_metadata(self): 408 return DiffTestBlueprint( 409 trace=DataPath('memory_counters.pb'), 410 query=Metric('trace_metadata'), 411 out=Path('trace_metadata.json.out')) 412 413 # Processes as a metric 414 def test_android_task_names(self): 415 return DiffTestBlueprint( 416 trace=TextProto(r""" 417 packet { 418 process_tree { 419 processes { 420 pid: 1 421 ppid: 0 422 cmdline: "init" 423 uid: 0 424 } 425 processes { 426 pid: 2 427 ppid: 1 428 cmdline: "com.google.android.gm:process" 429 uid: 10001 430 } 431 } 432 } 433 packet { 434 packages_list { 435 packages { 436 name: "com.google.android.gm" 437 uid: 10001 438 } 439 } 440 } 441 """), 442 query=Metric('android_task_names'), 443 out=TextProto(r""" 444 android_task_names { 445 process { 446 pid: 1 447 process_name: "init" 448 uid: 0 449 } 450 process { 451 pid: 2 452 process_name: "com.google.android.gm:process" 453 uid: 10001 454 uid_package_name: "com.google.android.gm" 455 } 456 } 457 """)) 458 459 # Ftrace stats imports in metadata and stats tables 460 def test_ftrace_setup_errors(self): 461 return DiffTestBlueprint( 462 trace=DataPath('ftrace_error_stats.pftrace'), 463 query=""" 464 SELECT value FROM stats WHERE name = 'ftrace_setup_errors' 465 UNION ALL 466 SELECT str_value FROM metadata WHERE name = 'ftrace_setup_errors'; 467 """, 468 out=Csv(""" 469 "value" 470 3 471 "Ftrace event unknown: foo/bar 472 Ftrace event unknown: sched/foobar 473 Atrace failures: error: unknown tracing category "bar" 474 error enabling tracing category "bar" 475 " 476 """)) 477 478 # Ftrace stats imports in metadata and stats tables 479 def test_filter_stats(self): 480 return DiffTestBlueprint( 481 trace=TextProto(""" 482 packet { trace_stats{ filter_stats { 483 input_packets: 836 484 input_bytes: 25689644 485 output_bytes: 24826981 486 errors: 12 487 time_taken_ns: 1228178548 488 bytes_discarded_per_buffer: 1 489 bytes_discarded_per_buffer: 34 490 bytes_discarded_per_buffer: 29 491 bytes_discarded_per_buffer: 0 492 bytes_discarded_per_buffer: 862588 493 }}}"""), 494 query=""" 495 SELECT name, value FROM stats 496 WHERE name like 'filter_%' OR name = 'traced_buf_bytes_filtered_out' 497 ORDER by name ASC 498 """, 499 out=Csv(""" 500 "name","value" 501 "filter_errors",12 502 "filter_input_bytes",25689644 503 "filter_input_packets",836 504 "filter_output_bytes",24826981 505 "filter_time_taken_ns",1228178548 506 "traced_buf_bytes_filtered_out",1 507 "traced_buf_bytes_filtered_out",34 508 "traced_buf_bytes_filtered_out",29 509 "traced_buf_bytes_filtered_out",0 510 "traced_buf_bytes_filtered_out",862588 511 """)) 512 513 # cpu_track table 514 def test_cpu_track_table(self): 515 return DiffTestBlueprint( 516 trace=TextProto(r""" 517 packet { 518 ftrace_events { 519 cpu: 1 520 event { 521 timestamp: 100001000000 522 pid: 10 523 irq_handler_entry { 524 irq: 100 525 name : "resource1" 526 } 527 } 528 event { 529 timestamp: 100002000000 530 pid: 10 531 irq_handler_exit { 532 irq: 100 533 ret: 1 534 } 535 } 536 } 537 } 538 packet { 539 ftrace_events { 540 cpu: 0 541 event { 542 timestamp: 100003000000 543 pid: 15 544 irq_handler_entry { 545 irq: 100 546 name : "resource1" 547 } 548 } 549 } 550 } 551 """), 552 query=""" 553 SELECT 554 type, 555 cpu 556 FROM cpu_track 557 ORDER BY type, cpu; 558 """, 559 out=Csv(""" 560 "type","cpu" 561 "cpu_track",0 562 "cpu_track",1 563 """)) 564 565 def test_thread_state_flattened_aggregated(self): 566 return DiffTestBlueprint( 567 trace=DataPath('android_monitor_contention_trace.atr'), 568 query=""" 569 INCLUDE PERFETTO MODULE sched.thread_state_flattened; 570 select * from _get_flattened_thread_state_aggregated(11155, NULL); 571 """, 572 out=Path('thread_state_flattened_aggregated_csv.out')) 573 574 def test_thread_state_flattened(self): 575 return DiffTestBlueprint( 576 trace=DataPath('android_monitor_contention_trace.atr'), 577 query=""" 578 INCLUDE PERFETTO MODULE sched.thread_state_flattened; 579 select * from _get_flattened_thread_state(11155, NULL); 580 """, 581 out=Path('thread_state_flattened_csv.out')) 582 583 def test_metadata(self): 584 return DiffTestBlueprint( 585 trace=TextProto(r""" 586 packet { 587 system_info { 588 tracing_service_version: "Perfetto v38.0-0bb49ab54 (0bb49ab54dbe55ce5b9dfea3a2ada68b87aecb65)" 589 timezone_off_mins: 60 590 utsname { 591 sysname: "Darwin" 592 version: "Foobar" 593 machine: "x86_64" 594 release: "22.6.0" 595 } 596 } 597 trusted_uid: 158158 598 trusted_packet_sequence_id: 1 599 } 600 """), 601 query=r"""SELECT name, COALESCE(str_value, int_value) as val 602 FROM metadata 603 WHERE name IN ( 604 "system_name", "system_version", "system_machine", 605 "system_release", "timezone_off_mins") 606 ORDER BY name 607 """, 608 out=Csv(r""" 609 "name","val" 610 "system_machine","x86_64" 611 "system_name","Darwin" 612 "system_release","22.6.0" 613 "system_version","Foobar" 614 "timezone_off_mins",60 615 """)) 616 617 def test_flow_table_trace_id(self): 618 return DiffTestBlueprint( 619 trace=TextProto(""" 620 packet { 621 timestamp: 0 622 track_event { 623 name: "Track 0 Event" 624 type: TYPE_SLICE_BEGIN 625 track_uuid: 10 626 flow_ids: 57 627 } 628 trusted_packet_sequence_id: 123 629 } 630 packet { 631 timestamp: 10 632 track_event { 633 name: "Track 0 Nested Event" 634 type: TYPE_SLICE_BEGIN 635 track_uuid: 10 636 flow_ids: 57 637 } 638 trusted_packet_sequence_id: 123 639 } 640 packet { 641 timestamp: 50 642 track_event { 643 name: "Track 0 Short Event" 644 type: TYPE_SLICE_BEGIN 645 track_uuid: 10 646 terminating_flow_ids: 57 647 } 648 trusted_packet_sequence_id: 123 649 } 650 """), 651 query="SELECT * FROM flow;", 652 out=Csv(""" 653 "id","type","slice_out","slice_in","trace_id","arg_set_id" 654 0,"flow",0,1,57,0 655 1,"flow",1,2,57,0 656 """)) 657 658 def test_clock_snapshot_table_multiplier(self): 659 return DiffTestBlueprint( 660 trace=TextProto(""" 661 packet { 662 clock_snapshot { 663 clocks { 664 clock_id: 1 665 timestamp: 42 666 unit_multiplier_ns: 10 667 } 668 clocks { 669 clock_id: 6 670 timestamp: 0 671 } 672 } 673 } 674 """), 675 query="SELECT TO_REALTIME(0);", 676 out=Csv(""" 677 "TO_REALTIME(0)" 678 420 679 """)) 680 681 # Test cpu_track with machine_id ID. 682 def test_cpu_track_table_machine_id(self): 683 return DiffTestBlueprint( 684 trace=TextProto(r""" 685 packet { 686 ftrace_events { 687 cpu: 1 688 event { 689 timestamp: 100001000000 690 pid: 10 691 irq_handler_entry { 692 irq: 100 693 name : "resource1" 694 } 695 } 696 event { 697 timestamp: 100002000000 698 pid: 10 699 irq_handler_exit { 700 irq: 100 701 ret: 1 702 } 703 } 704 } 705 machine_id: 1001 706 } 707 packet { 708 ftrace_events { 709 cpu: 0 710 event { 711 timestamp: 100003000000 712 pid: 15 713 irq_handler_entry { 714 irq: 100 715 name : "resource1" 716 } 717 } 718 } 719 machine_id: 1001 720 } 721 """), 722 query=""" 723 SELECT 724 type, 725 cpu, 726 machine_id 727 FROM cpu_track 728 ORDER BY type, cpu 729 """, 730 out=Csv(""" 731 "type","cpu","machine_id" 732 "cpu_track",0,1 733 "cpu_track",1,1 734 """)) 735