android: Support lightweight instrumentation in orderfile_generator_backend.py.
This adds a --lightweight-instrumentation flag to orderfile_generator.py
to use the new pipeline. The new step is using process_profiles.py to
output a list of reached offsets symbols, matching the output format
from the current instrumentation.
This allows the rest of the pipeline to remain unchanged.
Bug: 776702
Change-Id: Iddf8d42112f1d44a7ef36d26328f51d0b3b894cb
Reviewed-on: https://chromium-review.googlesource.com/746665
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: Egor Pasko <pasko@chromium.org>
Reviewed-by: Matthew Cary <mattcary@chromium.org>
Cr-Commit-Position: refs/heads/master@{#514470}
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py
index 37cb1da1..23ddbdc 100755
--- a/tools/cygprofile/orderfile_generator_backend.py
+++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -23,9 +23,11 @@
import shutil
import subprocess
import sys
+import tempfile
import time
import cygprofile_utils
+import process_profiles
import profile_android_startup
@@ -137,6 +139,31 @@
shutil.move(stashpath, buildpath)
+def _EnsureOrderfileStartsWithAnchorSection(filename):
+ """Ensures that the orderfile starts with the right anchor symbol.
+
+ This changes the orderfile, if required.
+
+ Args:
+ filename: (str) Path to the orderfile.
+ """
+ anchor_section = '.text.dummy_function_to_anchor_text'
+ with open(filename, 'r') as f:
+ if f.readline().strip() == anchor_section:
+ return
+ try:
+ f = tempfile.NamedTemporaryFile(dir=os.path.dirname(filename), delete=False)
+ f.write(anchor_section + '\n')
+ with open(filename, 'r') as orderfile_file:
+ for line in orderfile_file:
+ f.write(line + '\n')
+ f.close()
+ os.rename(f.name, filename)
+ finally:
+ if os.path.exists(f.name):
+ os.remove(f.name)
+
+
class StepRecorder(object):
"""Records steps and timings."""
@@ -221,15 +248,15 @@
"""Handles compilation of clank."""
def __init__(self, out_dir, step_recorder, arch, jobs, max_load, use_goma,
- goma_dir):
- self._arch = arch
- self._goma_dir = goma_dir
- self._jobs = jobs
- self._max_load = max_load
+ goma_dir, lightweight_instrumentation):
self._out_dir = out_dir
self._step_recorder = step_recorder
+ self._arch = arch
+ self._jobs = jobs
+ self._max_load = max_load
self._use_goma = use_goma
-
+ self._goma_dir = goma_dir
+ self._lightweight_instrumentation = lightweight_instrumentation
lib_chrome_so_dir = 'lib.unstripped'
self.lib_chrome_so = os.path.join(
self._out_dir, 'Release', lib_chrome_so_dir, 'libchrome.so')
@@ -240,8 +267,8 @@
"""Builds the provided ninja target with or without order_profiling on.
Args:
- instrumented: Whether we want to build an instrumented binary.
- target: The name of the ninja target to build.
+ instrumented: (bool) Whether we want to build an instrumented binary.
+ target: (str) The name of the ninja target to build.
"""
self._step_recorder.BeginStep('Compile %s' % target)
@@ -259,8 +286,11 @@
'use_goma=' + str(self._use_goma).lower(),
'use_order_profiling=' + str(instrumented).lower(),
]
+ if instrumented and self._lightweight_instrumentation:
+ args.append('use_lightweight_order_profiling=true')
if self._goma_dir:
args += ['goma_dir="%s"' % self._goma_dir]
+
self._step_recorder.RunCommand(
['gn', 'gen', os.path.join(self._out_dir, 'Release'),
'--args=' + ' '.join(args)])
@@ -273,7 +303,7 @@
"""Builds a Chrome.apk either with or without order_profiling on.
Args:
- instrumented: Whether we want to build an instrumented apk.
+ instrumented: (bool) Whether to build an instrumented apk.
force_relink: Whether libchromeview.so should be re-created.
"""
if force_relink:
@@ -284,8 +314,8 @@
"""Builds a libchrome.so either with or without order_profiling on.
Args:
- instrumented: Whether we want to build an instrumented apk.
- force_relink: Whether libchrome.so should be re-created.
+ instrumented: (bool) Whether to build an instrumented apk.
+ force_relink: (bool) Whether libchrome.so should be re-created.
"""
if force_relink:
self._step_recorder.RunCommand(['rm', '-rf', self.lib_chrome_so])
@@ -445,10 +475,15 @@
def _RunCygprofileUnitTests(self):
"""Builds, deploys and runs cygprofile_unittests."""
+ # There an no unittests (yet) for the lightweight instrumentation.
+ # TODO(lizeb): Fix this.
+ if self._options.lightweight_instrumentation:
+ return
tools_compiler = ClankCompiler(
os.path.dirname(constants.GetOutDirectory()),
self._step_recorder, self._options.arch, self._options.jobs,
- self._options.max_load, self._options.use_goma, self._options.goma_dir)
+ self._options.max_load, self._options.use_goma, self._options.goma_dir,
+ self._options.lightweight_instrumentation)
tools_compiler.Build(instrumented=False, target='android_tools')
self._compiler.Build(instrumented=True, target='cygprofile_unittests')
@@ -489,10 +524,15 @@
self._compiler.chrome_apk,
constants.PACKAGE_INFO['chrome'])
self._step_recorder.BeginStep('Process cyglog')
- with open(self._MERGED_CYGLOG_FILENAME, 'w') as merged_cyglog:
- self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files,
- constants.DIR_SOURCE_ROOT,
- stdout=merged_cyglog)
+ if self._options.lightweight_instrumentation:
+ assert os.path.exists(self._compiler.lib_chrome_so)
+ process_profiles.GetReachedSymbolsFromDumpsAndMaybeWriteOffsets(
+ files, self._compiler.lib_chrome_so, self._MERGED_CYGLOG_FILENAME)
+ else:
+ with open(self._MERGED_CYGLOG_FILENAME, 'w') as merged_cyglog:
+ self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files,
+ constants.DIR_SOURCE_ROOT,
+ stdout=merged_cyglog)
except CommandError:
for f in files:
self._SaveForDebugging(f)
@@ -502,12 +542,16 @@
logging.getLogger().setLevel(logging.INFO)
try:
- self._step_recorder.RunCommand([self._CYGLOG_TO_ORDERFILE_SCRIPT,
- self._MERGED_CYGLOG_FILENAME,
- self._compiler.lib_chrome_so,
- self._GetUnpatchedOrderfileFilename(),
- '--target-arch=' + self._options.arch],
- constants.DIR_SOURCE_ROOT)
+ command_args = [
+ '--target-arch=' + self._options.arch,
+ '--native-library=' + self._compiler.lib_chrome_so,
+ '--output=' + self._GetUnpatchedOrderfileFilename()]
+ if self._options.lightweight_instrumentation:
+ command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME)
+ else:
+ command_args.append('--merged-cyglog=' + self._MERGED_CYGLOG_FILENAME)
+ self._step_recorder.RunCommand(
+ [self._CYGLOG_TO_ORDERFILE_SCRIPT] + command_args)
except CommandError:
self._SaveForDebugging(self._MERGED_CYGLOG_FILENAME)
self._SaveForDebuggingWithOverwrite(self._compiler.lib_chrome_so)
@@ -642,9 +686,13 @@
self._instrumented_out_dir,
self._step_recorder, self._options.arch, self._options.jobs,
self._options.max_load, self._options.use_goma,
- self._options.goma_dir)
+ self._options.goma_dir,
+ self._options.lightweight_instrumentation)
self._RunCygprofileUnitTests()
- self._compiler.CompileChromeApk(True)
+ if self._options.lightweight_instrumentation:
+ _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile())
+ self._compiler.CompileChromeApk(
+ True, self._options.lightweight_instrumentation)
self._GenerateAndProcessProfile()
self._MaybeArchiveOrderfile(self._GetUnpatchedOrderfileFilename())
profile_uploaded = True
@@ -660,7 +708,8 @@
self._compiler = ClankCompiler(
self._uninstrumented_out_dir, self._step_recorder,
self._options.arch, self._options.jobs, self._options.max_load,
- self._options.use_goma, self._options.goma_dir)
+ self._options.use_goma, self._options.goma_dir,
+ self._options.lightweight_instrumentation)
self._compiler.CompileLibchrome(False)
self._PatchOrderfile()
# Because identical code folding is a bit different with and without
@@ -696,6 +745,9 @@
def CreateOptionParser():
parser = optparse.OptionParser()
parser.add_option(
+ '--lightweight-instrumentation', action='store_true', default=False,
+ help='Use the lightweight instrumentation path')
+ parser.add_option(
'--buildbot', action='store_true',
help='If true, the script expects to be run on a buildbot')
parser.add_option(