Update sdk/platform-tools to version 26.0.0.
[android_tools.git] / sdk / platform-tools / systrace / catapult / systrace / systrace / tracing_agents / ftrace_agent.py
blobcb1e7e15f28c3fa79180cfa8a007219b02159529
1 # Copyright 2015 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.
5 import optparse
6 import os
7 import py_utils
9 from systrace import trace_result
10 from systrace import tracing_agents
13 class FtraceAgentIo(object):
14 @staticmethod
15 def writeFile(path, data):
16 if FtraceAgentIo.haveWritePermissions(path):
17 with open(path, 'w') as f:
18 f.write(data)
19 else:
20 raise IOError('Cannot write to %s; did you forget sudo/root?' % path)
22 @staticmethod
23 def readFile(path):
24 with open(path, 'r') as f:
25 return f.read()
27 @staticmethod
28 def haveWritePermissions(path):
29 return os.access(path, os.W_OK)
32 FT_DIR = "/sys/kernel/debug/tracing/"
33 FT_CLOCK = FT_DIR + "trace_clock"
34 FT_BUFFER_SIZE = FT_DIR + "buffer_size_kb"
35 FT_TRACER = FT_DIR + "current_tracer"
36 FT_PRINT_TGID = FT_DIR + "options/print-tgid"
37 FT_TRACE_ON = FT_DIR + "tracing_on"
38 FT_TRACE = FT_DIR + "trace"
39 FT_TRACE_MARKER = FT_DIR + "trace_marker"
40 FT_OVERWRITE = FT_DIR + "options/overwrite"
42 all_categories = {
43 "sched": {
44 "desc": "CPU Scheduling",
45 "req": ["sched/sched_switch/", "sched/sched_wakeup/"]
47 "freq": {
48 "desc": "CPU Frequency",
49 "req": ["power/cpu_frequency/", "power/clock_set_rate/"]
51 "irq": {
52 "desc": "CPU IRQS and IPIS",
53 "req": ["irq/"],
54 "opt": ["ipi/"]
56 "workq": {
57 "desc": "Kernel workqueues",
58 "req": ["workqueue/"]
60 "memreclaim": {
61 "desc": "Kernel Memory Reclaim",
62 "req": ["vmscan/mm_vmscan_direct_reclaim_begin/",
63 "vmscan/mm_vmscan_direct_reclaim_end/",
64 "vmscan/mm_vmscan_kswapd_wake/",
65 "vmscan/mm_vmscan_kswapd_sleep/"]
67 "idle": {
68 "desc": "CPU Idle",
69 "req": ["power/cpu_idle/"]
71 "regulators": {
72 "desc": "Voltage and Current Regulators",
73 "req": ["regulator/"]
75 "disk": {
76 "desc": "Disk I/O",
77 "req": ["block/block_rq_issue/",
78 "block/block_rq_complete/"],
79 "opt": ["f2fs/f2fs_sync_file_enter/",
80 "f2fs/f2fs_sync_file_exit/",
81 "f2fs/f2fs_write_begin/",
82 "f2fs/f2fs_write_end/",
83 "ext4/ext4_da_write_begin/",
84 "ext4/ext4_da_write_end/",
85 "ext4/ext4_sync_file_enter/",
86 "ext4/ext4_sync_file_exit/"]
91 def try_create_agent(config):
92 if config.target != 'linux':
93 return None
94 return FtraceAgent(FtraceAgentIo)
97 def list_categories(_):
98 agent = FtraceAgent(FtraceAgentIo)
99 agent._print_avail_categories()
102 class FtraceConfig(tracing_agents.TracingConfig):
103 def __init__(self, ftrace_categories, target, trace_buf_size):
104 tracing_agents.TracingConfig.__init__(self)
105 self.ftrace_categories = ftrace_categories
106 self.target = target
107 self.trace_buf_size = trace_buf_size
110 def add_options(parser):
111 options = optparse.OptionGroup(parser, 'Ftrace options')
112 options.add_option('--ftrace-categories', dest='ftrace_categories',
113 help='Select ftrace categories with a comma-delimited '
114 'list, e.g. --ftrace-categories=cat1,cat2,cat3')
115 return options
118 def get_config(options):
119 return FtraceConfig(options.ftrace_categories, options.target,
120 options.trace_buf_size)
123 class FtraceAgent(tracing_agents.TracingAgent):
125 def __init__(self, fio=FtraceAgentIo):
126 """Initialize a systrace agent.
128 Args:
129 config: The command-line config.
130 categories: The trace categories to capture.
132 super(FtraceAgent, self).__init__()
133 self._fio = fio
134 self._config = None
135 self._categories = None
137 def _get_trace_buffer_size(self):
138 buffer_size = 4096
139 if ((self._config.trace_buf_size is not None)
140 and (self._config.trace_buf_size > 0)):
141 buffer_size = self._config.trace_buf_size
142 return buffer_size
144 def _fix_categories(self, categories):
146 Applies the default category (sched) if there are no categories
147 in the list and removes unavailable categories from the list.
148 Args:
149 categories: List of categories.
151 if not categories:
152 categories = ["sched"]
153 return [x for x in categories
154 if self._is_category_available(x)]
156 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
157 def StartAgentTracing(self, config, timeout=None):
158 """Start tracing.
160 self._config = config
161 categories = self._fix_categories(config.ftrace_categories)
162 self._fio.writeFile(FT_BUFFER_SIZE,
163 str(self._get_trace_buffer_size()))
164 self._fio.writeFile(FT_CLOCK, 'global')
165 self._fio.writeFile(FT_TRACER, 'nop')
166 self._fio.writeFile(FT_OVERWRITE, "0")
168 # TODO: riandrews to push necessary patches for TGID option to upstream
169 # linux kernel
170 # self._fio.writeFile(FT_PRINT_TGID, '1')
172 for category in categories:
173 self._category_enable(category)
175 self._categories = categories # need to store list of categories to disable
176 print 'starting tracing.'
178 self._fio.writeFile(FT_TRACE, '')
179 self._fio.writeFile(FT_TRACE_ON, '1')
180 return True
182 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
183 def StopAgentTracing(self, timeout=None):
184 """Collect the result of tracing.
186 This function will block while collecting the result. For sync mode, it
187 reads the data, e.g., from stdout, until it finishes. For async mode, it
188 blocks until the agent is stopped and the data is ready.
190 self._fio.writeFile(FT_TRACE_ON, '0')
191 for category in self._categories:
192 self._category_disable(category)
193 return True
195 @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
196 def GetResults(self, timeout=None):
197 # get the output
198 d = self._fio.readFile(FT_TRACE)
199 self._fio.writeFile(FT_BUFFER_SIZE, "1")
200 return trace_result.TraceResult('trace-data', d)
202 def SupportsExplicitClockSync(self):
203 return False
205 def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
206 # No implementation, but need to have this to support the API
207 # pylint: disable=unused-argument
208 return False
210 def _is_category_available(self, category):
211 if category not in all_categories:
212 return False
213 events_dir = FT_DIR + "events/"
214 req_events = all_categories[category]["req"]
215 for event in req_events:
216 event_full_path = events_dir + event + "enable"
217 if not self._fio.haveWritePermissions(event_full_path):
218 return False
219 return True
221 def _avail_categories(self):
222 ret = []
223 for event in all_categories:
224 if self._is_category_available(event):
225 ret.append(event)
226 return ret
228 def _print_avail_categories(self):
229 avail = self._avail_categories()
230 if len(avail):
231 print "tracing config:"
232 for category in self._avail_categories():
233 desc = all_categories[category]["desc"]
234 print "{0: <16}".format(category), ": ", desc
235 else:
236 print "No tracing categories available - perhaps you need root?"
238 def _category_enable_paths(self, category):
239 events_dir = FT_DIR + "events/"
240 req_events = all_categories[category]["req"]
241 for event in req_events:
242 event_full_path = events_dir + event + "enable"
243 yield event_full_path
244 if "opt" in all_categories[category]:
245 opt_events = all_categories[category]["opt"]
246 for event in opt_events:
247 event_full_path = events_dir + event + "enable"
248 if self._fio.haveWritePermissions(event_full_path):
249 yield event_full_path
251 def _category_enable(self, category):
252 for path in self._category_enable_paths(category):
253 self._fio.writeFile(path, "1")
255 def _category_disable(self, category):
256 for path in self._category_enable_paths(category):
257 self._fio.writeFile(path, "0")