#!/usr/bin/perl -w
# The contents of this file are subject to the terms of the Common Development
# and Distribution License (the License). You may not use this file except in
# compliance with the License.
#
# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
# or http://www.netbeans.org/cddl.txt.
# 
# When distributing Covered Code, include this CDDL Header Notice in each file
# and include the License file at http://www.netbeans.org/cddl.txt.
# If applicable, add the following below the CDDL Header, with the fields
# enclosed by brackets [] replaced by your own identifying information:
# "Portions Copyrighted [year] [name of copyright owner]"
#
# The Original Software is NetBeans. The Initial Developer of the Original
# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
# Microsystems, Inc. All Rights Reserved.

use strict;
use File::Basename qw(dirname);
# If you don't have this, get it from CPAN:
use Time::HiRes qw(time);

unless (@ARGV) {
  print STDERR <<'USAGE';
Measure startup-time impact of a change to NetBeans.

Usage: time-delta.pl RUNIDE_OLD.SH RUNIDE_NEW.SH ARG...

Suggested flags (in ARG section):
-nogui -nosplash		Run in non-GUI mode
-J-Dnetbeans.warm.close=true	Run warm-up tasks before exiting

Implied flags (always included):

-userdir <<testarea>> -J-Dnetbeans.logger.console=false -J-Dnetbeans.close=true -J-Dnetbeans.full.hack=true

This script (and the NB build in it) should maybe be in /dev/shm or a
similar RAM disk. Disable as many other apps on the machine as possible,
or timing results may be disturbed.
USAGE
  exit 2;
}
my $runide_old = shift;
my $runide_new = shift;
print "Testing startup time in: $runide_old and $runide_new\n";
print "Shut down any other major running GUI apps before starting!\n";
print "That includes fancy screensavers.\n";
print "Now go get some coffee and come back in ten minutes.\n";

my $primer_stages = 3;
my $real_stages = 15;
my $userdir_base = -w "/dev/shm" ? "/dev/shm/time-delta-ud" : "/tmp/time-delta-ud";
system('rm', '-rfv', $userdir_base) and die "rm -rfv $userdir_base: $!";

sub run($$) {
  my ($stage, $opt) = @_;
  if ($opt eq 'true') {
    print "Running optimized $stage...\n";
  } else {
    print "Running unoptimized $stage...\n";
  }
  my $actual_userdir = "$userdir_base/opt-$opt";
  unlink("$actual_userdir/system/ide.log"); # OK if fails
  my $start = time;
  my $actual_runide = ($opt eq 'true') ? $runide_new : $runide_old;
  system($actual_runide, '-userdir', $actual_userdir, '-J-Dnetbeans.logger.console=false', '-J-Dnetbeans.close=true', '-J-Dnetbeans.full.hack=true', @ARGV)
    and die "Failed to start NetBeans: $!";
  my $end = time;
  my $delta = $end - $start;
  print "\tElapsed time: $delta\n";
  return $delta;
}

# Run primer stages to get RAM and disk cache ready:
foreach my $i (map {"primer$_"} 1..$primer_stages) {
  foreach my $j ('false', 'true') {
    run($i, $j);
  }
}

# Now the real runs:
my $unopted = 0;
my @unopted = ();
my $opted = 0;
my @opted = ();
foreach my $i (map {"stage$_"} 1..$real_stages) {
  my $time = run($i, 'false');
  push @unopted, $time;
  $unopted += $time;
  $time = run($i, 'true');
  push @opted, $time;
  $opted += $time;
}

# Lies, damn lies, and statistics:
$unopted /= $real_stages;
$opted /= $real_stages;
my $delta = $unopted - $opted;
my $perc = $delta / $unopted * 100;
my $unopted_sumsq = 0;
foreach my $i (@unopted) {$unopted_sumsq += ($i - $unopted) ** 2}
my $unopted_stddev = sqrt($unopted_sumsq / ($real_stages - 1));
my $opted_sumsq = 0;
foreach my $i (@opted) {$opted_sumsq += ($i - $opted) ** 2}
my $opted_stddev = sqrt($opted_sumsq / ($real_stages - 1));
print "Average times: unoptimized  $unopted\n";
print "                 std. dev.  $unopted_stddev\n";
print "                 optimized  $opted\n";
print "                 std. dev.  $opted_stddev\n";
print "Improvement:                $delta\n";
print "Percentage:                 $perc%\n";
my $max_dev = ($unopted_stddev > $opted_stddev) ? $unopted_stddev : $opted_stddev;
print "Executive summary:\n";
if ($delta < 0) {
  print "You're a hoser.\n";
} elsif ($delta < $max_dev) {
  print "These numbers are so close as to be meaningless. Give up.\n";
} elsif ($delta < 2 * $max_dev) {
  print "You might have saved a little time, but it's not really clear.\n";
} elsif ($delta < 3 * $max_dev) {
  print "You probably saved some time here, though it is not for sure.\n";
} else {
  print "You pretty clearly saved time. Congratulations!\n";
}
