1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import telemetry.timeline.counter as tracing_counter
6import telemetry.timeline.event as event_module
7import telemetry.timeline.event_container as event_container
8import telemetry.timeline.thread as tracing_thread
9from telemetry.timeline import memory_dump_event
10
11
12class Process(event_container.TimelineEventContainer):
13  """The Process represents a single userland process in the trace.
14  """
15  def __init__(self, parent, pid):
16    super(Process, self).__init__('process %s' % pid, parent)
17    self.pid = pid
18    self.labels = None
19    self.uptime_seconds = None
20    self._threads = {}
21    self._counters = {}
22    self._trace_buffer_overflow_event = None
23    self._memory_dump_events = {}
24
25  @property
26  def trace_buffer_did_overflow(self):
27    return self._trace_buffer_overflow_event is not None
28
29  @property
30  def trace_buffer_overflow_event(self):
31    return self._trace_buffer_overflow_event
32
33  @property
34  def threads(self):
35    return self._threads
36
37  @property
38  def counters(self):
39    return self._counters
40
41  def IterChildContainers(self):
42    for thread in self._threads.itervalues():
43      yield thread
44    for counter in self._counters.itervalues():
45      yield counter
46
47  def IterEventsInThisContainer(self, event_type_predicate, event_predicate):
48    if (self.trace_buffer_did_overflow and
49        event_type_predicate(event_module.TimelineEvent) and
50        event_predicate(self._trace_buffer_overflow_event)):
51      yield self._trace_buffer_overflow_event
52    if (self._memory_dump_events and
53        event_type_predicate(memory_dump_event.ProcessMemoryDumpEvent)):
54      for memory_dump in self._memory_dump_events.itervalues():
55        if event_predicate(memory_dump):
56          yield memory_dump
57
58  def GetOrCreateThread(self, tid):
59    thread = self.threads.get(tid, None)
60    if thread:
61      return thread
62    thread = tracing_thread.Thread(self, tid)
63    self._threads[tid] = thread
64    return thread
65
66  def GetCounter(self, category, name):
67    counter_id = category + '.' + name
68    if counter_id in self.counters:
69      return self.counters[counter_id]
70    raise ValueError(
71        'Counter %s not found in process with id %s.' % (counter_id,
72                                                         self.pid))
73  def GetOrCreateCounter(self, category, name):
74    try:
75      return self.GetCounter(category, name)
76    except ValueError:
77      ctr = tracing_counter.Counter(self, category, name)
78      self._counters[ctr.full_name] = ctr
79      return ctr
80
81  def AutoCloseOpenSlices(self, max_timestamp, thread_time_bounds):
82    for thread in self._threads.itervalues():
83      thread.AutoCloseOpenSlices(max_timestamp, thread_time_bounds[thread].max)
84
85  def SetTraceBufferOverflowTimestamp(self, timestamp):
86    # TODO: use instant event for trace_buffer_overflow_event
87    self._trace_buffer_overflow_event = event_module.TimelineEvent(
88        "TraceBufferInfo", "trace_buffer_overflowed", timestamp, 0)
89
90  def AddMemoryDumpEvent(self, memory_dump):
91    """Add a ProcessMemoryDumpEvent to this process."""
92    if memory_dump.dump_id in self._memory_dump_events:
93      raise ValueError('Duplicate memory dump id %s in process with id %s.' % (
94          memory_dump.dump_id, self.pid))
95    self._memory_dump_events[memory_dump.dump_id] = memory_dump
96
97  def FinalizeImport(self):
98    for thread in self._threads.itervalues():
99      thread.FinalizeImport()
100    for counter in self._counters.itervalues():
101      counter.FinalizeImport()
102