mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-23 02:47:07 +00:00
Bug 1082265 - Rewrite split-profile.pl in python.
This adds arguments for the paths to jprof, the program being profiled, and the jprof profile itself, so I don't need to modify my local copy of split-profile.pl to fix those. DONTBUILD --HG-- extra : transplant_source : %97%D5%A6%1C%A86%5E%AC%F7%FB%A7%8D%B0L%1D%17%FDK%EA%9F
This commit is contained in:
parent
29be851cda
commit
456c443047
@ -1,100 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# split-profile.pl Documentation:
|
||||
#
|
||||
# This script uses jprof's includes (-i) and excludes (-e) options to
|
||||
# split profiles into segments. It takes as input a single text file,
|
||||
# and from that text file creates a series of jprof profiles in the
|
||||
# directory in which it is run. It expects the application binaries
|
||||
# with which the profile was made, including jprof, and the jprof
|
||||
# profile data, to be in a directory called "bin" that is a subdirectory
|
||||
# of the current directory, and it will output the profiles into the
|
||||
# current directory.
|
||||
#
|
||||
# The input file format looks like the following:
|
||||
#
|
||||
# poll g_main_poll
|
||||
# GetRuleCascade CSSRuleProcessor::GetRuleCascade(nsPresContext *, nsIAtom *)
|
||||
# RuleProcessorData RuleProcessorData::RuleProcessorData(nsPresContext *, nsIContent *, nsRuleWalker *, nsCompatibility *)
|
||||
#
|
||||
# From this input file, the script will construct a profile called
|
||||
# 00.html that contains the whole profile, a profile called 01-poll.html
|
||||
# that includes only stacks with g_main_poll, a profile called
|
||||
# 02-GetRuleCascade.html that includes only stacks that have
|
||||
# GetRuleCascade and do not have g_main_poll, a profile called
|
||||
# 03-RuleProcessorData.html that includes only stacks that have the
|
||||
# RuleProcessorData constructor and do not have GetRuleCascade or
|
||||
# g_main_poll, and a profile called 04.html that includes only stacks
|
||||
# that do not have any of the three functions in them.
|
||||
#
|
||||
# This means that all of the segments of the profile, except 00.html,
|
||||
# are mutually exclusive. Thus clever ordering of the functions in the
|
||||
# input file can lead to a logical splitting of the profile into
|
||||
# segments.
|
||||
|
||||
|
||||
use strict;
|
||||
|
||||
my @names;
|
||||
my @sigs;
|
||||
|
||||
sub read_info($) {
|
||||
my ($fname) = @_;
|
||||
|
||||
open(INFO, "<$fname");
|
||||
my $i = 0;
|
||||
while (<INFO>) {
|
||||
chop;
|
||||
my $line = $_;
|
||||
my $idx = index($line, " ");
|
||||
my $name = substr($line, 0, $idx);
|
||||
my $sig = substr($line, $idx+1);
|
||||
|
||||
$names[$i] = $name;
|
||||
$sigs[$i] = $sig;
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
sub run_profile($$) {
|
||||
my ($options, $outfile) = @_;
|
||||
|
||||
print "./jprof$options mozilla-bin jprof-log > ../$outfile.html\n";
|
||||
system "./jprof$options mozilla-bin jprof-log > ../$outfile.html";
|
||||
}
|
||||
|
||||
sub run_profiles() {
|
||||
run_profile("", "00");
|
||||
|
||||
for (my $i = 0; $i <= $#names + 1; ++$i) {
|
||||
my $options = "";
|
||||
for (my $j = 0; $j < $i; ++$j) {
|
||||
$options .= " -e\"$sigs[$j]\"";
|
||||
}
|
||||
if ($i <= $#names) {
|
||||
$options .= " -i\"$sigs[$i]\"";
|
||||
}
|
||||
my $num;
|
||||
my $n = $i + 1;
|
||||
if ($n < 10) {
|
||||
$num = "0$n";
|
||||
} else {
|
||||
$num = "$n";
|
||||
}
|
||||
if ($i <= $#names) {
|
||||
run_profile($options, "$num-$names[$i]");
|
||||
} else {
|
||||
run_profile($options, "$num");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
($#ARGV == 0) || die "Usage: split-profile.pl <info-file>\n";
|
||||
|
||||
read_info($ARGV[0]);
|
||||
chdir "bin" || die "Can't change directory to bin.";
|
||||
run_profiles();
|
140
tools/jprof/split-profile.py
Executable file
140
tools/jprof/split-profile.py
Executable file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/python
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This program splits up a jprof profile into multiple files based on a
|
||||
# list of functions in a text file. First, a complete profile is
|
||||
# generated. Then, for each line in the text file, a profile is
|
||||
# generated containing only stacks that go through that line, and also
|
||||
# excluding all stacks in earlier lines in the text file. This means
|
||||
# that the text file, from start to end, is splitting out pieces of the
|
||||
# profile in their own file. Finally, a final profile containing the
|
||||
# remainder is produced.
|
||||
|
||||
# The program takes four arguments:
|
||||
# (1) The path to jprof.
|
||||
# (2) The path to the text file describing the splits. The output
|
||||
# will be placed in the same directory as this file.
|
||||
# (3) The program that was profiled.
|
||||
# (4) The jprof-log file generated by the profile, to be split up.
|
||||
# (Really, all arguments from (3) and later are passed through to
|
||||
# jprof, so additional arguments could be provided if you want to pass
|
||||
# additional arguments to jprof.)
|
||||
|
||||
# In slightly more detail:
|
||||
#
|
||||
# This script uses jprof's includes (-i) and excludes (-e) options to
|
||||
# split profiles into segments. It takes as input a single text file,
|
||||
# and from that text file creates a series of jprof profiles in the
|
||||
# directory in which it is run. It expects the application binaries
|
||||
# with which the profile was made, including jprof, and the jprof
|
||||
# profile data, to be in a directory called "bin" that is a subdirectory
|
||||
# of the current directory, and it will output the profiles into the
|
||||
# current directory.
|
||||
#
|
||||
# The input file format looks like the following:
|
||||
#
|
||||
# poll g_main_poll
|
||||
# GetRuleCascade CSSRuleProcessor::GetRuleCascade(nsPresContext *, nsIAtom *)
|
||||
# RuleProcessorData RuleProcessorData::RuleProcessorData(nsPresContext *, nsIContent *, nsRuleWalker *, nsCompatibility *)
|
||||
#
|
||||
# From this input file, the script will construct a profile called
|
||||
# jprof-0.html that contains the whole profile, a profile called
|
||||
# jprof-1-poll.html that includes only stacks with g_main_poll, a
|
||||
# profile called jprof-2-GetRuleCascade.html that includes only stacks
|
||||
# that have GetRuleCascade and do not have g_main_poll, a profile called
|
||||
# jprof-3-RuleProcessorData.html that includes only stacks that have the
|
||||
# RuleProcessorData constructor and do not have GetRuleCascade or
|
||||
# g_main_poll, and a profile called jprof-4.html that includes only
|
||||
# stacks that do not have any of the three functions in them.
|
||||
#
|
||||
# This means that all of the segments of the profile, except
|
||||
# jprof-0.html, are mutually exclusive. Thus clever ordering of the
|
||||
# functions in the input file can lead to a logical splitting of the
|
||||
# profile into segments.
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import os.path
|
||||
|
||||
if len(sys.argv) < 5:
|
||||
sys.stderr.write("Expected arguments: <jprof> <split-file> <program> <jprof-log>\n")
|
||||
sys.exit(1)
|
||||
|
||||
jprof = sys.argv[1]
|
||||
splitfile = sys.argv[2]
|
||||
passthrough = sys.argv[3:]
|
||||
|
||||
for f in [jprof, splitfile]:
|
||||
if not os.path.isfile(f):
|
||||
sys.stderr.write("could not find file: {0}\n".format(f))
|
||||
sys.exit(1)
|
||||
|
||||
def read_splits(splitfile):
|
||||
"""
|
||||
Read splitfile (each line of which contains a name, a space, and
|
||||
then a function name to split on), and return a list of pairs
|
||||
representing exactly that. (Note that the name cannot contain
|
||||
spaces, but the function name can, and often does.)
|
||||
"""
|
||||
def line_to_split(line):
|
||||
line = line.strip("\r\n")
|
||||
idx = line.index(" ")
|
||||
return (line[0:idx], line[idx+1:])
|
||||
|
||||
io = open(splitfile, "r")
|
||||
result = [line_to_split(line) for line in io]
|
||||
io.close()
|
||||
return result
|
||||
|
||||
splits = read_splits(splitfile)
|
||||
|
||||
def generate_profile(options, destfile):
|
||||
"""
|
||||
Run jprof to generate one split of the profile.
|
||||
"""
|
||||
args = [jprof] + options + passthrough
|
||||
print "Generating {0}".format(destfile)
|
||||
destio = open(destfile, "w")
|
||||
process = subprocess.Popen(args, stdout=destio)
|
||||
process.wait()
|
||||
destio.close()
|
||||
if process.returncode != 0:
|
||||
os.remove(destfile)
|
||||
sys.stderr.write("Error {0} from command:\n {1}\n".format(process.returncode, " ".join(args)))
|
||||
sys.exit(process.returncode)
|
||||
|
||||
def output_filename(number, splitname):
|
||||
"""
|
||||
Return the filename (absolute path) we should use to output the
|
||||
profile segment with the given number and splitname. Splitname
|
||||
should be None for the complete profile and the remainder.
|
||||
"""
|
||||
def pad_count(i):
|
||||
result = str(i)
|
||||
# 0-pad to the same length
|
||||
result = "0" * (len(str(len(splits) + 1)) - len(result)) + result
|
||||
return result
|
||||
|
||||
name = pad_count(number)
|
||||
if splitname is not None:
|
||||
name += "-" + splitname
|
||||
|
||||
return os.path.join(os.path.dirname(splitfile),
|
||||
"jprof-{0}.html".format(name))
|
||||
|
||||
# generate the complete profile
|
||||
generate_profile([], output_filename(0, None))
|
||||
|
||||
# generate the listed splits
|
||||
count = 1
|
||||
excludes = []
|
||||
for (splitname, splitfunction) in splits:
|
||||
generate_profile(excludes + ["-i" + splitfunction],
|
||||
output_filename(count, splitname))
|
||||
excludes += ["-e" + splitfunction]
|
||||
count = count + 1
|
||||
|
||||
# generate the remainder after the splits
|
||||
generate_profile(excludes, output_filename(count, None))
|
Loading…
x
Reference in New Issue
Block a user