• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python
2# Copyright (C) 2018 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 at
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
16import argparse
17
18from google.protobuf import descriptor, descriptor_pb2, message_factory, reflection
19from google.protobuf.pyext import _message
20
21CLONE_THREAD = 0x00010000
22CLONE_VFORK = 0x00004000
23CLONE_VM = 0x00000100
24
25
26class Trace(object):
27
28  def __init__(self, trace):
29    self.trace = trace
30    self.proc_map = {}
31    self.proc_map[0] = 'idle_thread'
32
33  def add_system_info(self, arch="", fingerprint=""):
34    self.packet = self.trace.packet.add()
35    self.packet.system_info.utsname.machine = arch
36    self.packet.system_info.android_build_fingerprint = fingerprint
37
38  def add_ftrace_packet(self, cpu):
39    self.packet = self.trace.packet.add()
40    self.packet.ftrace_events.cpu = cpu
41
42  def add_packet(self, ts=None):
43    self.packet = self.trace.packet.add()
44    if ts is not None:
45      self.packet.timestamp = ts
46    return self.packet
47
48  def __add_ftrace_event(self, ts, tid):
49    ftrace = self.packet.ftrace_events.event.add()
50    ftrace.timestamp = ts
51    ftrace.pid = tid
52    return ftrace
53
54  def add_rss_stat(self, ts, tid, member, size, mm_id=None, curr=None):
55    ftrace = self.__add_ftrace_event(ts, tid)
56    rss_stat = ftrace.rss_stat
57    rss_stat.member = member
58    rss_stat.size = size
59    if mm_id is not None:
60      rss_stat.mm_id = mm_id
61    if curr is not None:
62      rss_stat.curr = curr
63
64  def add_ion_event(self, ts, tid, heap_name, len, size=0):
65    ftrace = self.__add_ftrace_event(ts, tid)
66    ion = ftrace.ion_heap_grow
67    ion.heap_name = heap_name
68    ion.len = len
69    ion.total_allocated = size
70
71  def add_oom_score_update(self, ts, oom_score_adj, pid):
72    ftrace = self.__add_ftrace_event(ts, pid)
73    oom_score = ftrace.oom_score_adj_update
74    oom_score.comm = self.proc_map[pid]
75    oom_score.oom_score_adj = oom_score_adj
76    oom_score.pid = pid
77
78  def add_sched(self,
79                ts,
80                prev_pid,
81                next_pid,
82                prev_comm=None,
83                next_comm=None,
84                prev_state=None):
85    ftrace = self.__add_ftrace_event(ts, 0)
86    ss = ftrace.sched_switch
87    ss.prev_comm = prev_comm or self.proc_map[prev_pid]
88    ss.prev_pid = prev_pid
89    ss.next_pid = next_pid
90    ss.next_comm = next_comm or self.proc_map[next_pid]
91    if prev_state:
92      if prev_state == 'R':
93        ss.prev_state = 0
94      elif prev_state == 'S':
95        ss.prev_state = 1
96      elif prev_state == 'U':
97        ss.prev_state = 2
98      else:
99        raise Exception('Invalid prev state {}'.format(prev_state))
100
101  def add_cpufreq(self, ts, freq, cpu):
102    ftrace = self.__add_ftrace_event(ts, 0)
103    cpufreq = ftrace.cpu_frequency
104    cpufreq.state = freq
105    cpufreq.cpu_id = cpu
106
107  def add_kernel_lmk(self, ts, tid):
108    ftrace = self.__add_ftrace_event(ts, tid)
109    lowmemory_kill = ftrace.lowmemory_kill
110    lowmemory_kill.pid = tid
111
112  def add_sys_enter(self, ts, tid, id):
113    ftrace = self.__add_ftrace_event(ts, tid)
114    sys_enter = ftrace.sys_enter
115    sys_enter.id = id
116
117  def add_sys_exit(self, ts, tid, id, ret):
118    ftrace = self.__add_ftrace_event(ts, tid)
119    sys_exit = ftrace.sys_exit
120    sys_exit.id = id
121    sys_exit.ret = ret
122
123  def add_newtask(self, ts, tid, new_tid, new_comm, flags):
124    ftrace = self.__add_ftrace_event(ts, tid)
125    newtask = ftrace.task_newtask
126    newtask.pid = new_tid
127    newtask.comm = new_comm
128    newtask.clone_flags = flags
129
130  def add_process_free(self, ts, tid, comm, prio):
131    ftrace = self.__add_ftrace_event(ts, tid)
132    sched_process_free = ftrace.sched_process_free
133    sched_process_free.pid = tid
134    sched_process_free.comm = comm
135    sched_process_free.prio = prio
136
137  def add_rename(self, ts, tid, old_comm, new_comm, oom_score_adj):
138    ftrace = self.__add_ftrace_event(ts, tid)
139    task_rename = ftrace.task_rename
140    task_rename.pid = tid
141    task_rename.oldcomm = old_comm
142    task_rename.newcomm = new_comm
143    task_rename.oom_score_adj = oom_score_adj
144
145  def add_print(self, ts, tid, buf):
146    ftrace = self.__add_ftrace_event(ts, tid)
147    print_event = getattr(ftrace, 'print')
148    print_event.buf = buf
149
150  def add_kmalloc(self, ts, tid, bytes_alloc, bytes_req, call_site, gfp_flags,
151                  ptr):
152    ftrace = self.__add_ftrace_event(ts, tid)
153    kmalloc = ftrace.kmalloc
154    kmalloc.bytes_alloc = bytes_alloc
155    kmalloc.bytes_req = bytes_req
156    kmalloc.call_site = call_site
157    kmalloc.gfp_flags = gfp_flags
158    kmalloc.ptr = ptr
159
160  def add_kfree(self, ts, tid, call_site, ptr):
161    ftrace = self.__add_ftrace_event(ts, tid)
162    kfree = ftrace.kfree
163    kfree.call_site = call_site
164    kfree.ptr = ptr
165
166  def add_atrace_counter(self, ts, pid, tid, buf, cnt):
167    self.add_print(ts, tid, 'C|{}|{}|{}'.format(pid, buf, cnt))
168
169  def add_atrace_begin(self, ts, tid, pid, buf):
170    self.add_print(ts, tid, 'B|{}|{}'.format(pid, buf))
171
172  def add_atrace_end(self, ts, tid, pid):
173    self.add_print(ts, tid, 'E|{}'.format(pid))
174
175  def add_atrace_async_begin(self, ts, tid, pid, buf):
176    self.add_print(ts, tid, 'S|{}|{}|0'.format(pid, buf))
177
178  def add_atrace_async_end(self, ts, tid, pid, buf):
179    self.add_print(ts, tid, 'F|{}|{}|0'.format(pid, buf))
180
181  def add_process(self, pid, ppid, cmdline, uid=None):
182    process = self.packet.process_tree.processes.add()
183    process.pid = pid
184    process.ppid = ppid
185    process.cmdline.append(cmdline)
186    if uid is not None:
187      process.uid = uid
188    self.proc_map[pid] = cmdline
189
190  def add_thread(self, tid, tgid, cmdline):
191    thread = self.packet.process_tree.threads.add()
192    thread.tid = tid
193    thread.tgid = tgid
194    self.proc_map[tid] = cmdline
195
196  def add_battery_counters(self, ts, charge_uah, cap_prct, curr_ua,
197                           curr_avg_ua):
198    self.packet = self.trace.packet.add()
199    self.packet.timestamp = ts
200    battery_count = self.packet.battery
201    battery_count.charge_counter_uah = charge_uah
202    battery_count.capacity_percent = cap_prct
203    battery_count.current_ua = curr_ua
204    battery_count.current_avg_ua = curr_avg_ua
205
206  def add_battery_counters_no_curr_ua(self, ts, charge_uah, cap_prct,
207                                      curr_avg_ua):
208    self.packet = self.trace.packet.add()
209    self.packet.timestamp = ts
210    battery_count = self.packet.battery
211    battery_count.charge_counter_uah = charge_uah
212    battery_count.capacity_percent = cap_prct
213    battery_count.current_avg_ua = curr_avg_ua
214
215  def add_power_rails_desc(self, index_val, name):
216    power_rails = self.packet.power_rails
217    descriptor = power_rails.rail_descriptor.add()
218    descriptor.index = index_val
219    descriptor.rail_name = name
220
221  def add_power_rails_data(self, ts, index_val, value):
222    power_rails = self.packet.power_rails
223    energy_data = power_rails.energy_data.add()
224    energy_data.index = index_val
225    energy_data.timestamp_ms = ts
226    energy_data.energy = value
227
228  def add_package_list(self, ts, name, uid, version_code):
229    packet = self.add_packet()
230    packet.timestamp = ts
231    plist = packet.packages_list
232    pinfo = plist.packages.add()
233    pinfo.name = name
234    pinfo.uid = uid
235    pinfo.version_code = version_code
236
237  def add_profile_packet(self, ts):
238    packet = self.add_packet()
239    packet.timestamp = ts
240    return packet.profile_packet
241
242  def add_clock_snapshot(self, clocks, seq_id=None):
243    packet = self.add_packet()
244    if seq_id is not None:
245      packet.trusted_packet_sequence_id = seq_id
246    snap = self.packet.clock_snapshot
247    for k, v in clocks.iteritems():
248      clock = snap.clocks.add()
249      clock.clock_id = k
250      clock.timestamp = v
251
252  def add_gpu_counter_spec(self,
253                           ts,
254                           counter_id,
255                           name,
256                           description=None,
257                           unit_numerators=[],
258                           unit_denominators=[]):
259    packet = self.add_packet()
260    packet.timestamp = ts
261    gpu_counters = packet.gpu_counter_event
262    counter_desc = gpu_counters.counter_descriptor
263    spec = counter_desc.specs.add()
264    spec.counter_id = counter_id
265    spec.name = name
266    if description is not None:
267      spec.description = description
268    spec.numerator_units.extend(unit_numerators)
269    spec.denominator_units.extend(unit_denominators)
270
271  def add_gpu_counter(self, ts, counter_id, value, clock_id=None, seq_id=None):
272    packet = self.add_packet()
273    packet.timestamp = ts
274    if clock_id is not None:
275      packet.timestamp_clock_id = clock_id
276    if seq_id is not None:
277      packet.trusted_packet_sequence_id = seq_id
278    gpu_counters = self.packet.gpu_counter_event
279    gpu_counter = gpu_counters.counters.add()
280    gpu_counter.counter_id = counter_id
281    gpu_counter.int_value = value
282
283  def add_gpu_render_stages_hw_queue_spec(self, specs=[]):
284    packet = self.add_packet()
285    spec = self.packet.gpu_render_stage_event.specifications
286    for s in specs:
287      hw_queue = spec.hw_queue.add()
288      hw_queue.name = s.get('name', '')
289      if 'description' in s:
290        hw_queue.description = s['description']
291
292  def add_gpu_render_stages_stage_spec(self, specs=[]):
293    packet = self.add_packet()
294    spec = self.packet.gpu_render_stage_event.specifications
295    for s in specs:
296      stage = spec.stage.add()
297      stage.name = s.get('name', '')
298      if 'description' in s:
299        stage.description = s['description']
300
301  def add_gpu_render_stages(self,
302                            ts,
303                            event_id,
304                            duration,
305                            hw_queue_id,
306                            stage_id,
307                            context,
308                            render_target_handle=None,
309                            render_pass_handle=None,
310                            command_buffer_handle=None,
311                            submission_id=None,
312                            extra_data={}):
313    packet = self.add_packet()
314    packet.timestamp = ts
315    render_stage = self.packet.gpu_render_stage_event
316    render_stage.event_id = event_id
317    render_stage.duration = duration
318    render_stage.hw_queue_id = hw_queue_id
319    render_stage.stage_id = stage_id
320    render_stage.context = context
321    if render_target_handle is not None:
322      render_stage.render_target_handle = render_target_handle
323    if render_pass_handle is not None:
324      render_stage.render_pass_handle = render_pass_handle
325    if command_buffer_handle is not None:
326      render_stage.command_buffer_handle = command_buffer_handle
327    if submission_id is not None:
328      render_stage.submission_id = submission_id
329    for key, value in extra_data.items():
330      data = render_stage.extra_data.add()
331      data.name = key
332      if value is not None:
333        data.value = value
334
335  def add_vk_debug_marker(self, ts, pid, vk_device, obj_type, obj, obj_name):
336    packet = self.add_packet()
337    packet.timestamp = ts
338    debug_marker = (self.packet.vulkan_api_event.vk_debug_utils_object_name)
339    debug_marker.pid = pid
340    debug_marker.vk_device = vk_device
341    debug_marker.object_type = obj_type
342    debug_marker.object = obj
343    debug_marker.object_name = obj_name
344
345  def add_vk_queue_submit(self, ts, dur, pid, tid, vk_queue, vk_command_buffers,
346                          submission_id):
347    packet = self.add_packet()
348    packet.timestamp = ts
349    submit = (self.packet.vulkan_api_event.vk_queue_submit)
350    submit.duration_ns = dur
351    submit.pid = pid
352    submit.tid = tid
353    for cmd in vk_command_buffers:
354      submit.vk_command_buffers.append(cmd)
355    submit.submission_id = submission_id
356
357  def add_gpu_log(self, ts, severity, tag, message):
358    packet = self.add_packet()
359    packet.timestamp = ts
360    gpu_log = self.packet.gpu_log
361    gpu_log.severity = severity
362    gpu_log.tag = tag
363    gpu_log.log_message = message
364
365  def add_buffer_event_packet(self, ts, buffer_id, layer_name, frame_number,
366                              event_type, duration):
367    packet = self.add_packet()
368    packet.timestamp = ts
369    buffer_event = packet.graphics_frame_event.buffer_event
370    if buffer_id >= 0:
371      buffer_event.buffer_id = buffer_id
372    buffer_event.layer_name = layer_name
373    buffer_event.frame_number = frame_number
374    if event_type >= 0:
375      buffer_event.type = event_type
376    buffer_event.duration_ns = duration
377
378  def add_cpu(self, freqs):
379    cpu = self.packet.cpu_info.cpus.add()
380    for freq in freqs:
381      cpu.frequencies.append(freq)
382
383  def add_process_stats(self, pid, freqs):
384    process = self.packet.process_stats.processes.add()
385    process.pid = pid
386    thread = process.threads.add()
387    thread.tid = pid * 10
388    for index in freqs:
389      thread.cpu_freq_indices.append(index)
390      thread.cpu_freq_ticks.append(freqs[index])
391
392
393def create_trace():
394  parser = argparse.ArgumentParser()
395  parser.add_argument(
396      'trace_descriptor', type=str, help='location of trace descriptor')
397  args = parser.parse_args()
398
399  with open(args.trace_descriptor, 'rb') as t:
400    fileContent = t.read()
401
402  file_desc_set_pb2 = descriptor_pb2.FileDescriptorSet()
403  file_desc_set_pb2.MergeFromString(fileContent)
404
405  desc_by_path = {}
406  for f_desc_pb2 in file_desc_set_pb2.file:
407    f_desc_pb2_encode = f_desc_pb2.SerializeToString()
408    f_desc = descriptor.FileDescriptor(
409        name=f_desc_pb2.name,
410        package=f_desc_pb2.package,
411        serialized_pb=f_desc_pb2_encode)
412
413    for desc in f_desc.message_types_by_name.values():
414      desc_by_path[desc.full_name] = desc
415
416  trace = message_factory.MessageFactory().GetPrototype(
417      desc_by_path['perfetto.protos.Trace'])()
418  return Trace(trace)
419