1#!/usr/bin/env python3 2# Copyright (C) 2024 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 Csv, Path, DataPath 17from python.generators.diff_tests.testing import DiffTestBlueprint 18from python.generators.diff_tests.testing import TestSuite 19 20 21# These diff tests are based on the same test data simpleperf uses for its 22# testing 23# (https://android.googlesource.com/platform/system/extras/+/refs/heads/main/simpleperf/testdata). 24# Basically we load these perf files and make sure we can get the same data we 25# would get via `simpleperf report` 26class Simpleperf(TestSuite): 27 # simpleperf report -i perf.data --print-event-count --csv --cpu 2,6,7 28 def test_perf(self): 29 return DiffTestBlueprint( 30 trace=DataPath('simpleperf/perf.data'), 31 query=Path('perf_test.sql'), 32 out=Csv(''' 33 "event_count","command","pid","tid","shared_object","symbol" 34 130707953,"t2",26130,26130,"/t2","t2[+51c]" 35 126249237,"elf",26083,26083,"/elf","elf[+51c]" 36 109687208,"t1",26124,26124,"/t1","t1[+523]" 37 107027760,"t1",26124,26124,"/t1","t1[+51c]" 38 101887409,"t2",26130,26130,"/t2","t2[+523]" 39 92421568,"elf",26083,26083,"/elf","elf[+523]" 40 61539363,"t1",26124,26124,"/t1","t1[+518]" 41 60355129,"elf",26083,26083,"/elf","elf[+513]" 42 54840659,"t1",26124,26124,"/t1","t1[+4ed]" 43 52233968,"elf",26083,26083,"/elf","elf[+4ed]" 44 50833094,"t1",26124,26124,"/t1","t1[+4f7]" 45 50746374,"t2",26130,26130,"/t2","t2[+4ed]" 46 49185691,"elf",26083,26083,"/elf","elf[+4f7]" 47 47520901,"t2",26130,26130,"/t2","t2[+513]" 48 45979652,"elf",26083,26083,"/elf","elf[+518]" 49 44834371,"t2",26130,26130,"/t2","t2[+4f7]" 50 42928068,"t2",26130,26130,"/t2","t2[+518]" 51 39608138,"t1",26124,26124,"/t1","t1[+513]" 52 1390415,"t1",26124,26124,"/t1","t1[+4fa]" 53 1390305,"t2",26130,26130,"/t2","t2[+4fa]" 54 1390173,"elf",26083,26083,"/elf","elf[+500]" 55 1389030,"t2",26130,26130,"/t2","t2[+500]" 56 693786,"t2",26130,26130,"/lib/modules/3.13.0-76-generic/kernel/drivers/ata/pata_acpi.ko","pata_acpi.ko[+ffffffffa05c4da4]" 57 ''')) 58 59 def test_perf_tracks(self): 60 return DiffTestBlueprint( 61 trace=DataPath('simpleperf/perf.data'), 62 query=''' 63 SELECT 64 name, 65 unit, 66 description, 67 cpu, 68 is_timebase 69 FROM perf_counter_track 70 ORDER BY perf_session_id, name, cpu; 71 ''', 72 out=Csv(''' 73 "name","unit","description","cpu","is_timebase" 74 "","[NULL]","[NULL]",2,1 75 "","[NULL]","[NULL]",6,1 76 "","[NULL]","[NULL]",7,1 77 "","[NULL]","[NULL]",16,1 78 ''')) 79 80 def test_perf_with_add_counter_tracks(self): 81 return DiffTestBlueprint( 82 trace=DataPath('simpleperf/perf_with_add_counter.data'), 83 query=''' 84 SELECT 85 name, 86 unit, 87 description, 88 cpu, 89 is_timebase 90 FROM perf_counter_track 91 ORDER BY perf_session_id, name, cpu; 92 ''', 93 out=Csv(''' 94 "name","unit","description","cpu","is_timebase" 95 "cpu-cycles","[NULL]","[NULL]",40,1 96 "instructions","[NULL]","[NULL]",40,0 97 ''')) 98 99 # simpleperf report -i perf.data --print-event-count --csv 100 # The thread name in this trace changes over time. simpleperf shows samples 101 # with the old and new name. Perfetto does not support threads changing names, 102 # it only keeps the last name, thus there is a slight mismatch in the outputs. 103 def test_perf_with_add_counter(self): 104 return DiffTestBlueprint( 105 trace=DataPath('simpleperf/perf_with_add_counter.data'), 106 query=Path('perf_with_add_counter_test.sql'), 107 out=Csv(''' 108 "cpu_cycles","instructions","others","command","pid","tid","shared_object","symbol" 109 1011567,1188389,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8cc9d30]" 110 219490,233619,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8e498c6]" 111 191017,157031,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa94d0901]" 112 175099,140443,0,"sleep",689664,689664,"/lib/x86_64-linux-gnu/libc-2.32.so","_dl_addr" 113 152310,130151,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8e30c70]" 114 122439,87058,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa960015d]" 115 89368,68332,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8e03757]" 116 40272,30457,0,"sleep",689664,689664,"/lib/x86_64-linux-gnu/ld-2.32.so","ld-2.32.so[+1767b]" 117 14742,7858,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8ce7a78]" 118 7551,1953,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8cc90c5]" 119 7080,2940,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8cc8119]" 120 3520,295,0,"sleep",689664,689664,"[kernel.kallsyms]","[kernel.kallsyms][+ffffffffa8c6b3e6]" 121 ''')) 122 123 def test_build_id_feature(self): 124 return DiffTestBlueprint( 125 trace=DataPath('simpleperf/perf.data'), 126 query=''' 127 SELECT build_id, name 128 FROM stack_profile_mapping 129 WHERE build_id <> "" 130 ORDER BY name 131 ''', 132 out=Csv(''' 133 "build_id","name" 134 "0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/elf" 135 "0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/elf" 136 "47111a47babdcd27ca2f9ff450dc1897ded761ed","/lib/modules/3.13.0-76-generic/kernel/drivers/ata/pata_acpi.ko" 137 "0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/t1" 138 "0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/t2" 139 ''')) 140 141 def test_clocks_align(self): 142 return DiffTestBlueprint( 143 trace=DataPath('zip/perf_track_sym.zip'), 144 query=Path('clocks_align_test.sql'), 145 out=Csv(''' 146 "misaligned_count" 147 0 148 ''')) 149 150 def test_cmdline(self): 151 return DiffTestBlueprint( 152 trace=DataPath('simpleperf/perf.data'), 153 query=''' 154 SELECT cmdline 155 FROM perf_session 156 ''', 157 out=Csv(''' 158 "cmdline" 159 "/ssd/android/aosp_master/out/host/linux-x86/bin/simpleperf record -p 26083,26090,26124,26130 sleep 0.0001" 160 ''')) 161 162 # Make sure we can parse perf.data files with synthetic events (perf will 163 # write those with an id = 0). This trace file has some synthetic COMM events. 164 def test_perf_with_synthetic_events(self): 165 return DiffTestBlueprint( 166 trace=DataPath('simpleperf/perf_with_synthetic_events.data'), 167 query=''' 168 SELECT tid, name 169 FROM thread 170 ORDER BY tid 171 ''', 172 out=Csv(''' 173 "tid","name" 174 0,"[NULL]" 175 289003,"trace_processor" 176 ''')) 177 178 # Counters are not updated for samples with no CPU (b/352257666) 179 def test_perf_with_no_cpu_in_sample_no_counters(self): 180 return DiffTestBlueprint( 181 trace=DataPath('simpleperf/perf_with_synthetic_events.data'), 182 query=''' 183 SELECT 184 ( 185 SELECT value AS sample_count 186 FROM stats 187 WHERE name = 'perf_counter_skipped_because_no_cpu' 188 ) AS counter_skipped, 189 (SELECT COUNT(*) FROM perf_sample) AS sample_count 190 ''', 191 out=Csv(''' 192 "counter_skipped","sample_count" 193 9126,9126 194 ''')) 195 196 def test_perf_with_no_cpu_in_sample(self): 197 return DiffTestBlueprint( 198 trace=DataPath('simpleperf/perf_with_synthetic_events.data'), 199 query=''' 200 SELECT cpu, COUNT(*) AS count 201 FROM perf_sample 202 WHERE callsite_id IS NOT NULL 203 GROUP BY cpu ORDER BY cpu 204 ''', 205 out=Csv(''' 206 "cpu","count" 207 "[NULL]",9126 208 ''')) 209 210 def test_linux_perf_unwinding(self): 211 return DiffTestBlueprint( 212 trace=DataPath('simpleperf/linux_perf_with_symbols.zip'), 213 query=Path('stacks_test.sql'), 214 out=Csv(''' 215 "name" 216 "main,A" 217 "main,A,B" 218 "main,A,B,C" 219 "main,A,B,C,D" 220 "main,A,B,C,D,E" 221 "main,A,B,C,E" 222 "main,A,B,D" 223 "main,A,B,D,E" 224 "main,A,B,E" 225 "main,A,C" 226 "main,A,C,D" 227 "main,A,C,D,E" 228 "main,A,C,E" 229 "main,A,D" 230 "main,A,D,E" 231 "main,A,E" 232 "main,B" 233 "main,B,C" 234 "main,B,C,D" 235 "main,B,C,D,E" 236 "main,B,C,E" 237 "main,B,D" 238 "main,B,D,E" 239 "main,B,E" 240 "main,C" 241 "main,C,D" 242 "main,C,D,E" 243 "main,C,E" 244 "main,D" 245 "main,D,E" 246 "main,E" 247 ''')) 248 249 def test_spe_operation(self): 250 return DiffTestBlueprint( 251 trace=DataPath('simpleperf/spe.trace.zip'), 252 query=''' 253 INCLUDE PERFETTO MODULE linux.perf.spe; 254 SELECT 255 operation, 256 count(*) AS cnt 257 FROM linux_perf_spe_record 258 GROUP BY operation 259 ORDER BY operation 260 ''', 261 out=Csv(''' 262 "operation","cnt" 263 "BRANCH",68038 264 "LOAD",54 265 "STORE",47 266 ''')) 267 268 def test_spe_pc(self): 269 return DiffTestBlueprint( 270 trace=DataPath('simpleperf/spe.trace.zip'), 271 query=''' 272 INCLUDE PERFETTO MODULE linux.perf.spe; 273 SELECT 274 printf('0x%08x', rel_pc + m.start - exact_offset) AS pc, 275 exception_level, 276 COUNT(*) AS cnt 277 FROM linux_perf_spe_record r, stack_profile_frame f 278 ON r.instruction_frame_id = f.id, 279 stack_profile_mapping m 280 ON f.mapping = m.id 281 GROUP BY pc, exception_level 282 HAVING cnt > 1 283 ORDER BY pc, exception_level 284 ''', 285 out=Csv(''' 286 "pc","exception_level","cnt" 287 "0x5cfc344464","EL0",2157 288 "0x5cfc344528","EL0",2166 289 "0x5cfc3445c4","EL0",2154 290 "0x5cfc3446c8","EL0",2108 291 "0x5cfc3447a8","EL0",2209 292 "0x5cfc344854","EL0",2178 293 "0x5cfc34492c","EL0",2246 294 "0x5cfc344c14","EL0",4461 295 "0x5cfc344cd0","EL0",4416 296 "0x5cfc344d7c","EL0",4399 297 "0x5cfc344df4","EL0",2 298 "0x5cfc344e90","EL0",4427 299 "0x5cfc3450e8","EL0",8756 300 "0x5cfc345194","EL0",8858 301 "0x5cfc345240","EL0",8776 302 "0x5cfc345354","EL0",8659 303 "0xffffd409990628","EL1",14 304 "0xffffd40999062c","EL1",15 305 "0xffffd40fb0f124","EL1",2 306 ''')) 307 308 def test_perf_summary_tree(self): 309 return DiffTestBlueprint( 310 trace=DataPath('simpleperf/perf.data'), 311 query=''' 312 INCLUDE PERFETTO MODULE linux.perf.samples; 313 314 SELECT * 315 FROM linux_perf_samples_summary_tree 316 LIMIT 10 317 ''', 318 out=Csv(''' 319 "id","parent_id","name","mapping_name","source_file","line_number","self_count","cumulative_count" 320 0,"[NULL]","","/elf","[NULL]","[NULL]",84,84 321 1,"[NULL]","","/elf","[NULL]","[NULL]",69,69 322 2,"[NULL]","","/elf","[NULL]","[NULL]",177,177 323 3,"[NULL]","","/elf","[NULL]","[NULL]",89,89 324 4,"[NULL]","","/t1","[NULL]","[NULL]",70,70 325 5,"[NULL]","","/elf","[NULL]","[NULL]",218,218 326 6,"[NULL]","","/elf","[NULL]","[NULL]",65,65 327 7,"[NULL]","","/elf","[NULL]","[NULL]",70,70 328 8,"[NULL]","","/t1","[NULL]","[NULL]",87,87 329 9,"[NULL]","","/elf","[NULL]","[NULL]",64,64 330 ''')) 331