aboutsummaryrefslogtreecommitdiff
path: root/heatmaps/heat_map.py
diff options
context:
space:
mode:
Diffstat (limited to 'heatmaps/heat_map.py')
-rwxr-xr-xheatmaps/heat_map.py341
1 files changed, 181 insertions, 160 deletions
diff --git a/heatmaps/heat_map.py b/heatmaps/heat_map.py
index a989ab70..a3c52369 100755
--- a/heatmaps/heat_map.py
+++ b/heatmaps/heat_map.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Copyright 2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Wrapper to generate heat maps for chrome."""
-from __future__ import print_function
import argparse
import os
@@ -19,167 +18,189 @@ from heatmaps import heatmap_generator
def IsARepoRoot(directory):
- """Returns True if directory is the root of a repo checkout."""
- return os.path.exists(
- os.path.join(os.path.realpath(os.path.expanduser(directory)), '.repo'))
+ """Returns True if directory is the root of a repo checkout."""
+ return os.path.exists(
+ os.path.join(os.path.realpath(os.path.expanduser(directory)), ".repo")
+ )
class HeatMapProducer(object):
- """Class to produce heat map."""
-
- def __init__(self,
- chromeos_root,
- perf_data,
- hugepage,
- binary,
- title,
- logger=None):
- self.chromeos_root = os.path.realpath(os.path.expanduser(chromeos_root))
- self.perf_data = os.path.realpath(os.path.expanduser(perf_data))
- self.hugepage = hugepage
- self.dir = os.path.dirname(os.path.realpath(__file__))
- self.binary = binary
- self.ce = command_executer.GetCommandExecuter()
- self.temp_dir = ''
- self.temp_perf_inchroot = ''
- self.temp_dir_created = False
- self.perf_report = ''
- self.title = title
- self.logger = logger
-
- def _EnsureFileInChroot(self):
- chroot_prefix = os.path.join(self.chromeos_root, 'chroot')
- if self.perf_data.startswith(chroot_prefix):
- # If the path to perf_data starts with the same chromeos_root, assume
- # it's in the chromeos_root so no need for temporary directory and copy.
- self.temp_dir = self.perf_data.replace('perf.data', '')
- self.temp_perf_inchroot = self.temp_dir.replace(chroot_prefix, '')
-
- else:
- # Otherwise, create a temporary directory and copy perf.data into chroot.
- self.temp_dir = tempfile.mkdtemp(
- prefix=os.path.join(self.chromeos_root, 'src/'))
- temp_perf = os.path.join(self.temp_dir, 'perf.data')
- shutil.copy2(self.perf_data, temp_perf)
- self.temp_perf_inchroot = os.path.join('~/trunk/src',
- os.path.basename(self.temp_dir))
- self.temp_dir_created = True
-
- def _GeneratePerfReport(self):
- cmd = ('cd %s && perf report -D -i perf.data > perf_report.txt' %
- self.temp_perf_inchroot)
- retval = self.ce.ChrootRunCommand(self.chromeos_root, cmd)
- if retval:
- raise RuntimeError('Failed to generate perf report')
- self.perf_report = os.path.join(self.temp_dir, 'perf_report.txt')
-
- def _GetHeatMap(self, top_n_pages):
- generator = heatmap_generator.HeatmapGenerator(
- perf_report=self.perf_report,
- page_size=4096,
- hugepage=self.hugepage,
- title=self.title)
- generator.draw()
- # Analyze top N hottest symbols with the binary, if provided
- if self.binary:
- generator.analyze(self.binary, top_n_pages)
-
- def _RemoveFiles(self):
- files = [
- 'out.txt', 'inst-histo.txt', 'inst-histo-hp.txt', 'inst-histo-sp.txt'
- ]
- for f in files:
- if os.path.exists(f):
- os.remove(f)
-
- def Run(self, top_n_pages):
- try:
- self._EnsureFileInChroot()
- self._GeneratePerfReport()
- self._GetHeatMap(top_n_pages)
- finally:
- self._RemoveFiles()
- msg = ('heat map and time histogram genereated in the current '
- 'directory with name heat_map.png and timeline.png '
- 'accordingly.')
- if self.binary:
- msg += ('\nThe hottest %d pages inside and outside hugepage '
- 'is symbolized and saved to addr2symbol.txt' % top_n_pages)
- if self.logger:
- self.logger.LogOutput(msg)
- else:
- print(msg)
+ """Class to produce heat map."""
+
+ def __init__(
+ self, chromeos_root, perf_data, hugepage, binary, title, logger=None
+ ):
+ self.chromeos_root = os.path.realpath(os.path.expanduser(chromeos_root))
+ self.perf_data = os.path.realpath(os.path.expanduser(perf_data))
+ self.hugepage = hugepage
+ self.dir = os.path.dirname(os.path.realpath(__file__))
+ self.binary = binary
+ self.ce = command_executer.GetCommandExecuter()
+ self.temp_dir = ""
+ self.temp_perf_inchroot = ""
+ self.temp_dir_created = False
+ self.perf_report = ""
+ self.title = title
+ self.logger = logger
+
+ def _EnsureFileInChroot(self):
+ chroot_prefix = os.path.join(self.chromeos_root, "chroot")
+ if self.perf_data.startswith(chroot_prefix):
+ # If the path to perf_data starts with the same chromeos_root, assume
+ # it's in the chromeos_root so no need for temporary directory and copy.
+ self.temp_dir = self.perf_data.replace("perf.data", "")
+ self.temp_perf_inchroot = self.temp_dir.replace(chroot_prefix, "")
+
+ else:
+ # Otherwise, create a temporary directory and copy perf.data into chroot.
+ self.temp_dir = tempfile.mkdtemp(
+ prefix=os.path.join(self.chromeos_root, "src/")
+ )
+ temp_perf = os.path.join(self.temp_dir, "perf.data")
+ shutil.copy2(self.perf_data, temp_perf)
+ self.temp_perf_inchroot = os.path.join(
+ "~/trunk/src", os.path.basename(self.temp_dir)
+ )
+ self.temp_dir_created = True
+
+ def _GeneratePerfReport(self):
+ cmd = (
+ "cd %s && perf report -D -i perf.data > perf_report.txt"
+ % self.temp_perf_inchroot
+ )
+ retval = self.ce.ChrootRunCommand(self.chromeos_root, cmd)
+ if retval:
+ raise RuntimeError("Failed to generate perf report")
+ self.perf_report = os.path.join(self.temp_dir, "perf_report.txt")
+
+ def _GetHeatMap(self, top_n_pages):
+ generator = heatmap_generator.HeatmapGenerator(
+ perf_report=self.perf_report,
+ page_size=4096,
+ hugepage=self.hugepage,
+ title=self.title,
+ )
+ generator.draw()
+ # Analyze top N hottest symbols with the binary, if provided
+ if self.binary:
+ generator.analyze(self.binary, top_n_pages)
+
+ def _RemoveFiles(self):
+ files = [
+ "out.txt",
+ "inst-histo.txt",
+ "inst-histo-hp.txt",
+ "inst-histo-sp.txt",
+ ]
+ for f in files:
+ if os.path.exists(f):
+ os.remove(f)
+
+ def Run(self, top_n_pages):
+ try:
+ self._EnsureFileInChroot()
+ self._GeneratePerfReport()
+ self._GetHeatMap(top_n_pages)
+ finally:
+ self._RemoveFiles()
+ msg = (
+ "heat map and time histogram genereated in the current "
+ "directory with name heat_map.png and timeline.png "
+ "accordingly."
+ )
+ if self.binary:
+ msg += (
+ "\nThe hottest %d pages inside and outside hugepage "
+ "is symbolized and saved to addr2symbol.txt" % top_n_pages
+ )
+ if self.logger:
+ self.logger.LogOutput(msg)
+ else:
+ print(msg)
def main(argv):
- """Parse the options.
-
- Args:
- argv: The options with which this script was invoked.
-
- Returns:
- 0 unless an exception is raised.
- """
- parser = argparse.ArgumentParser()
-
- parser.add_argument(
- '--chromeos_root',
- dest='chromeos_root',
- required=True,
- help='ChromeOS root to use for generate heatmaps.')
- parser.add_argument(
- '--perf_data',
- dest='perf_data',
- required=True,
- help='The raw perf data. Must be collected with -e instructions while '
- 'disabling ASLR.')
- parser.add_argument(
- '--binary',
- dest='binary',
- help='The path to the Chrome binary. Only useful if want to print '
- 'symbols on hottest pages',
- default=None)
- parser.add_argument(
- '--top_n',
- dest='top_n',
- type=int,
- default=10,
- help='Print out top N hottest pages within/outside huge page range. '
- 'Must be used with --hugepage and --binary. (Default: %(default)s)')
- parser.add_argument(
- '--title', dest='title', help='Title of the heatmap', default='')
- parser.add_argument(
- '--hugepage',
- dest='hugepage',
- help='A range of addresses (start,end) where huge page starts and ends'
- ' in text section, separated by a comma.'
- ' Used to differentiate regions in heatmap.'
- ' Example: --hugepage=0,4096'
- ' If not specified, no effect on the heatmap.',
- default=None)
-
- options = parser.parse_args(argv)
-
- if not IsARepoRoot(options.chromeos_root):
- parser.error('%s does not contain .repo dir.' % options.chromeos_root)
-
- if not os.path.isfile(options.perf_data):
- parser.error('Cannot find perf_data: %s.' % options.perf_data)
-
- hugepage_range = None
- if options.hugepage:
- hugepage_range = options.hugepage.split(',')
- if len(hugepage_range) != 2 or \
- int(hugepage_range[0]) > int(hugepage_range[1]):
- parser.error('Wrong format of hugepage range: %s' % options.hugepage)
- hugepage_range = [int(x) for x in hugepage_range]
-
- heatmap_producer = HeatMapProducer(options.chromeos_root, options.perf_data,
- hugepage_range, options.binary,
- options.title)
-
- heatmap_producer.Run(options.top_n)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ """Parse the options.
+
+ Args:
+ argv: The options with which this script was invoked.
+
+ Returns:
+ 0 unless an exception is raised.
+ """
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument(
+ "--chromeos_root",
+ dest="chromeos_root",
+ required=True,
+ help="ChromeOS root to use for generate heatmaps.",
+ )
+ parser.add_argument(
+ "--perf_data",
+ dest="perf_data",
+ required=True,
+ help="The raw perf data. Must be collected with -e instructions while "
+ "disabling ASLR.",
+ )
+ parser.add_argument(
+ "--binary",
+ dest="binary",
+ help="The path to the Chrome binary. Only useful if want to print "
+ "symbols on hottest pages",
+ default=None,
+ )
+ parser.add_argument(
+ "--top_n",
+ dest="top_n",
+ type=int,
+ default=10,
+ help="Print out top N hottest pages within/outside huge page range. "
+ "Must be used with --hugepage and --binary. (Default: %(default)s)",
+ )
+ parser.add_argument(
+ "--title", dest="title", help="Title of the heatmap", default=""
+ )
+ parser.add_argument(
+ "--hugepage",
+ dest="hugepage",
+ help="A range of addresses (start,end) where huge page starts and ends"
+ " in text section, separated by a comma."
+ " Used to differentiate regions in heatmap."
+ " Example: --hugepage=0,4096"
+ " If not specified, no effect on the heatmap.",
+ default=None,
+ )
+
+ options = parser.parse_args(argv)
+
+ if not IsARepoRoot(options.chromeos_root):
+ parser.error("%s does not contain .repo dir." % options.chromeos_root)
+
+ if not os.path.isfile(options.perf_data):
+ parser.error("Cannot find perf_data: %s." % options.perf_data)
+
+ hugepage_range = None
+ if options.hugepage:
+ hugepage_range = options.hugepage.split(",")
+ if len(hugepage_range) != 2 or int(hugepage_range[0]) > int(
+ hugepage_range[1]
+ ):
+ parser.error(
+ "Wrong format of hugepage range: %s" % options.hugepage
+ )
+ hugepage_range = [int(x) for x in hugepage_range]
+
+ heatmap_producer = HeatMapProducer(
+ options.chromeos_root,
+ options.perf_data,
+ hugepage_range,
+ options.binary,
+ options.title,
+ )
+
+ heatmap_producer.Run(options.top_n)
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))