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.
8 from profile_chrome
import controllers
9 from profile_chrome
import util
11 from pylib
import cmd_helper
15 # Compress the trace before sending it over USB.
17 # Use a large trace buffer to increase the polling interval.
21 # Interval in seconds for sampling systrace data.
22 _SYSTRACE_INTERVAL
= 15
24 _TRACING_ON_PATH
= '/sys/kernel/debug/tracing/tracing_on'
27 class SystraceController(controllers
.BaseController
):
28 def __init__(self
, device
, categories
, ring_buffer
):
29 controllers
.BaseController
.__init
__(self
)
31 self
._categories
= categories
32 self
._ring
_buffer
= ring_buffer
33 self
._done
= threading
.Event()
35 self
._trace
_data
= None
41 def GetCategories(device
):
42 return device
.RunShellCommand('atrace --list_categories')
44 def StartTracing(self
, _
):
45 self
._thread
= threading
.Thread(target
=self
._CollectData
)
48 def StopTracing(self
):
55 output_name
= 'systrace-%s' % util
.GetTraceTimestamp()
56 with
open(output_name
, 'w') as out
:
57 out
.write(self
._trace
_data
)
60 def IsTracingOn(self
):
61 result
= self
._RunAdbShellCommand
(['cat', _TRACING_ON_PATH
])
62 return result
.strip() == '1'
64 def _RunAdbShellCommand(self
, command
):
65 # We use a separate interface to adb because the one from AndroidCommands
67 # TODO(jbudorick) Look at providing a way to unhandroll this once the
68 # adb rewrite has fully landed.
69 device_param
= (['-s', str(self
._device
)] if str(self
._device
) else [])
70 cmd
= ['adb'] + device_param
+ ['shell'] + command
71 return cmd_helper
.GetCmdOutput(cmd
)
73 def _RunATraceCommand(self
, command
):
74 cmd
= ['atrace', '--%s' % command
] + _SYSTRACE_OPTIONS
+ self
._categories
75 return self
._RunAdbShellCommand
(cmd
)
77 def _ForceStopAtrace(self
):
78 # atrace on pre-M Android devices cannot be stopped asynchronously
79 # correctly. Use synchronous mode to force stop.
80 cmd
= ['atrace', '-t', '0']
81 return self
._RunAdbShellCommand
(cmd
)
83 def _CollectData(self
):
85 self
._RunATraceCommand
('async_start')
87 while not self
._done
.is_set():
88 self
._done
.wait(_SYSTRACE_INTERVAL
)
89 if not self
._ring
_buffer
or self
._done
.is_set():
91 self
._DecodeTraceData
(self
._RunATraceCommand
('async_dump')))
94 self
._DecodeTraceData
(self
._RunATraceCommand
('async_stop')))
95 if self
.IsTracingOn():
96 self
._ForceStopAtrace
()
97 self
._trace
_data
= ''.join([zlib
.decompress(d
) for d
in trace_data
])
100 def _DecodeTraceData(trace_data
):
102 trace_start
= trace_data
.index('TRACE:')
104 raise RuntimeError('Systrace start marker not found')
105 trace_data
= trace_data
[trace_start
+ 6:]
107 # Collapse CRLFs that are added by adb shell.
108 if trace_data
.startswith('\r\n'):
109 trace_data
= trace_data
.replace('\r\n', '\n')
111 # Skip the initial newline.
112 return trace_data
[1:]