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 ProcessTracking(TestSuite): 23 # Tests for the core process and thread tracking logic. Smoke tests 24 def test_process_tracking(self): 25 return DiffTestBlueprint( 26 trace=Path('synth_process_tracking.py'), 27 query=""" 28 SELECT tid, pid, process.name AS pname, thread.name AS tname 29 FROM thread 30 LEFT JOIN process USING(upid) 31 WHERE tid > 0 32 ORDER BY tid; 33 """, 34 out=Csv(""" 35 "tid","pid","pname","tname" 36 10,10,"process1","p1-t0" 37 11,"[NULL]","[NULL]","p1-t1" 38 12,10,"process1","p1-t2" 39 20,20,"process_2","p2-t0" 40 21,20,"process_2","p2-t1" 41 22,20,"process_2","p2-t2" 42 30,30,"process_3","p3-t0" 43 31,30,"process_3","p3-t1" 44 31,40,"process_4","p4-t1" 45 32,30,"process_3","p3-t2" 46 33,30,"process_3","p3-t3" 47 34,30,"process_3","p3-t4" 48 40,40,"process_4","p4-t0" 49 """)) 50 51 # Short lived threads/processes 52 def test_process_tracking_process_tracking_short_lived_1(self): 53 return DiffTestBlueprint( 54 trace=Path('process_tracking_short_lived_1.py'), 55 query=""" 56 SELECT tid, pid, process.name AS pname, thread.name AS tname 57 FROM thread 58 LEFT JOIN process USING(upid) 59 WHERE tid > 0 60 ORDER BY tid; 61 """, 62 out=Csv(""" 63 "tid","pid","pname","tname" 64 10,10,"parent","parent" 65 11,11,"child","child" 66 """)) 67 68 def test_process_tracking_process_tracking_short_lived_2(self): 69 return DiffTestBlueprint( 70 trace=Path('process_tracking_short_lived_2.py'), 71 query=""" 72 SELECT tid, pid, process.name AS pname, thread.name AS tname 73 FROM thread 74 LEFT JOIN process USING(upid) 75 WHERE tid > 0 76 ORDER BY tid; 77 """, 78 out=Csv(""" 79 "tid","pid","pname","tname" 80 10,10,"parent","parent" 81 11,11,"true_name","true_name" 82 """)) 83 84 # Process uid handling 85 def test_process_tracking_uid(self): 86 return DiffTestBlueprint( 87 trace=Path('synth_process_tracking.py'), 88 query=""" 89 SELECT pid, uid 90 FROM process 91 ORDER BY pid; 92 """, 93 out=Csv(""" 94 "pid","uid" 95 0,"[NULL]" 96 10,1001 97 20,1002 98 30,"[NULL]" 99 40,"[NULL]" 100 """)) 101 102 # Tracking across execs 103 def test_process_tracking_process_tracking_exec(self): 104 return DiffTestBlueprint( 105 trace=Path('process_tracking_exec.py'), 106 query=""" 107 SELECT tid, pid, process.name AS pname, thread.name AS tname 108 FROM thread 109 LEFT JOIN process USING(upid) 110 WHERE tid > 0 111 ORDER BY tid; 112 """, 113 out=Csv(""" 114 "tid","pid","pname","tname" 115 10,10,"parent","parent" 116 11,11,"true_process_name","true_name" 117 """)) 118 119 # Tracking parent threads 120 def test_process_parent_pid_process_parent_pid_tracking_1(self): 121 return DiffTestBlueprint( 122 trace=Path('process_parent_pid_tracking_1.py'), 123 query=""" 124 SELECT 125 child.pid AS child_pid, 126 parent.pid AS parent_pid 127 FROM process AS child 128 JOIN process AS parent 129 ON child.parent_upid = parent.upid 130 ORDER BY child_pid; 131 """, 132 out=Csv(""" 133 "child_pid","parent_pid" 134 10,0 135 20,10 136 """)) 137 138 def test_process_parent_pid_process_parent_pid_tracking_2(self): 139 return DiffTestBlueprint( 140 trace=Path('process_parent_pid_tracking_2.py'), 141 query=""" 142 SELECT 143 child.pid AS child_pid, 144 parent.pid AS parent_pid 145 FROM process AS child 146 JOIN process AS parent 147 ON child.parent_upid = parent.upid 148 ORDER BY child_pid; 149 """, 150 out=Csv(""" 151 "child_pid","parent_pid" 152 10,0 153 20,10 154 """)) 155 156 # Tracking thread reuse 157 def test_process_tracking_reused_thread_print(self): 158 return DiffTestBlueprint( 159 trace=Path('reused_thread_print.py'), 160 query=""" 161 SELECT tid, pid, process.name AS pname, thread.name AS tname 162 FROM thread 163 LEFT JOIN process USING(upid) 164 WHERE tid > 0 165 ORDER BY tid; 166 """, 167 out=Csv(""" 168 "tid","pid","pname","tname" 169 10,10,"parent","[NULL]" 170 11,11,"short_lived","[NULL]" 171 11,10,"parent","true_name" 172 """)) 173 174 # TODO(lalitm): move this out of this folder. 175 def test_slice_with_pid_sde_tracing_mark_write(self): 176 return DiffTestBlueprint( 177 trace=TextProto(r""" 178 packet { 179 ftrace_events { 180 cpu: 0 181 event { 182 timestamp: 100 183 pid: 403 184 sde_tracing_mark_write { 185 pid: 403 186 trace_name: "test_event" 187 trace_begin: 1 188 } 189 } 190 event { 191 timestamp: 101 192 pid: 403 193 sde_tracing_mark_write { 194 pid: 403 195 trace_name: "test_event" 196 trace_begin: 0 197 } 198 } 199 } 200 } 201 """), 202 query=""" 203 SELECT s.name, dur, tid, pid 204 FROM slice s 205 JOIN thread_track t ON s.track_id = t.id 206 JOIN thread USING(utid) 207 LEFT JOIN process USING(upid); 208 """, 209 out=Csv(""" 210 "name","dur","tid","pid" 211 "test_event",1,403,403 212 """)) 213 214 # Check that a <...> thread name doesn't overwrite a useful thread name 215 def test_unknown_thread_name_tracking(self): 216 return DiffTestBlueprint( 217 trace=Path('unknown_thread_name.systrace'), 218 query=""" 219 SELECT tid, pid, process.name AS pname, thread.name AS tname 220 FROM thread 221 LEFT JOIN process USING(upid) 222 WHERE tid > 0 223 ORDER BY tid; 224 """, 225 out=Csv(""" 226 "tid","pid","pname","tname" 227 19999,"[NULL]","[NULL]","real_name" 228 """)) 229 230 def test_process_tracking_machine_id(self): 231 return DiffTestBlueprint( 232 trace=Path('synth_process_tracking.py'), 233 trace_modifier=TraceInjector(['ftrace_events', 'process_tree'], 234 {'machine_id': 1001}), 235 query=""" 236 SELECT tid, pid, process.name AS pname, thread.name AS tname, 237 thread.machine_id as tmachine, process.machine_id as pmachine 238 FROM thread 239 LEFT JOIN process USING(upid) 240 WHERE tid > 0 241 ORDER BY tid; 242 """, 243 out=Csv(""" 244 "tid","pid","pname","tname","tmachine","pmachine" 245 10,10,"process1","p1-t0",1,1 246 11,"[NULL]","[NULL]","p1-t1",1,"[NULL]" 247 12,10,"process1","p1-t2",1,1 248 20,20,"process_2","p2-t0",1,1 249 21,20,"process_2","p2-t1",1,1 250 22,20,"process_2","p2-t2",1,1 251 30,30,"process_3","p3-t0",1,1 252 31,30,"process_3","p3-t1",1,1 253 31,40,"process_4","p4-t1",1,1 254 32,30,"process_3","p3-t2",1,1 255 33,30,"process_3","p3-t3",1,1 256 34,30,"process_3","p3-t4",1,1 257 40,40,"process_4","p4-t0",1,1 258 """)) 259 260 def test_process_stats_process_runtime(self): 261 return DiffTestBlueprint( 262 trace=TextProto(r""" 263 packet { 264 first_packet_on_sequence: true 265 timestamp: 1088821452006028 266 incremental_state_cleared: true 267 process_tree { 268 processes { 269 pid: 9301 270 ppid: 9251 271 uid: 304336 272 nspid: 4 273 nspid: 1 274 cmdline: "/bin/command" 275 process_start_from_boot: 157620000000 276 } 277 collection_end_timestamp: 1088821520810204 278 } 279 trusted_uid: 304336 280 trusted_packet_sequence_id: 3 281 trusted_pid: 1137063 282 previous_packet_dropped: true 283 } 284 packet { 285 timestamp: 1088821520899054 286 process_stats { 287 processes { 288 pid: 9301 289 runtime_user_mode: 16637390000000 290 runtime_kernel_mode: 1327800000000 291 vm_size_kb: 1188971644 292 vm_locked_kb: 0 293 vm_hwm_kb: 1180568 294 vm_rss_kb: 1100672 295 rss_anon_kb: 1045332 296 rss_file_kb: 46848 297 rss_shmem_kb: 8492 298 vm_swap_kb: 163936 299 oom_score_adj: 300 300 } 301 collection_end_timestamp: 1088821539659978 302 } 303 trusted_uid: 304336 304 trusted_packet_sequence_id: 3 305 trusted_pid: 1137063 306 } 307 packet { 308 timestamp: 1088821786436938 309 process_stats { 310 processes { 311 pid: 9301 312 runtime_user_mode: 16638280000000 313 runtime_kernel_mode: 1327860000000 314 vm_size_kb: 1188979836 315 vm_locked_kb: 0 316 vm_hwm_kb: 1180568 317 vm_rss_kb: 895428 318 rss_anon_kb: 832028 319 rss_file_kb: 46848 320 rss_shmem_kb: 16552 321 vm_swap_kb: 163936 322 oom_score_adj: 300 323 } 324 collection_end_timestamp: 1088821817629747 325 } 326 trusted_uid: 304336 327 trusted_packet_sequence_id: 3 328 trusted_pid: 1137063 329 } 330 """), 331 query=""" 332 select c.ts, c.value, pct.name, p.pid, p.start_ts, p.cmdline 333 from counter c 334 join process_counter_track pct on (c.track_id = pct.id) 335 join process p using (upid) 336 where pct.name in ("runtime.user_ns", "runtime.kernel_ns") 337 and p.pid = 9301 338 order by ts asc, pct.name asc 339 """, 340 out=Csv(""" 341 "ts","value","name","pid","start_ts","cmdline" 342 1088821520899054,1327800000000.000000,"runtime.kernel_ns",9301,157620000000,"/bin/command" 343 1088821520899054,16637390000000.000000,"runtime.user_ns",9301,157620000000,"/bin/command" 344 1088821786436938,1327860000000.000000,"runtime.kernel_ns",9301,157620000000,"/bin/command" 345 1088821786436938,16638280000000.000000,"runtime.user_ns",9301,157620000000,"/bin/command" 346 """)) 347 348 # Distinguish set-to-zero process age (can happen for kthreads) from unset 349 # process age. 350 def test_process_age_optionality(self): 351 return DiffTestBlueprint( 352 trace=TextProto(r""" 353 packet { 354 first_packet_on_sequence: true 355 timestamp: 1088821452006028 356 incremental_state_cleared: true 357 process_tree { 358 processes { 359 pid: 2 360 ppid: 0 361 uid: 0 362 cmdline: "kthreadd" 363 process_start_from_boot: 0 364 } 365 processes { 366 pid: 68 367 ppid: 2 368 uid: 0 369 cmdline: "ksoftirqd/7" 370 process_start_from_boot: 10000000 371 } 372 processes { 373 pid: 9301 374 ppid: 9251 375 uid: 304336 376 cmdline: "no_age_field" 377 } 378 collection_end_timestamp: 1088821520810204 379 } 380 trusted_uid: 304336 381 trusted_packet_sequence_id: 3 382 trusted_pid: 1137063 383 previous_packet_dropped: true 384 } 385 """), 386 query=""" 387 select p.pid, p.start_ts, p.cmdline 388 from process p 389 where pid in (2, 68, 9301) 390 order by pid asc; 391 """, 392 out=Csv(""" 393 "pid","start_ts","cmdline" 394 2,0,"kthreadd" 395 68,10000000,"ksoftirqd/7" 396 9301,"[NULL]","no_age_field" 397 """)) 398