• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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