当前位置:网站首页>Systrace parsing
Systrace parsing
2022-04-23 07:26:00 【pwl999】
The picture above basically makes it clear systrace The whole framework of :
- 1、systrace call atrace Grab the of the target machine trace data ;
- 2、systrace hold trace Data and ’prefix.html’、‘suffix.html’、'systrace_trace_viewer.html’ Synthesis of a ’trace.html’ file ;
- 3、 Use chrome Browser open ’trace.html’ It is very convenient to view and analyze in graphical form trace data . Behind is Trace-Viewer Your script is running ;
Kernel state and user state storage trace Data implementation :
- 1、 kernel trace Information , adopt trace event It was recorded that ftrace Of buffer in ;
- 2、 User mode (app/java framework/native) By using Trace Class to record trace The information of , Also recorded to the kernel ftrace buffer In the middle of , It's through "/sys/kernel/debug/tracing/trace_marker" Interface record .
1、systrace Use
In positioning Android When it comes to performance issues , We often use systrace Tools . Configuration to adb, Connect to the target mobile phone , Use a similar command on the host side to start systrace:
ASOP_ROOT/external/chromium-trace/catapult/systrace/bin$ ./systrace -o trace.html -t 10 gfx view wm am dalvik input sched freq idle
Starting tracing (10 seconds)
Tracing completed. Collecting output...
Outputting Systrace results...
Tracing complete, writing results
Wrote trace HTML file: file:///ASOP_ROOT/external/chromium-trace/catapult/systrace/bin/trace.html
systrace Command in ASOP Source package ASOP_ROOT/external/chromium-trace/catapult/systrace/bin Under the path . The parameters of the above command :
- ‘-t 10’, Grab... Is specified trace The duration is 10s;
- ‘-o trace.html’, It specifies trace Output file for ;
- ‘gfx view wm am dalvik input sched freq idle’, Specifies the event to be fetched ;
After the command starts , We can slide on the target 、 start-up app A series of operations ,10s These operations will be recorded in the final dump Into the trace.html file . We can go through google Of chrome Browser to see 、 analysis trace.html:‘google-chrome trace.html’.
[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-qqCrtMms-1614825016918)(FD8E0E30D8DE443AA3E1B1CA80D33780)]
Can pass ’-l’ Option to view the supported systrace A complete collection of events :
$ ./systrace -l
gfx - Graphics
input - Input
view - View System
webview - WebView
wm - Window Manager
am - Activity Manager
sm - Sync Manager
audio - Audio
video - Video
camera - Camera
hal - Hardware Modules
app - Application
res - Resource Loading
dalvik - Dalvik VM
rs - RenderScript
bionic - Bionic C Library
power - Power Management
pm - Package Manager
ss - System Server
database - Database
network - Network
adb - ADB
pdx - PDX services
sched - CPU Scheduling
irq - IRQ Events
freq - CPU Frequency
idle - CPU Idle
disk - Disk I/O
workq - Kernel Workqueues
memreclaim - Kernel Memory Reclaim
regulators - Voltage and Current Regulators
binder_driver - Binder Kernel driver
binder_lock - Binder global lock trace
pagecache - Page cache
NOTE: more categories may be available with adb root
You can also use ’–help’ Options to see systrace Detailed options of the command :
$ ./systrace --help
Usage: systrace [options] [category1 [category2 ...]]
Example: systrace -b 32768 -t 15 gfx input view sched freq
Options:
-h, --help show this help message and exit
-o FILE write trace output to FILE
-j, --json write a JSON file
--link-assets (deprecated)
--asset-dir=ASSET_DIR
(deprecated)
-e DEVICE_SERIAL_NUMBER, --serial=DEVICE_SERIAL_NUMBER
adb device serial number
--timeout=TIMEOUT timeout for start and stop tracing (seconds)
--collection-timeout=COLLECTION_TIMEOUT
timeout for data collection (seconds)
-t N, --time=N trace for N seconds
--target=TARGET choose tracing target (android or linux)
-b N, --buf-size=N use a trace buffer size of N KB
-l, --list-categories
list the available categories and exit
Atrace options:
--atrace-categories=ATRACE_CATEGORIES
Select atrace categories with a comma-delimited list,
e.g. --atrace-categories=cat1,cat2,cat3
-k KFUNCS, --ktrace=KFUNCS
specify a comma-separated list of kernel functions to
trace
--no-compress Tell the device not to send the trace data in
compressed form.
-a APP_NAME, --app=APP_NAME
enable application-level tracing for comma-separated
list of app cmdlines
--from-file=FROM_FILE
read the trace from a file (compressed) rather than
running a live trace
BattOr trace options:
--battor-categories=BATTOR_CATEGORIES
Select battor categories with a comma-delimited list,
e.g. --battor-categories=cat1,cat2,cat3
--serial-map=SERIAL_MAP
File containing pregenerated map of phone serial
numbers to BattOr serial numbers.
--battor-path=BATTOR_PATH
specify a BattOr path to use
--battor Use the BattOr tracing agent.
Ftrace options:
--ftrace-categories=FTRACE_CATEGORIES
Select ftrace categories with a comma-delimited list,
e.g. --ftrace-categories=cat1,cat2,cat3
WALT trace options:
--walt Use the WALT tracing agent. WALT is a device for
measuring latency of physical sensors on phones and
computers. See https://github.com/google/walt
2、 host systrace Implementation of commands (python)
systrace It's essentially a python file , Whole python Related packages are in ASOP_ROOT/external/chromium-trace/catapult/ Under the path , Take this path as the root (root=ASOP_ROOT/external/chromium-trace/catapult), Let's analyze its implementation process :
./systrace/bin/systrace:
import os
import sys
# (1) take './systrace/' The path is added to python Search path for #
_SYSTRACE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
sys.path.insert(0, _SYSTRACE_DIR)
# (2) So we can find './systrace/systrace/run_systrace.py' Module and import #
from systrace import run_systrace
# (3) call run_systrace.py Module main() function #
if __name__ == '__main__':
sys.exit(run_systrace.main())
↓
./systrace/systrace/run_systrace.py:
# (3.1) main() The function continues to call main_impl() function #
def main():
main_impl(sys.argv)
↓
def main_impl(arguments):
# Parse the command line options.
# (3.1.1) Parse the parameters entered by the user into options and categories #
options, categories = parse_options(arguments)
# Override --atrace-categories and --ftrace-categories flags if command-line
# categories are provided.
# (3.1.2) If it resolves trace event categories #
# according to options.target Specified platform 'android'/'linux', Here it is options Assignment of options in #
# The platform is to use sytrace Ordered '--target=TARGET' Option to specify , If not specified, the default value is 'android' #
if categories:
if options.target == 'android':
options.atrace_categories = categories
elif options.target == 'linux':
options.ftrace_categories = categories
else:
raise RuntimeError('Categories are only valid for atrace/ftrace. Target '
'platform must be either Android or Linux.')
↓
./systrace/systrace/run_systrace.py:
# Include atrace categories by default in Systrace.
# (3.1.3) If the platform is 'android', And there is no designation trace event , Give the default trace event #
if options.target == 'android' and not options.atrace_categories:
options.atrace_categories = atrace_agent.DEFAULT_CATEGORIES
# (3.1.4) If the platform is 'android', And not reading data from a file , Then it is to read data from the actual target machine #
if options.target == 'android' and not options.from_file:
# initialization adb #
initialize_devil()
# If the target machine is not specified serialnumber, Attempt to read #
if not options.device_serial_number:
devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
if len(devices) == 0:
raise RuntimeError('No ADB devices connected.')
elif len(devices) >= 2:
raise RuntimeError('Multiple devices connected, serial number required')
options.device_serial_number = devices[0]
# If list_categories is selected, just print the list of categories.
# In this case, use of the tracing controller is not necessary.
# (3.1.5) If it is currently 'systrace -l' command , List all supported by the target trace Return directly after the event #
if options.list_categories:
if options.target == 'android':
# call 'systrace/systrace/tracing_agents/atrace_agent.py' In the document list_categories() function #
# The last thing to call is `adb shell atrace --list_categories' command #
atrace_agent.list_categories(options)
elif options.target == 'linux':
ftrace_agent.list_categories(options)
return
# Set up the systrace runner and start tracing.
# (3.1.6) If it's normal trace command , according to 'systrace/systrace/systrace_runner.py' Module SystraceRunner Class to create objects #
controller = systrace_runner.SystraceRunner(
os.path.dirname(os.path.abspath(__file__)), options)
# (3.1.6.1) Start tracing #
controller.StartTracing()
# Wait for the given number of seconds or until the user presses enter.
# pylint: disable=superfluous-parens
# (need the parens so no syntax error if trying to load with Python 3)
if options.from_file is not None:
print('Reading results from file.')
elif options.trace_time:
print('Starting tracing (%d seconds)' % options.trace_time)
time.sleep(options.trace_time)
else:
raw_input('Starting tracing (stop with enter)')
# Stop tracing and collect the output.
print('Tracing completed. Collecting output...')
# (3.1.6.2) stop it tracing #
controller.StopTracing()
print('Outputting Systrace results...')
# (3.1.6.3) Output tracing The results are in the file #
controller.OutputSystraceResults(write_json=options.write_json)
We can see trace The focus of the discussion finally falls on SystraceRunner Object creation , as well as .StartTracing()/.StopTracing()/.OutputSystraceResults() In several ways .
Let's analyze the implementation process of these steps in detail .
2.1、SystraceRunner Class initialization
SystraceRunner Class in systrace_runner.py The file of , Let's look at the specific implementation .
./systrace/systrace/systrace_runner.py:
AGENT_MODULES = [android_process_data_agent, atrace_agent,
atrace_from_file_agent, battor_trace_agent,
ftrace_agent, walt_agent]
class SystraceRunner(object):
def __init__(self, script_dir, options):
"""Constructor.
Args:
script_dir: Directory containing the trace viewer script
(systrace_trace_viewer.html)
options: Object containing command line options.
"""
# Parse command line arguments and create agents.
self._script_dir = script_dir
self._out_filename = options.output_file
# (1) #
agents_with_config = tracing_controller.CreateAgentsWithConfig(
options, AGENT_MODULES)
# (2) #
controller_config = tracing_controller.GetControllerConfig(options)
# Set up tracing controller.
# (3) #
self._tracing_controller = tracing_controller.TracingController(
agents_with_config, controller_config)
- 1、 analysis tracing_controller.CreateAgentsWithConfig() The implementation of the ;
./systrace/systrace/tracing_controller.py:
def CreateAgentsWithConfig(options, modules):
"""Create tracing agents.
This function will determine which tracing agents are valid given the
options and create those agents along with their corresponding configuration
object.
Args:
options: The command-line options.
modules: The modules for either Systrace or profile_chrome.
TODO(washingtonp): After all profile_chrome agents are in
Systrace, this parameter will no longer be valid.
Returns:
A list of AgentWithConfig options containing agents and their corresponding
configuration object.
"""
result = []
# (1.1) Traverse modules Medium agent Call the corresponding function . Yes 'android' Come on , Basically, it will only call atrace_agent、android_process_data_agent #
for module in modules:
# (1.1.1) #
config = module.get_config(options)
# (1.1.2) #
agent = module.try_create_agent(config)
if agent and config:
# (1.1.3) Create a AgentWithConfig Class object , Used to store config and agent #
result.append(AgentWithConfig(agent, config))
return [x for x in result if x and x.agent]
|→
./systrace/systrace/tracing_agents/atrace_agent.py:
# (1.1.1) Create a AtraceConfig Class object , Used to store optios Related configuration in #
def get_config(options):
return AtraceConfig(options.atrace_categories,
options.trace_buf_size, options.kfuncs,
options.app_name, options.compress_trace_data,
options.from_file, options.device_serial_number,
options.trace_time, options.target)
↓
class AtraceConfig(tracing_agents.TracingConfig):
def __init__(self, atrace_categories, trace_buf_size, kfuncs,
app_name, compress_trace_data, from_file,
device_serial_number, trace_time, target):
tracing_agents.TracingConfig.__init__(self)
self.atrace_categories = atrace_categories
self.trace_buf_size = trace_buf_size
self.kfuncs = kfuncs
self.app_name = app_name
self.compress_trace_data = compress_trace_data
self.from_file = from_file
self.device_serial_number = device_serial_number
self.trace_time = trace_time
self.target = target
# (1.1.2) Create a AtraceAgent Class object #
def try_create_agent(config):
"""Create an Atrace agent.
Args:
config: Command line config.
"""
# according to config Configuration of , Judge the present Atrace agent Do you need to create #
if config.target != 'android':
return None
if config.from_file is not None:
return None
if not config.atrace_categories:
return None
# Check device SDK version.
device_sdk_version = util.get_device_sdk_version()
if device_sdk_version < version_codes.JELLY_BEAN_MR2:
print ('Device SDK versions < 18 (Jellybean MR2) not supported.\n'
'Your device SDK version is %d.' % device_sdk_version)
return None
return AtraceAgent(device_sdk_version)
↓
class AtraceAgent(tracing_agents.TracingAgent):
def __init__(self, device_sdk_version):
super(AtraceAgent, self).__init__()
self._device_sdk_version = device_sdk_version
self._adb = None
self._trace_data = None
self._tracer_args = None
self._collection_thread = None
self._device_utils = None
self._device_serial_number = None
self._config = None
self._categories = None
|→
./systrace/systrace/tracing_agents/android_process_data_agent.py:
def try_create_agent(config):
if config.target != 'android':
return None
if config.from_file is not None:
return None
return AndroidProcessDataAgent()
↓
class AndroidProcessDataAgent(tracing_agents.TracingAgent):
def __init__(self):
super(AndroidProcessDataAgent, self).__init__()
self._trace_data = ""
self._device = None
- 2、 analysis tracing_controller.GetControllerConfig() The implementation of the ;
./systrace/systrace/tracing_controller.py:
# (2.1) Create a TracingControllerConfig Class object , Used to store optios Related configuration in #
def GetControllerConfig(options):
return TracingControllerConfig(options.output_file, options.trace_time,
options.write_json,
options.link_assets, options.asset_dir,
options.timeout, options.collection_timeout,
options.device_serial_number, options.target)
↓
class TracingControllerConfig(tracing_agents.TracingConfig):
def __init__(self, output_file, trace_time, write_json,
link_assets, asset_dir, timeout, collection_timeout,
device_serial_number, target):
tracing_agents.TracingConfig.__init__(self)
self.output_file = output_file
self.trace_time = trace_time
self.write_json = write_json
self.link_assets = link_assets
self.asset_dir = asset_dir
self.timeout = timeout
self.collection_timeout = collection_timeout
self.device_serial_number = device_serial_number
self.target = target
- 3、 analysis tracing_controller.TracingController() The implementation of the ;
./systrace/systrace/tracing_controller.py:
# (3.1) Create a TracingController Class object , Later start/stop/output All operations use the object's methods #
class TracingController(object):
def __init__(self, agents_with_config, controller_config):
"""Create tracing controller.
Create a tracing controller object. Note that the tracing
controller is also a tracing agent.
Args:
agents_with_config: List of tracing agents for this controller with the
corresponding tracing configuration objects.
controller_config: Configuration options for the tracing controller.
"""
self._child_agents = None
# (3.1.1) Storage agent Objects and config #
self._child_agents_with_config = agents_with_config
# (3.1.2) Create a new one TracingControllerAgent Class object #
self._controller_agent = TracingControllerAgent()
# (3.1.3) Storage controller Hierarchical config #
self._controller_config = controller_config
self._trace_in_progress = False
self.all_results = None
2.2、SystraceRunner.StartTracing()
The entrance is SystraceRunner Class .StartTracing() Method ,./systrace/systrace/systrace_runner.py:
class SystraceRunner(object):
def StartTracing(self):
# (1) #
self._tracing_controller.StartTracing()
↓
Continue calling to TracingController Class .StartTracing() Method ,./systrace/systrace/tracing_controller.py:
class TracingController(object):
def StartTracing(self):
"""Start tracing for all tracing agents.
This function starts tracing for both the controller tracing agent
and the child tracing agents.
Returns:
Boolean indicating whether or not the start tracing succeeded.
Start tracing is considered successful if at least the
controller tracing agent was started.
"""
# (1.1) Set... In the object tracing Start up sign #
assert not self._trace_in_progress, 'Trace already in progress.'
self._trace_in_progress = True
# Start the controller tracing agents. Controller tracing agent
# must be started successfully to proceed.
# (1.2) Start member object _controller_agent Of .StartAgentTracing() Method #
# Record some log #
if not self._controller_agent.StartAgentTracing(
self._controller_config,
timeout=self._controller_config.timeout):
print 'Unable to start controller tracing agent.'
return False
# Start the child tracing agents.
succ_agents = []
# (1.3) Start one by one agent list in agent Of .StartAgentTracing() Method #
# Yes 'Android' Come on , Just one agent:AtraceAgent #
for agent_and_config in self._child_agents_with_config:
agent = agent_and_config.agent
config = agent_and_config.config
# start-up agent #
if agent.StartAgentTracing(config,
timeout=self._controller_config.timeout):
# Start the successful agent Join in succ_agents list #
succ_agents.append(agent)
else:
print 'Agent %s not started.' % str(agent)
# Print warning if all agents not started.
na = len(self._child_agents_with_config)
ns = len(succ_agents)
if ns < na:
print 'Warning: Only %d of %d tracing agents started.' % (ns, na)
self._child_agents = succ_agents
return True
|→
Continue calling to AtraceAgent Class .StartTracing() Method ,./systrace/systrace/tracing_agents/atrace_agent.py:
class AtraceAgent(tracing_agents.TracingAgent):
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
assert config.atrace_categories, 'Atrace categories are missing!'
self._config = config
# systrace The need to give orders trace Events #
self._categories = config.atrace_categories
if isinstance(self._categories, list):
self._categories = ','.join(self._categories)
# Use 'atrace --list_categories' Get the supported executable of the target machine trace event #
avail_cats = get_available_categories(config, self._device_sdk_version)
# (1.3.1) Determine whether there are any commands that the target machine does not support trace event #
unavailable = [x for x in self._categories.split(',') if
x not in avail_cats]
self._categories = [x for x in self._categories.split(',') if
x in avail_cats]
if unavailable:
print 'These categories are unavailable: ' + ' '.join(unavailable)
self._device_utils = device_utils.DeviceUtils(config.device_serial_number)
self._device_serial_number = config.device_serial_number
# (1.3.2) Construction parameters :'atrace ... categories' #
# '...' Include the following options : #
# '-z': compress_trace_data #
# '-t trace_time' #
# '-b trace_buf_size' #
# '-a app_name' #
# '-k kfuncs' #
self._tracer_args = _construct_atrace_args(config,
self._categories)
# (1.3.3) Carry out orders :'atrace ... categories --async_start' #
self._device_utils.RunShellCommand(
self._tracer_args + ['--async_start'], check_return=True)
return True
|→
Continue calling to AndroidProcessDataAgent Class .StartTracing() Method ,./systrace/systrace/tracing_agents/android_process_data_agent.py:
class AndroidProcessDataAgent(tracing_agents.TracingAgent):
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._device = device_utils.DeviceUtils(config.device_serial_number)
self._trace_data += self._get_process_snapshot()
return True
↓
def _get_process_snapshot(self):
use_legacy = False
try:
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC, check_return=True, as_root=True, shell=True)
except AdbShellCommandFailedError:
use_legacy = True
# Check length of 2 as we execute two commands, which in case of failure
# on old devices output 1 line each.
if use_legacy or len(dump) == 2:
logging.debug('Couldn\'t parse ps dump, trying legacy method ...')
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC_LEGACY, check_return=True, as_root=True, shell=True)
if len(dump) == 2:
logging.error('Unable to extract process data!')
return ""
return '\n'.join(dump) + '\n'
# In fact, it is StartTracing() and StopTracing() when , Call the following... Once each ps command #
PS_COMMAND_PROC = "ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM" \
"&& ps -AT -o USER,PID,TID,CMD"
2.3、SystraceRunner.StopTracing()
The entrance is SystraceRunner Class .StopTracing() Method ,./systrace/systrace/systrace_runner.py:
class SystraceRunner(object):
def StopTracing(self):
# (1) #
self._tracing_controller.StopTracing()
↓
Continue calling to TracingController Class .StopTracing() Method ,./systrace/systrace/tracing_controller.py:
class TracingController(object):
def StopTracing(self):
"""Issue clock sync marker and stop tracing for all tracing agents.
This function stops both the controller tracing agent
and the child tracing agents. It issues a clock sync marker prior
to stopping tracing.
Returns:
Boolean indicating whether or not the stop tracing succeeded
for all agents.
"""
# (1.1) Clear... From the object tracing Start up sign #
assert self._trace_in_progress, 'No trace in progress.'
self._trace_in_progress = False
# Issue the clock sync marker and stop the child tracing agents.
self._IssueClockSyncMarker()
succ_agents = []
# (1.2) One by one call agent list in agent Of .StopAgentTracing() Method #
# Yes 'Android' Come on , Just one agent:AtraceAgent #
for agent in self._child_agents:
if agent.StopAgentTracing(timeout=self._controller_config.timeout):
succ_agents.append(agent)
else:
print 'Agent %s not stopped.' % str(agent)
# Stop the controller tracing agent. Controller tracing agent
# must be stopped successfully to proceed.
# (1.3) Call member object _controller_agent Of .StartAgentTracing() Method #
# Record some log #
if not self._controller_agent.StopAgentTracing(
timeout=self._controller_config.timeout):
print 'Unable to stop controller tracing agent.'
return False
# Print warning if all agents not stopped.
na = len(self._child_agents)
ns = len(succ_agents)
if ns < na:
print 'Warning: Only %d of %d tracing agents stopped.' % (ns, na)
self._child_agents = succ_agents
# Collect the results from all the stopped tracing agents.
all_results = []
# (1.4) Summary agent list in agent And member objects _controller_agent be-all result #
for agent in self._child_agents + [self._controller_agent]:
try:
result = agent.GetResults(
timeout=self._controller_config.collection_timeout)
if not result:
print 'Warning: Timeout when getting results from %s.' % str(agent)
continue
if result.source_name in [r.source_name for r in all_results]:
print ('Warning: Duplicate tracing agents named %s.' %
result.source_name)
all_results.append(result)
# Check for exceptions. If any exceptions are seen, reraise and abort.
# Note that a timeout exception will be swalloed by the timeout
# mechanism and will not get to that point (it will return False instead
# of the trace result, which will be dealt with above)
except:
print 'Warning: Exception getting results from %s:' % str(agent)
print sys.exc_info()[0]
raise
self.all_results = all_results
return all_results
|→
Continue calling to AtraceAgent Class .StopAgentTracing() Method ,./systrace/systrace/tracing_agents/atrace_agent.py:
class AtraceAgent(tracing_agents.TracingAgent):
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Stops tracing and starts collecting results.
To synchronously retrieve the results after calling this function,
call GetResults().
"""
# (1.2.1) start-up stop tracing The thread of #
self._collection_thread = threading.Thread(
target=self._collect_and_preprocess)
self._collection_thread.start()
return True
↓
def _collect_and_preprocess(self):
"""Collects and preprocesses trace data.
Stores results in self._trace_data.
"""
# (1.2.1.1) dump trace data , and stop tracing #
trace_data = self._collect_trace_data()
# (1.2.1.2) Acquired trace Data preprocessing #
self._trace_data = self._preprocess_trace_data(trace_data)
↓
def _collect_trace_data(self):
"""Reads the output from atrace and stops the trace."""
# (1.2.1.1.1) dump Out trace data #
# Carry out orders :'atrace ... categories --async_dump' #
dump_cmd = self._tracer_args + ['--async_dump']
result = self._device_utils.RunShellCommand(
dump_cmd, raw_output=True, large_output=True, check_return=True)
# (1.2.1.1.2) find trace In the data 'TRACE\:' The starting position #
data_start = re.search(TRACE_START_REGEXP, result)
if data_start:
data_start = data_start.end(0)
else:
raise IOError('Unable to get atrace data. Did you forget adb root?')
# (1.2.1.1.3) eliminate trace Similar invalid data in data :r'^capturing trace\.\.\. done|^capturing trace\.\.\.' #
output = re.sub(ADB_IGNORE_REGEXP, '', result[data_start:])
# (1.2.1.1.4) stop tracing #
# Carry out orders :'atrace ... categories --async_stop' #
self._stop_trace()
return output
def _preprocess_trace_data(self, trace_data):
"""Performs various processing on atrace data.
Args:
trace_data: The raw trace data.
Returns:
The processed trace data.
"""
# (1.2.1.2.1) Yes trace Data for some strp And decompress #
if trace_data:
trace_data = strip_and_decompress_trace(trace_data)
if not trace_data:
print >> sys.stderr, ('No data was captured. Output file was not '
'written.')
sys.exit(1)
# (1.2.1.2.2) Repair MISSING_TGIDS #
if _FIX_MISSING_TGIDS:
# Gather proc data from device and patch tgids
procfs_dump = self._device_utils.RunShellCommand(
'echo -n /proc/[0-9]*/task/[0-9]*',
shell=True, check_return=True)[0].split(' ')
pid2_tgid = extract_tgids(procfs_dump)
trace_data = fix_missing_tgids(trace_data, pid2_tgid)
# (1.2.1.2.3) Repair CIRCULAR_TRACES #
if _FIX_CIRCULAR_TRACES:
trace_data = fix_circular_traces(trace_data)
return trace_data
|→
Continue calling to AndroidProcessDataAgent Class .StopAgentTracing() Method ,./systrace/systrace/tracing_agents/android_process_data_agent.py:
class AndroidProcessDataAgent(tracing_agents.TracingAgent):
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
self._trace_data += self._get_process_snapshot()
return True
↓
def _get_process_snapshot(self):
use_legacy = False
try:
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC, check_return=True, as_root=True, shell=True)
except AdbShellCommandFailedError:
use_legacy = True
# Check length of 2 as we execute two commands, which in case of failure
# on old devices output 1 line each.
if use_legacy or len(dump) == 2:
logging.debug('Couldn\'t parse ps dump, trying legacy method ...')
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC_LEGACY, check_return=True, as_root=True, shell=True)
if len(dump) == 2:
logging.error('Unable to extract process data!')
return ""
return '\n'.join(dump) + '\n'
# In fact, it is StartTracing() and StopTracing() when , Call the following... Once each ps command #
PS_COMMAND_PROC = "ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM" \
"&& ps -AT -o USER,PID,TID,CMD"
2.4、SystraceRunner.OutputSystraceResults()
The entrance is SystraceRunner Class .OutputSystraceResults() Method ,./systrace/systrace/systrace_runner.py:
class SystraceRunner(object):
def OutputSystraceResults(self, write_json=False):
"""Output the results of systrace to a file.
If output is necessary, then write the results of systrace to either (a)
a standalone HTML file, or (b) a json file which can be read by the
trace viewer.
Args:
write_json: Whether to output to a json file (if false, use HTML file)
"""
print 'Tracing complete, writing results'
if write_json:
# (1) Output into jason Format #
result = output_generator.GenerateJSONOutput(
self._tracing_controller.all_results,
self._out_filename)
else:
# (2) Output into html Format #
# all_results It's the last step stoptracing When you get trace result #
# _out_filename It's using '-o' File name specified by option #
result = output_generator.GenerateHTMLOutput(
self._tracing_controller.all_results,
self._out_filename)
print '\nWrote trace %s file: file://%s\n' % (('JSON' if write_json
else 'HTML'), result)
↓
Continue calling to output_generator Module GenerateHTMLOutput() function ,./systrace/systrace/output_generator.py:
def GenerateHTMLOutput(trace_results, output_file_name):
"""Write the results of systrace to an HTML file.
Args:
trace_results: A list of TraceResults.
output_file_name: The name of the HTML file that the trace viewer
results should be written to.
"""
def _ReadAsset(src_dir, filename):
return open(os.path.join(src_dir, filename)).read()
# TODO(rnephew): The tracing output formatter is able to handle a single
# systrace trace just as well as it handles multiple traces. The obvious thing
# to do here would be to use it all for all systrace output: however, we want
# to continue using the legacy way of formatting systrace output when a single
# systrace and the tracing controller trace are present in order to match the
# Java verison of systrace. Java systrace is expected to be deleted at a later
# date. We should consolidate this logic when that happens.
# (2.1) If result list The number of members in is greater than 3, Using new methods NewGenerateHTMLOutput #
if len(trace_results) > 3:
NewGenerateHTMLOutput(trace_results, output_file_name)
return os.path.abspath(output_file_name)
systrace_dir = os.path.abspath(os.path.dirname(__file__))
# (2.2) Try to update ./systrace/systrace/systrace_trace_viewer.html file #
try:
from systrace import update_systrace_trace_viewer
except ImportError:
pass
else:
update_systrace_trace_viewer.update()
trace_viewer_html = _ReadAsset(systrace_dir, 'systrace_trace_viewer.html')
# Open the file in binary mode to prevent python from changing the
# line endings, then write the prefix.
# (2.3) read out 'prefix.html','suffix.html','systrace_trace_viewer.html' The contents of the file are for backup #
systrace_dir = os.path.abspath(os.path.dirname(__file__))
html_prefix = _ReadAsset(systrace_dir, 'prefix.html')
html_suffix = _ReadAsset(systrace_dir, 'suffix.html')
trace_viewer_html = _ReadAsset(systrace_dir,
'systrace_trace_viewer.html')
# Open the file in binary mode to prevent python from changing the
# line endings, then write the prefix.
# (2.4) Open a file named 'xxx.html' Output file for , Prepare to write #
html_file = open(output_file_name, 'wb')
# (2.4.1) First write 'prefix.html' The content of #
# And put the '{
{SYSTRACE_TRACE_VIEWER_HTML}}' The characters are 'systrace_trace_viewer.html' Replace with the contents of the file #
html_file.write(html_prefix.replace('{
{SYSTRACE_TRACE_VIEWER_HTML}}',
trace_viewer_html))
# Write the trace data itself. There is a separate section of the form
# <script class="trace-data" type="application/text"> ... </script>
# for each tracing agent (including the controller tracing agent).
# (2.4.2) Write in format one by one trace_results Medium trace data #
html_file.write('<!-- BEGIN TRACE -->\n')
for result in trace_results:
html_file.write(' <script class="trace-data" type="application/text">\n')
html_file.write(_ConvertToHtmlString(result.raw_data))
html_file.write(' </script>\n')
html_file.write('<!-- END TRACE -->\n')
# Write the suffix and finish.
# (2.4.3) Finally write 'suffix.html' The content of #
html_file.write(html_suffix)
html_file.close()
final_path = os.path.abspath(output_file_name)
return final_path
2.4、 Executed command
We are devil/devil/android/device_utils.py Of RunShellCommand.run() and devil/devil/utils/cmd_helper.py Of Popen() Add debugging print at , notice ’./systrace -o trace.html -t 10 gfx view wm am dalvik input sched freq idle‘ The specific execution process of the command is as follows :
ASOP_ROOT/external/chromium-trace/catapult/systrace/bin/systrace -o trace.html -t 10 gfx view wm am dalvik input sched freq idle
Popen: [u'/usr/bin/adb', 'devices']
run: ( c=/data/local/tmp/cache_token;echo $EXTERNAL_STORAGE;cat $c 2>/dev/null||echo;echo "636d6fb8-d59c-11e8-ae24-b8ca3a959992">$c &&getprop )>/data/local/tmp/temp_file-4aec8d95e60eb
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( ( c=/data/local/tmp/cache_token;echo $EXTERNAL_STORAGE;cat $c 2>/dev/null||echo;echo "636d6fb8-d59c-11e8-ae24-b8ca3a959992">$c &&getprop )>/data/local/tmp/temp_file-4aec8d95e60eb );echo %$?']
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'pull', '/data/local/tmp/temp_file-4aec8d95e60eb', '/tmp/tmple_FOq/tmp_ReadFileWithPull']
run: su 0 ls /root && ! ls /root
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', Popen: [u'/usr/bin/adb', 'shell''-s', , '8'( su 0 ls72QADT5KWKRG', /root && ! ls /root 'shell', );echo'rm -f /data/local/tmp/ %$?']temp_file-4aec8d95e60eb']
run: ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM&& ps -AT -o USER,PID,TID,CMD
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM&& ps -AT -o USER,PID,TID,CMD );echo %$?']
run: atrace --list_categories
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( atrace --list_categories );echo %$?']
run: atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_start
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_start );echo %$?']
Starting tracing (10 seconds)
Tracing completed. Collecting output...
run: ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM&& ps -AT -o USER,PID,TID,CMD
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM&& ps -AT -o USER,PID,TID,CMD );echo %$?']
run: ( atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_dump )>/data/local/tmp/temp_file-57edea8625b51
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( ( atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_dump )>/data/local/tmp/temp_file-57edea8625b51 );echo %$?']
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'pull', '/data/local/tmp/temp_file-57edea8625b51', '/tmp/tmp_preLk/tmp_ReadFileWithPull']
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', 'rm -f /data/local/tmp/temp_file-57edea8625b51']
run: atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_stop
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_stop );echo %$?']
run: echo -n /proc/[0-9]*/task/[0-9]*
Popen: [u'/usr/bin/adb', '-s', '872QADT5KWKRG', 'shell', '( echo -n /proc/[0-9]*/task/[0-9]* );echo %$?']
Outputting Systrace results...
Tracing complete, writing results
Wrote trace HTML file: file:///home/pengweilin/sdb2/m1872/code/repo/external/chromium-trace/catapult/systrace/bin/pwl1.html
To simplify, it is to call... On the target machine atrace Command implemented :
adb shell atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_start
adb shell atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_dump > /data/local/tmp/temp_file-57edea8625b51
adb pull /data/local/tmp/temp_file-57edea8625b51 /tmp/tmp_preLk/tmp_ReadFileWithPull
adb shell rm -f /data/local/tmp/temp_file-57edea8625b51
adb shell atrace -z -t 10 -b 4096 gfx view wm am dalvik input sched freq idle --async_stop
3、 Target machine atrace Implementation of commands (c++)
From the previous section, you can see the of the host systrace In fact, the command finally calls the... On the target machine atrace Command implemented . from atrace From the command format of , In two parts :
- [options]: Namely ’-‘ and ’–' Leading options ;
- [categories…]: Specify the need trace What events . Just like that. ’gfx view wm am dalvik input sched freq idle’ these ;
$ atrace --help
usage: atrace [options] [categories...]
options include:
-a appname enable app-level tracing for a comma separated list of cmdlines
-b N use a trace buffer size of N KB
-c trace into a circular buffer
-f filename use the categories written in a file as space-separated
values in a line
-k fname,... trace the listed kernel functions
-n ignore signals
-s N sleep for N seconds before tracing [default 0]
-t N trace for N seconds [default 5]
-z compress the trace dump
--async_start start circular trace and return immediately
--async_dump dump the current contents of circular trace buffer
--async_stop stop tracing and dump the current contents of circular
trace buffer
--stream stream trace to stdout as it enters the trace buffer
Note: this can take significant CPU time, and is best
used for measuring things that are not affected by
CPU performance, like pagecache usage.
--list_categories
list the available tracing categories
-o filename write the trace to the specified file instead
of stdout.
atrace The source code is ASOP_ROOT/frameworks/native/cmds/atrace/atrace.cpp, Let's analyze it in detail :
int main(int argc, char **argv)
{
bool async = false;
bool traceStart = true;
bool traceStop = true;
bool traceDump = true;
bool traceStream = false;
/* (1) atrace Follow "--help" Options , Print out help information */
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
showHelp(argv[0]);
exit(0);
}
/* (2) ftrace Whether the directory exists */
if (!findTraceFiles()) {
fprintf(stderr, "No trace folder found\n");
exit(-1);
}
/* (3) One by one atrace Command parameters for */
for (;;) {
int ret;
int option_index = 0;
static struct option long_options[] = {
{"async_start", no_argument, 0, 0 },
{"async_stop", no_argument, 0, 0 },
{"async_dump", no_argument, 0, 0 },
{"list_categories", no_argument, 0, 0 },
{"stream", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
/* (3.1) Try to use option Parsing atrace Command parameters for */
ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
long_options, &option_index);
/* (3.2) If you use option Parse failure , Try to use category To parse */
if (ret < 0) {
for (int i = optind; i < argc; i++) {
if (!setCategoryEnable(argv[i], true)) {
fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
exit(1);
}
}
break;
}
/* (3.3) According to the analysis option, Set up flag */
switch(ret) {
case 'a':
g_debugAppCmdLine = optarg;
break;
case 'b':
g_traceBufferSizeKB = atoi(optarg);
break;
case 'c':
g_traceOverwrite = true;
break;
case 'f':
g_categoriesFile = optarg;
break;
case 'k':
g_kernelTraceFuncs = optarg;
break;
case 'n':
g_nohup = true;
break;
case 's':
g_initialSleepSecs = atoi(optarg);
break;
case 't':
g_traceDurationSeconds = atoi(optarg);
break;
case 'z':
g_compress = true;
break;
case 'o':
g_outputFile = optarg;
break;
case 0:
if (!strcmp(long_options[option_index].name, "async_start")) {
async = true;
traceStop = false;
traceDump = false;
g_traceOverwrite = true;
} else if (!strcmp(long_options[option_index].name, "async_stop")) {
async = true;
traceStart = false;
} else if (!strcmp(long_options[option_index].name, "async_dump")) {
async = true;
traceStart = false;
traceStop = false;
} else if (!strcmp(long_options[option_index].name, "stream")) {
traceStream = true;
traceDump = false;
} else if (!strcmp(long_options[option_index].name, "list_categories")) {
listSupportedCategories();
exit(0);
}
break;
default:
fprintf(stderr, "\n");
showHelp(argv[0]);
exit(-1);
break;
}
}
registerSigHandler();
if (g_initialSleepSecs > 0) {
sleep(g_initialSleepSecs);
}
bool ok = true;
/* (4) "-- async_start" option The actual execution of the command */
if (traceStart) {
/* (4.1) */
ok &= setUpTrace();
/* (4.2) */
ok &= startTrace();
}
if (ok && traceStart) {
if (!traceStream) {
printf("capturing trace...");
fflush(stdout);
}
// We clear the trace after starting it because tracing gets enabled for
// each CPU individually in the kernel. Having the beginning of the trace
// contain entries from only one CPU can cause "begin" entries without a
// matching "end" entry to show up if a task gets migrated from one CPU to
// another.
/* (4.3) eliminate trace Content */
ok = clearTrace();
/* (4.4) adopt trace_marker File interface , Write synchronization information */
writeClockSyncMarker();
/* (4.5) async==false Support for */
if (ok && !async && !traceStream) {
// Sleep to allow the trace to be captured.
struct timespec timeLeft;
timeLeft.tv_sec = g_traceDurationSeconds;
timeLeft.tv_nsec = 0;
do {
if (g_traceAborted) {
break;
}
} while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
}
/* (4.6) traceStream Support for */
if (traceStream) {
streamTrace();
}
}
// Stop the trace and restore the default settings.
/* (5) "-- async_stop" option The actual execution of the command */
if (traceStop)
stopTrace();
/* (6) "-- async_dump" option The actual execution of the command */
if (ok && traceDump) {
if (!g_traceAborted) {
printf(" done\n");
fflush(stdout);
int outFd = STDOUT_FILENO;
if (g_outputFile) {
outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
if (outFd == -1) {
printf("Failed to open '%s', err=%d", g_outputFile, errno);
} else {
dprintf(outFd, "TRACE:\n");
dumpTrace(outFd);
if (g_outputFile) {
close(outFd);
}
}
} else {
printf("\ntrace aborted.\n");
fflush(stdout);
}
clearTrace();
} else if (!ok) {
fprintf(stderr, "unable to start tracing\n");
}
// Reset the trace buffer size to 1.
if (traceStop)
cleanUpTrace();
return g_traceAborted ? 1 : 0;
}
3.1、categories
categories Refers to something that can be trace Category of events , Its complete works are as follows :
/* Tracing categories */
static const TracingCategory k_categories[] = {
{ "gfx", "Graphics", ATRACE_TAG_GRAPHICS, {
{ OPT, "events/mdss/enable" },
} },
{ "input", "Input", ATRACE_TAG_INPUT, { } },
{ "view", "View System", ATRACE_TAG_VIEW, { } },
{ "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
{ "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
{ "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
{ "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
{ "audio", "Audio", ATRACE_TAG_AUDIO, { } },
{ "video", "Video", ATRACE_TAG_VIDEO, { } },
{ "camera", "Camera", ATRACE_TAG_CAMERA, { } },
{ "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
{ "app", "Application", ATRACE_TAG_APP, { } },
{ "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
{ "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
{ "rs", "RenderScript", ATRACE_TAG_RS, { } },
{ "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
{ "power", "Power Management", ATRACE_TAG_POWER, { } },
{ "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
{ "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
{ "database", "Database", ATRACE_TAG_DATABASE, { } },
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
{ REQ, "events/sched/sched_switch/enable" },
{ REQ, "events/sched/sched_wakeup/enable" },
{ OPT, "events/sched/sched_waking/enable" },
{ OPT, "events/sched/sched_blocked_reason/enable" },
{ OPT, "events/sched/sched_cpu_hotplug/enable" },
{ OPT, "events/cgroup/enable" },
} },
{ "irq", "IRQ Events", 0, {
{ REQ, "events/irq/enable" },
{ OPT, "events/ipi/enable" },
} },
{ "i2c", "I2C Events", 0, {
{ REQ, "events/i2c/enable" },
{ REQ, "events/i2c/i2c_read/enable" },
{ REQ, "events/i2c/i2c_write/enable" },
{ REQ, "events/i2c/i2c_result/enable" },
{ REQ, "events/i2c/i2c_reply/enable" },
{ OPT, "events/i2c/smbus_read/enable" },
{ OPT, "events/i2c/smbus_write/enable" },
{ OPT, "events/i2c/smbus_result/enable" },
{ OPT, "events/i2c/smbus_reply/enable" },
} },
{ "freq", "CPU Frequency", 0, {
{ REQ, "events/power/cpu_frequency/enable" },
{ OPT, "events/power/clock_set_rate/enable" },
{ OPT, "events/power/cpu_frequency_limits/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
{ REQ, "events/memory_bus/enable" },
} },
{ "idle", "CPU Idle", 0, {
{ REQ, "events/power/cpu_idle/enable" },
} },
{ "disk", "Disk I/O", 0, {
{ OPT, "events/f2fs/f2fs_sync_file_enter/enable" },
{ OPT, "events/f2fs/f2fs_sync_file_exit/enable" },
{ OPT, "events/f2fs/f2fs_write_begin/enable" },
{ OPT, "events/f2fs/f2fs_write_end/enable" },
{ OPT, "events/ext4/ext4_da_write_begin/enable" },
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
{ OPT, "events/ext4/ext4_sync_file_exit/enable" },
{ REQ, "events/block/block_rq_issue/enable" },
{ REQ, "events/block/block_rq_complete/enable" },
} },
{ "mmc", "eMMC commands", 0, {
{ REQ, "events/mmc/enable" },
} },
{ "load", "CPU Load", 0, {
{ REQ, "events/cpufreq_interactive/enable" },
} },
{ "sync", "Synchronization", 0, {
{ REQ, "events/sync/enable" },
} },
{ "workq", "Kernel Workqueues", 0, {
{ REQ, "events/workqueue/enable" },
} },
{ "memreclaim", "Kernel Memory Reclaim", 0, {
{ REQ, "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
{ REQ, "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
{ REQ, "events/vmscan/mm_vmscan_kswapd_wake/enable" },
{ REQ, "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
{ REQ, "events/lowmemorykiller/enable" },
} },
{ "regulators", "Voltage and Current Regulators", 0, {
{ REQ, "events/regulator/enable" },
} },
{ "binder_driver", "Binder Kernel driver", 0, {
{ REQ, "events/binder/binder_transaction/enable" },
{ REQ, "events/binder/binder_transaction_received/enable" },
{ OPT, "events/binder/binder_set_priority/enable" },
} },
{ "binder_lock", "Binder global lock trace", 0, {
{ OPT, "events/binder/binder_lock/enable" },
{ OPT, "events/binder/binder_locked/enable" },
{ OPT, "events/binder/binder_unlock/enable" },
} },
{ "pagecache", "Page cache", 0, {
{ REQ, "events/filemap/enable" },
} },
};
these categories It can be simply divided into 3 class :
- 1、 Using the kernel ftrace Of trace event Implemented kernel Events . for example "sched",.sysfiles The field specifies trace event The path of ;
- 2、 Use Trace Class to implement user state events (app/java framework/native). for example "input",.tags The field specifies trace tag;
- 3、service Type of event . Such as k_coreServiceCategory and k_pdxServiceCategory;
The specific target machine may only support categories Part of the complete collection , therefore atrace The specified in the command parameters will be categories Whether the machine supports judgment :
main() -> setCategoryEnable():
static bool setCategoryEnable(const char* name, bool enable)
{
/* (1) Judge the... In the command parameters one by one categories, Whether the machine supports */
for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (strcmp(name, c.name) == 0) {
/* (2) Judge categories Do you support */
if (isCategorySupported(c)) {
g_categoryEnables[i] = enable;
return true;
} else {
/* (3) If this machine does not support categories, Whether the reason is that there is no root jurisdiction ? */
if (isCategorySupportedForRoot(c)) {
fprintf(stderr, "error: category \"%s\" requires root "
"privileges.\n", name);
/* (4) This machine does not support categories, Report errors */
} else {
fprintf(stderr, "error: category \"%s\" is not supported "
"on this device.\n", name);
}
return false;
}
}
}
fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
return false;
}
↓
static bool isCategorySupported(const TracingCategory& category)
{
/* (2.1) If category yes k_coreServiceCategory, Judge name Is it "core_services", Judge "ro.atrace.core.services" Of property Whether there is */
if (strcmp(category.name, k_coreServiceCategory) == 0) {
return !android::base::GetProperty(k_coreServicesProp, "").empty();
}
/* (2.2) If category yes k_pdxServiceCategory, Judge name Is it "pdx" */
if (strcmp(category.name, k_pdxServiceCategory) == 0) {
return true;
}
bool ok = category.tags != 0;
/* (2.2) If category It uses the kernel trace event, Judge trace4event Whether the corresponding file exists and can be written */
for (int i = 0; i < MAX_SYS_FILES; i++) {
const char* path = category.sysfiles[i].path;
bool req = category.sysfiles[i].required == REQ;
if (path != NULL) {
if (req) {
if (!fileIsWritable(path)) {
return false;
} else {
ok = true;
}
} else {
ok = true;
}
}
}
return ok;
}
We can also use atrace Ordered "–list_categories" Options , List all supported by the current target machine categories:
main() -> listSupportedCategories():
static void listSupportedCategories()
{
/* (1) One by one k_categories All in the array category */
for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
/* (2) Judge whether the current target system supports */
if (isCategorySupported(c)) {
printf(" %10s - %s\n", c.name, c.longname);
}
}
}
3.2、’–async_start’
When atrace The command uses ’–async_start’ After the options , Will start all specified categories:
static bool setUpTrace()
{
bool ok = true;
// Set up the tracing options.
/* (4.1.1) If categories Is specified using the file , Parse the file categories And enable */
ok &= setCategoriesEnableFromFile(g_categoriesFile);
/* (4.1.2) according to '-c' Options , To configure trace event Of overwrite:"/sys/kernel/debug/tracing/options/overwrite" */
ok &= setTraceOverwriteEnable(g_traceOverwrite);
/* (4.1.3) according to '-b' Options , To configure trace event Of buffer size:"/sys/kernel/debug/tracing/buffer_size_kb" */
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
// TODO: Re-enable after stabilization
//ok &= setCmdlineSize();
/* (4.1.4) According to the options , To configure :"/sys/kernel/debug/tracing/trace_clock" */
ok &= setClock();
/* (4.1.5) Can make :"/sys/kernel/debug/tracing/options/print-tgid" */
ok &= setPrintTgidEnableIfPresent(true);
/* (4.1.6) according to '-k' Option specifies the need for trace Of kernel function ,
Configuration of the current tracer by function_graph:"/sys/kernel/debug/tracing/current_tracer"
stay filter The configuration in requires trace The function name of :"/sys/kernel/debug/tracing/set_ftrace_filter"
*/
ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
// Set up the tags property.
uint64_t tags = 0;
/* (4.1.7) hold categories China needs trace Of tag Conduct ' or ' operation , And configure to "debug.atrace.tags.enableflags" Of property in */
for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
tags |= c.tags;
}
}
ok &= setTagsProperty(tags);
bool coreServicesTagEnabled = false;
for (size_t i = 0; i < arraysize(k_categories); i++) {
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
// Set whether to poke PDX services in this session.
if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
g_tracePdx = g_categoryEnables[i];
}
}
/* (4.1.8) according to '-a' Option specifies the need for trace Of app name, At most 16 individual ,
Configuration to "debug.atrace.app_%d" Of property among
*/
std::string packageList(g_debugAppCmdLine);
if (coreServicesTagEnabled) {
if (!packageList.empty()) {
packageList += ",";
}
packageList += android::base::GetProperty(k_coreServicesProp, "");
}
ok &= setAppCmdlineProperty(&packageList[0]);
/* (4.1.9) Give Way defaultServiceManager() All in service Reread property, Make the modified configuration effective */
ok &= pokeBinderServices();
/* (4.1.10) Give Way ::android::hardware::defaultServiceManager() All in service Reread property, Make the modified configuration effective */
pokeHalServices();
/* (4.1.11) If categories It specifies "pdx", Give Way pdx service Reread property, Make the modified configuration effective */
if (g_tracePdx) {
ok &= ServiceUtility::PokeServices();
}
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
/* (4.1.12) disable Drop everything trace event */
ok &= disableKernelTraceEvents();
// Enable all the sysfs enables that are in an enabled category.
/* (4.1.13) according to categories Configuration in array , Make corresponding trace event */
for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
const char* path = c.sysfiles[j].path;
bool required = c.sysfiles[j].required == REQ;
if (path != NULL) {
if (fileIsWritable(path)) {
ok &= setKernelOptionEnable(path, true);
} else if (required) {
fprintf(stderr, "error writing file %s\n", path);
ok = false;
}
}
}
}
}
return ok;
}
static bool startTrace()
{
return setTracingEnabled(true);
}
↓
// Enable or disable kernel tracing.
static bool setTracingEnabled(bool enable)
{
/* (4.2.1) Turn on the main switch :"/sys/kernel/debug/tracing/tracing_on" */
return setKernelOptionEnable(k_tracingOnPath, enable);
}
3.3、’–async_dump’
When atrace The command uses ’–async_dump’ After the options , Meeting dump Out trace Content :
main()
{
/* (6) "-- async_dump" option The actual execution of the command */
if (ok && traceDump) {
if (!g_traceAborted) {
printf(" done\n");
fflush(stdout);
/* (6.1) default dump Information output handle */
int outFd = STDOUT_FILENO;
/* (6.2) Use '-o' Option specified dump Information output handle */
if (g_outputFile) {
outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
if (outFd == -1) {
printf("Failed to open '%s', err=%d", g_outputFile, errno);
} else {
dprintf(outFd, "TRACE:\n");
/* (6.3) read out "/sys/kernel/debug/tracing/trace" The content of dump To the output handle */
dumpTrace(outFd);
if (g_outputFile) {
close(outFd);
}
}
} else {
printf("\ntrace aborted.\n");
fflush(stdout);
}
clearTrace();
} else if (!ok) {
fprintf(stderr, "unable to start tracing\n");
}
}
↓
3.4、’–async_stop’
When atrace The command uses ’–async_stop’ After the options , Will stop all categories Of trace Information fetching :
static void stopTrace()
{
setTracingEnabled(false);
}
↓
static bool setTracingEnabled(bool enable)
{
/* (5.1) Turn off the main switch :"/sys/kernel/debug/tracing/tracing_on" */
return setKernelOptionEnable(k_tracingOnPath, enable);
}
4、 Target machine Trace The use of the class (java/c++)
atrace Just a control command , Actually trace Data paths are divided in this way :
- 1、 kernel trace Information , adopt trace event It was recorded that ftrace Of buffer in ;
- 2、 User mode (app/java framework/native) By using Trace Class to record trace The information of , In fact, by "/sys/kernel/debug/tracing/trace_marker" Interface records to the kernel ftracebuffer In the middle of .
We see the atrace dump The original information , You can see the corresponding "tracing_mark_write" Field :
ndroid.systemui-1856 ( 1856) [001] ...1 89888.553074: tracing_mark_write: S|1856|animator:alpha|62928891
ndroid.systemui-1856 ( 1856) [001] ...1 89888.553096: tracing_mark_write: F|1856|animator:alpha|62928891
ndroid.systemui-1856 ( 1856) [001] ...1 89888.553110: tracing_mark_write: S|1856|animator:scaleX|37096049
ndroid.systemui-1856 ( 1856) [001] ...1 89888.553131: tracing_mark_write: F|1856|animator:scaleX|37096049
In this way, the kernel state and user state trace The data is finally written to ftrace buffer among , It also realizes time synchronization , Finally through "/sys/kernel/debug/tracing/trace" Interface readout .
It is used in this way at all levels of user status Trace Class :
4.1、app
import android.os.Trace;
Trace.beginSection(String sectionName)
Trace.EndSection()
For detailed examples, please refer to :systrace
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
...
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Trace.beginSection("MyAdapter.onCreateViewHolder");
MyViewHolder myViewHolder;
try {
myViewHolder = MyViewHolder.newInstance(parent);
} finally {
// In 'try...catch' statements, always call <code><a href="/reference/android/os/Trace.html#endSection()">endSection()</a></code>
// in a 'finally' block to ensure it is invoked even when an exception
// is thrown.
Trace.endSection();
}
return myViewHolder;
}</p>
<p>@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Trace.beginSection("MyAdapter.onBindViewHolder");
try {
try {
Trace.beginSection("MyAdapter.queryDatabase");
RowItem rowItem = queryDatabase(position);
mDataset.add(rowItem);
} finally {
Trace.endSection();
}
holder.bind(mDataset.get(position));
} finally {
Trace.endSection();
}
}
...
}
And then through python systrace.py --app=sectionName Appoint apk, Or by ddms Select to specify apk, Grab systrace analysis .
4.2、Java framework
import android.os.Trace;
Trace.traceBegin(long traceTag, String methodName)
Trace.traceEnd(long traceTag)
4.3、Native framework
#include <cutils/trace.h>
ATRACE_CALL()
5、 host Trace-Viewer The implementation of the (js)
from systrace python After parsing the file, we can see , Finally, put trace Data and ’prefix.html’、‘suffix.html’、'systrace_trace_viewer.html’ Synthesis of a ’trace.html’ file , Use chrome Browser open ’trace.html’ It is very convenient to view and analyze in graphical form trace data .
The key is Trace-Viewer, The core is js Script . The project github Home page .
I am js Poor skills , After reading a pile of information, I still don't know the point . If you are interested, you can continue to study deeply ,Trace-Viewer Very powerful , Used to do trace The analysis and implementation of data can not be more appropriate , If you can use it to modify it yourself, it is very powerful .
Some reference documents :
catapult on github
Trace-Viewer
Trace Event Format
extending-and-customizing-trace-viewer
Trace Viewer getting-started
Trace Viewer doc
<template> label
and Polymer Join in Web Component revolution
The Trace Event Profiling Tool (about:tracing)
Recording Tracing Runs
Understanding about:tracing results
FrameViewer How-To
One of the most famous questions here is trace.html Add a custom trace curve , The main steps are as follows :
- 1、 In their own kernel trace event;
- 2、 stay atrace.cpp Code k_categories[] Add the corresponding... To the array category;
- 3、 stay Trace-Viewer Add to this category Parsing ,Trace-Viewer The analysis of data is through parser To achieve , Can imitate linux_perf The implementation of in adds a parser, To regenerate the ’systrace_trace_viewer.html’、'trace.html’ File can .
Reference documents
1、systrace
2、Android Introduction to system performance tuning tools
3、 Understand and use systrace
版权声明
本文为[pwl999]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230612157128.html
边栏推荐
- 第3章 Pytorch神经网络工具箱
- Systrace 解析
- 【无标题】PID控制TT编码器电机
- AUTOSAR从入门到精通100讲(五十二)-诊断和通信管理功能单元
- [point cloud series] a rotation invariant framework for deep point cloud analysis
- Computer shutdown program
- PyTorch 11.正则化
- Machine learning notes 1: learning ideas
- Five methods are used to obtain the parameters and calculation of torch network model
- 画 ArcFace 中的 margin 曲线
猜你喜欢
第4章 Pytorch数据处理工具箱
ArcGIS license server administrator cannot start the workaround
x86架构初探之8086
EMMC/SD学习小记
EasyUI combobox determines whether the input item exists in the drop-down list
使用 trt 的int8 量化和推断 onnx 模型
FATFS FAT32学习小记
pth 转 onnx 时出现的 gather、unsqueeze 等算子
【点云系列】Fully-Convolutional geometric features
[3D shape reconstruction series] implicit functions in feature space for 3D shape reconstruction and completion
随机推荐
Systrace 解析
SSL / TLS application example
PyTorch 9. 优化器
Unwind 栈回溯详解
PyMySQL连接数据库
安装 pycuda 出现 PEP517 的错误
[3D shape reconstruction series] implicit functions in feature space for 3D shape reconstruction and completion
Keras如何保存、加载Keras模型
Proteus 8.10安装问题(亲测稳定不闪退!)
第2章 Pytorch基础2
【点云系列】Pointfilter: Point Cloud Filtering via Encoder-Decoder Modeling
【点云系列】DeepMapping: Unsupervised Map Estimation From Multiple Point Clouds
[dynamic programming] different paths 2
Five methods are used to obtain the parameters and calculation of torch network model
基于openmv的无人机Apriltag动态追踪降落完整项目资料(labview+openmv+apriltag+正点原子四轴)
N states of prime number solution
Thanos. SH kill bully script, easily delete half of the files in the system at random
Pymysql connection database
Gobang games
How keras saves and loads the keras model