blob: efe02189692c3b615481d1a33e42a017682a6a63 [file] [log] [blame]
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# 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 shutil
import os
import sys
import tempfile
from cros_utils import command_executer
import heatmap_generator
def IsARepoRoot(directory):
"""Returns True if directory is the root of a repo checkout."""
return os.path.exists(os.path.join(directory, '.repo'))
class HeatMapProducer(object):
"""Class to produce heat map."""
def __init__(self, chromeos_root, perf_data, page_size, binary, title):
self.chromeos_root = os.path.realpath(chromeos_root)
self.perf_data = os.path.realpath(perf_data)
self.page_size = page_size
self.dir = os.path.dirname(os.path.realpath(__file__))
self.binary = binary
self.tempDir = ''
self.ce = command_executer.GetCommandExecuter()
self.loading_address = None
self.temp_perf = ''
self.temp_perf_inchroot = ''
self.perf_report = ''
self.title = title
def copyFileToChroot(self):
self.tempDir = tempfile.mkdtemp(
prefix=os.path.join(self.chromeos_root, 'src/'))
self.temp_perf = os.path.join(self.tempDir, 'perf.data')
shutil.copy2(self.perf_data, self.temp_perf)
self.temp_perf_inchroot = os.path.join('~/trunk/src',
os.path.basename(self.tempDir))
def getPerfReport(self):
if os.path.isfile(os.path.join(self.tempDir, 'perf_report.txt')):
self.perf_report = os.path.join(self.tempDir, 'perf_report.txt')
return
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.tempDir, 'perf_report.txt')
def getHeatMap(self, top_n_pages=None):
generator = heatmap_generator.HeatmapGenerator(self.perf_report,
self.page_size, self.title)
generator.draw()
# Analyze top N hottest symbols with the binary, if provided
if self.binary != '':
if top_n_pages is not None:
generator.analyze(self.binary, top_n_pages)
else:
generator.analyze(self.binary)
def RemoveFiles(self):
shutil.rmtree(self.tempDir)
if os.path.isfile(os.path.join(os.getcwd(), 'out.txt')):
os.remove(os.path.join(os.getcwd(), 'out.txt'))
if os.path.isfile(os.path.join(os.getcwd(), 'inst-histo.txt')):
os.remove(os.path.join(os.getcwd(), 'inst-histo.txt'))
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.')
parser.add_argument(
'--binary',
dest='binary',
required=False,
help='The path to the Chrome binary.',
default=None)
parser.add_argument(
'--top_n',
dest='top_n',
required=False,
help='Print out top N hottest pages within/outside huge page range(30MB)',
default=None)
parser.add_argument(
'--page_size',
dest='page_size',
required=False,
help='The page size for heat maps.',
default=4096)
parser.add_argument('--title', dest='title', default='')
options = parser.parse_args(argv)
if not IsARepoRoot(options.chromeos_root):
parser.error('% 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)
heatmap_producer = HeatMapProducer(options.chromeos_root, options.perf_data,
options.page_size, options.binary,
options.title)
try:
heatmap_producer.copyFileToChroot()
heatmap_producer.getPerfReport()
heatmap_producer.getHeatMap(options.top_n)
print('\nheat map and time histgram genereated in the current directory '
'with name heat_map.png and timeline.png accordingly.')
except RuntimeError, e:
print(e)
finally:
heatmap_producer.RemoveFiles()
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))