2012-05-21 04:12:37 -07:00
|
|
|
# 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/.
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
package Util;
|
|
|
|
|
|
|
|
use Sys::Hostname;
|
|
|
|
use File::Copy;
|
|
|
|
use POSIX qw(sys_wait_h strftime);
|
|
|
|
|
|
|
|
sub print_log {
|
|
|
|
my ($text) = @_;
|
|
|
|
#print LOG $text;
|
|
|
|
print $text;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_logfile {
|
|
|
|
my ($logfile, $test_name) = @_;
|
|
|
|
print "DEBUG: $logfile\n";
|
|
|
|
print_log "----------- Output from $test_name ------------- \n";
|
|
|
|
open READRUNLOG, "$logfile" or die "Can't open log $logfile: $!\n";
|
|
|
|
print_log " $_" while <READRUNLOG>;
|
|
|
|
close READRUNLOG or die "Can't close log $logfile: $!\n";
|
|
|
|
print_log "----------- End Output from $test_name --------- \n";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_test_errors {
|
|
|
|
my ($result, $name) = @_;
|
|
|
|
|
|
|
|
if (not $result->{timed_out} and $result->{exit_value} != 0) {
|
|
|
|
if ($result->{sig_name} ne '') {
|
|
|
|
print_log "Error: $name: received SIG$result->{sig_name}\n";
|
|
|
|
}
|
|
|
|
print_log "Error: $name: exited with status $result->{exit_value}\n";
|
|
|
|
if ($result->{dumped_core}) {
|
|
|
|
print_log "Error: $name: dumped core.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Parse a file for $token, return the token.
|
|
|
|
# Look for the line "<token><delimiter><return-value>", e.g.
|
|
|
|
# for "__startuptime,5501"
|
|
|
|
# token = "__startuptime"
|
|
|
|
# delimiter = ","
|
|
|
|
# return-value = "5501";
|
|
|
|
#
|
|
|
|
sub extract_token {
|
|
|
|
my ($output, $token, $delimiter) = @_;
|
|
|
|
use Data::Dumper;
|
|
|
|
print Dumper("extract_token: @_");
|
|
|
|
my $token_value = 0;
|
|
|
|
if ($output =~ /$token/) {
|
|
|
|
$token_value = substr($output, index($output, $delimiter) + 1);
|
|
|
|
chomp($token_value);
|
|
|
|
}
|
|
|
|
return $token_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_cmd {
|
|
|
|
my ($home_dir, $binary_dir, $args, $timeout_secs) = @_;
|
|
|
|
my $now = localtime();
|
|
|
|
my $pid = 0;
|
|
|
|
my $shell_command = join(' ', @{$args});
|
|
|
|
|
|
|
|
my $exit_value = 1;
|
|
|
|
my $signal_num;
|
|
|
|
my $sig_name;
|
|
|
|
my $dumped_core;
|
|
|
|
my $timed_out;
|
|
|
|
my $output;
|
|
|
|
|
|
|
|
print_log "Begin: $now\n";
|
|
|
|
print_log "cmd = $shell_command\n";
|
|
|
|
|
|
|
|
eval{
|
|
|
|
# Set XRE_NO_WINDOWS_CRASH_DIALOG to disable showing
|
|
|
|
# the windows crash dialog in case the child process
|
|
|
|
# crashes
|
|
|
|
$ENV{XRE_NO_WINDOWS_CRASH_DIALOG} = 1;
|
|
|
|
|
|
|
|
# Now cd to dir where binary is..
|
|
|
|
chdir $binary_dir or die "chdir($binary_dir): $!\n";
|
|
|
|
|
|
|
|
local $SIG{ALRM} = sub { die "alarm" };
|
|
|
|
alarm $timeout_secs;
|
|
|
|
$pid = open CMD, "$shell_command |"
|
|
|
|
or die "Could not run command: $!";
|
|
|
|
|
|
|
|
while (<CMD>) {
|
|
|
|
$output .= $_;
|
|
|
|
print_log $_;
|
|
|
|
}
|
|
|
|
close CMD or die "Could not close command: $!";
|
|
|
|
$exit_value = $? >> 8;
|
|
|
|
$signal_num = $? >> 127;
|
|
|
|
$sig_name = signal_name($signal_num);
|
|
|
|
$dumped_core = $? & 128;
|
|
|
|
$timed_out = 0;
|
|
|
|
alarm 0;
|
|
|
|
};
|
|
|
|
if($@){
|
|
|
|
if($@ =~ /alarm/){
|
|
|
|
$timed_out = 1;
|
|
|
|
kill_process($pid);
|
|
|
|
}else{
|
|
|
|
print_log("Error running $shell_command: $@\n");
|
|
|
|
$output = $@;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$now = localtime();
|
|
|
|
print_log "End: $now\n";
|
|
|
|
|
|
|
|
if ($exit_value || $timed_out || $dumped_core || $signal_num){
|
|
|
|
print_log("Error running $shell_command\n");
|
|
|
|
if($output){
|
|
|
|
print_log("Output: $output\n");
|
|
|
|
}
|
|
|
|
if ($exit_value) {
|
|
|
|
print_log("Exit value: $exit_value\n");
|
|
|
|
}
|
|
|
|
if ($timed_out) {
|
|
|
|
print_log("Timed out\n");
|
|
|
|
# callers expect exit_value to be non-zero if request timed out
|
|
|
|
$exit_value = 1;
|
|
|
|
}
|
|
|
|
if ($dumped_core) {
|
|
|
|
print_log("Segfault (core dumped)\n");
|
|
|
|
}
|
|
|
|
if ($signal_num) {
|
|
|
|
print_log("Received signal: $sig_name\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return { timed_out=>$timed_out,
|
|
|
|
exit_value=>$exit_value,
|
|
|
|
sig_name=>$sig_name,
|
|
|
|
output=>$output,
|
|
|
|
dumped_core=>$dumped_core };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub get_system_cwd {
|
|
|
|
my $a = Cwd::getcwd()||`pwd`;
|
|
|
|
chomp($a);
|
|
|
|
return $a;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get_graph_tbox_name {
|
|
|
|
if ($Settings::GraphNameOverride ne '') {
|
|
|
|
return $Settings::GraphNameOverride;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $name = hostname();
|
|
|
|
if ($Settings::BuildTag ne '') {
|
|
|
|
$name .= '_' . $Settings::BuildTag;
|
|
|
|
}
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_log_test_result {
|
|
|
|
my ($test_name, $test_title, $num_result, $units, $print_name, $print_result) = @_;
|
|
|
|
|
|
|
|
print_log "\nTinderboxPrint:";
|
|
|
|
if ($Settings::TestsPhoneHome) {
|
|
|
|
my $time = POSIX::strftime "%Y:%m:%d:%H:%M:%S", localtime;
|
|
|
|
print_log "<a title=\"$test_title\" href=\"http://$Settings::results_server/graph/query.cgi?testname=" . $test_name . "&units=$units&tbox=" . get_graph_tbox_name() . "&autoscale=1&days=7&avg=1&showpoint=$time,$num_result\">";
|
|
|
|
} else {
|
|
|
|
print_log "<abbr title=\"$test_title\">";
|
|
|
|
}
|
|
|
|
print_log $print_name;
|
|
|
|
if (!$Settings::TestsPhoneHome) {
|
|
|
|
print_log "</abbr>";
|
|
|
|
}
|
|
|
|
print_log ':' . $print_result;
|
|
|
|
if ($Settings::TestsPhoneHome) {
|
|
|
|
print_log "</a>";
|
|
|
|
}
|
|
|
|
print_log "\n";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_log_test_result_ms {
|
|
|
|
my ($test_name, $test_title, $result, $print_name) = @_;
|
|
|
|
print_log_test_result($test_name, $test_title, $result, 'ms',
|
|
|
|
$print_name, $result . 'ms');
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_log_test_result_bytes {
|
|
|
|
my ($test_name, $test_title, $result, $print_name, $sig_figs) = @_;
|
|
|
|
|
|
|
|
print_log_test_result($test_name, $test_title, $result, 'bytes',
|
|
|
|
$print_name, PrintSize($result, $sig_figs) . 'B');
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_log_test_result_count {
|
|
|
|
my ($test_name, $test_title, $result, $print_name, $sig_figs) = @_;
|
|
|
|
print_log_test_result($test_name, $test_title, $result, 'count',
|
|
|
|
$print_name, PrintSize($result, $sig_figs));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Report test results back to a server.
|
|
|
|
# Netscape-internal now, will push to mozilla.org, ask
|
|
|
|
# mcafee or jrgm for details.
|
|
|
|
#
|
|
|
|
# Needs the following perl stubs, installed for rh7.1:
|
|
|
|
# perl-Digest-MD5-2.13-1.i386.rpm
|
|
|
|
# perl-MIME-Base64-2.12-6.i386.rpm
|
|
|
|
# perl-libnet-1.0703-6.noarch.rpm
|
|
|
|
# perl-HTML-Tagset-3.03-3.i386.rpm
|
|
|
|
# perl-HTML-Parser-3.25-2.i386.rpm
|
|
|
|
# perl-URI-1.12-5.noarch.rpm
|
|
|
|
# perl-libwww-perl-5.53-3.noarch.rpm
|
|
|
|
#
|
|
|
|
sub send_results_to_server {
|
|
|
|
my ($value, $raw_data, $testname) = @_;
|
|
|
|
|
|
|
|
# Prepend raw data with cvs checkout date, performance
|
|
|
|
# Use MOZ_CO_DATE, but with same graph/collect.cgi format. (server)
|
|
|
|
#my $data_plus_co_time = "MOZ_CO_DATE=$co_time_str\t$raw_data";
|
|
|
|
my $data_plus_co_time = "MOZ_CO_DATE=test";
|
|
|
|
my $tbox = get_graph_tbox_name();
|
|
|
|
|
|
|
|
my $tmpurl = "http://$Settings::results_server/graph/collect.cgi";
|
|
|
|
$tmpurl .= "?value=$value&data=$data_plus_co_time&testname=$testname&tbox=$tbox";
|
|
|
|
|
|
|
|
print_log "send_results_to_server(): \n";
|
|
|
|
print_log "tmpurl = $tmpurl\n";
|
|
|
|
|
|
|
|
# libwww-perl has process control problems on windows,
|
|
|
|
# spawn wget instead.
|
|
|
|
if ($Settings::OS =~ /^WIN/) {
|
|
|
|
system ("wget", "-O", "/dev/null", $tmpurl);
|
|
|
|
print_log "send_results_to_server() succeeded.\n";
|
|
|
|
} else {
|
|
|
|
my $res = eval q{
|
|
|
|
use LWP::UserAgent;
|
|
|
|
use HTTP::Request;
|
|
|
|
my $ua = LWP::UserAgent->new;
|
|
|
|
$ua->timeout(10); # seconds
|
|
|
|
my $req = HTTP::Request->new(GET => $tmpurl);
|
|
|
|
my $res = $ua->request($req);
|
|
|
|
return $res;
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
warn "Failed to submit startup results: $@";
|
|
|
|
print_log "send_results_to_server() failed.\n";
|
|
|
|
} else {
|
|
|
|
print_log "Results submitted to server: \n" .
|
|
|
|
$res->status_line . "\n" . $res->content . "\n";
|
|
|
|
print_log "send_results_to_server() succeeded.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub kill_process {
|
|
|
|
my ($target_pid) = @_;
|
|
|
|
my $start_time = time;
|
|
|
|
|
|
|
|
# Try to kill and wait 10 seconds, then try a kill -9
|
|
|
|
my $sig;
|
|
|
|
for $sig ('TERM', 'KILL') {
|
|
|
|
print "kill $sig $target_pid\n";
|
|
|
|
kill $sig => $target_pid;
|
|
|
|
my $interval_start = time;
|
|
|
|
while (time - $interval_start < 10) {
|
|
|
|
# the following will work with 'cygwin' perl on win32, but not
|
|
|
|
# with 'MSWin32' (ActiveState) perl
|
|
|
|
my $pid = waitpid($target_pid, POSIX::WNOHANG());
|
|
|
|
if (($pid == $target_pid and POSIX::WIFEXITED($?)) or $pid == -1) {
|
|
|
|
my $secs = time - $start_time;
|
|
|
|
$secs = $secs == 1 ? '1 second' : "$secs seconds";
|
|
|
|
print_log "Process killed. Took $secs to die.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sleep 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
die "Unable to kill process: $target_pid";
|
|
|
|
}
|
|
|
|
|
|
|
|
BEGIN {
|
|
|
|
my %sig_num = ();
|
|
|
|
my @sig_name = ();
|
|
|
|
|
|
|
|
sub signal_name {
|
|
|
|
# Find the name of a signal number
|
|
|
|
my ($number) = @_;
|
|
|
|
|
|
|
|
unless (@sig_name) {
|
|
|
|
unless($Config::Config{sig_name} && $Config::Config{sig_num}) {
|
|
|
|
die "No sigs?";
|
|
|
|
} else {
|
|
|
|
my @names = split ' ', $Config::Config{sig_name};
|
|
|
|
@sig_num{@names} = split ' ', $Config::Config{sig_num};
|
|
|
|
foreach (@names) {
|
|
|
|
$sig_name[$sig_num{$_}] ||= $_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $sig_name[$number];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub PercentChange($$) {
|
|
|
|
my ($old, $new) = @_;
|
|
|
|
if ($old == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return ($new - $old) / $old;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Print a value of bytes out in a reasonable
|
|
|
|
# KB, MB, or GB form. Sig figs should probably
|
|
|
|
# be 3, 4, or 5 for most purposes here. This used
|
|
|
|
# to default to 3 sig figs, but I wanted 4 so I
|
|
|
|
# generalized here. -mcafee
|
|
|
|
#
|
|
|
|
# Usage: PrintSize(valueAsInteger, numSigFigs)
|
|
|
|
#
|
|
|
|
sub PrintSize($$) {
|
|
|
|
|
|
|
|
# print a number with 3 significant figures
|
|
|
|
sub PrintNum($$) {
|
|
|
|
my ($num, $sigs) = @_;
|
|
|
|
my $rv;
|
|
|
|
|
|
|
|
# Figure out how many decimal places to show.
|
|
|
|
# Only doing a few cases here, for normal range
|
|
|
|
# of test numbers.
|
|
|
|
|
|
|
|
# Handle zero case first.
|
|
|
|
if ($num == 0) {
|
|
|
|
$rv = "0";
|
|
|
|
} elsif ($num < 10**($sigs-5)) {
|
|
|
|
$rv = sprintf "%.5f", ($num);
|
|
|
|
} elsif ($num < 10**($sigs-4)) {
|
|
|
|
$rv = sprintf "%.4f", ($num);
|
|
|
|
} elsif ($num < 10**($sigs-3)) {
|
|
|
|
$rv = sprintf "%.3f", ($num);
|
|
|
|
} elsif ($num < 10**($sigs-2)) {
|
|
|
|
$rv = sprintf "%.2f", ($num);
|
|
|
|
} elsif ($num < 10**($sigs-1)) {
|
|
|
|
$rv = sprintf "%.1f", ($num);
|
|
|
|
} else {
|
|
|
|
$rv = sprintf "%d", ($num);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
my ($size, $sigfigs) = @_;
|
|
|
|
|
|
|
|
# 1K = 1024, previously this was approximated as 1000.
|
|
|
|
my $rv;
|
|
|
|
if ($size > 1073741824) { # 1024^3
|
|
|
|
$rv = PrintNum($size / 1073741824.0, $sigfigs) . "G";
|
|
|
|
} elsif ($size > 1048576) { # 1024^2
|
|
|
|
$rv = PrintNum($size / 1048576.0, $sigfigs) . "M";
|
|
|
|
} elsif ($size > 1024) {
|
|
|
|
$rv = PrintNum($size / 1024.0, $sigfigs) . "K";
|
|
|
|
} else {
|
|
|
|
$rv = PrintNum($size, $sigfigs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Page loader (-f option):
|
|
|
|
# If you are building optimized, you need to add
|
|
|
|
# --enable-trace-malloc --enable-perf-metrics
|
|
|
|
# to turn the pageloader code on. If you are building debug you only
|
|
|
|
# need
|
|
|
|
# --enable-trace-malloc
|
|
|
|
#
|
|
|
|
|
|
|
|
sub ReadLeakstatsLog($) {
|
|
|
|
my ($filename) = @_;
|
|
|
|
my $leaks = 0;
|
|
|
|
my $leaked_allocs = 0;
|
|
|
|
my $mhs = 0;
|
|
|
|
my $bytes = 0;
|
|
|
|
my $allocs = 0;
|
|
|
|
|
|
|
|
open LEAKSTATS, "$filename"
|
|
|
|
or die "unable to open $filename";
|
|
|
|
while (<LEAKSTATS>) {
|
|
|
|
chop;
|
|
|
|
my $line = $_;
|
|
|
|
if ($line =~ /Leaks: (\d+) bytes, (\d+) allocations/) {
|
|
|
|
$leaks = $1;
|
|
|
|
$leaked_allocs = $2;
|
|
|
|
} elsif ($line =~ /Maximum Heap Size: (\d+) bytes/) {
|
|
|
|
$mhs = $1;
|
|
|
|
} elsif ($line =~ /(\d+) bytes were allocated in (\d+) allocations./) {
|
|
|
|
$bytes = $1;
|
|
|
|
$allocs = $2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
'leaks' => $leaks,
|
|
|
|
'leaked_allocs' => $leaked_allocs,
|
|
|
|
'mhs' => $mhs,
|
|
|
|
'bytes' => $bytes,
|
|
|
|
'allocs' => $allocs
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|