Francois Gouget : testbot/log2revtimes: Add a script to extract the VM revert times from the WineTestBot log and prepare them for analysis.
Alexandre Julliard
julliard at winehq.org
Wed May 14 14:39:15 CDT 2014
Module: tools
Branch: master
Commit: 8928cfed8b86c32d627ab8b0ace514d15b7469f3
URL: http://source.winehq.org/git/tools.git/?a=commit;h=8928cfed8b86c32d627ab8b0ace514d15b7469f3
Author: Francois Gouget <fgouget at codeweavers.com>
Date: Mon May 12 19:31:27 2014 +0200
testbot/log2revtimes: Add a script to extract the VM revert times from the WineTestBot log and prepare them for analysis.
---
testbot/scripts/log2revtimes | 324 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 324 insertions(+)
diff --git a/testbot/scripts/log2revtimes b/testbot/scripts/log2revtimes
new file mode 100755
index 0000000..2eac048
--- /dev/null
+++ b/testbot/scripts/log2revtimes
@@ -0,0 +1,324 @@
+#!/usr/bin/perl
+#
+# Parses the WineTestBot Engine's log to extract the VM revert times.
+#
+# Copyright 2013-2014 Francois Gouget
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+use warnings;
+use strict;
+
+use DateTime::Format::Strptime;
+
+
+my $name0 = $0;
+$name0 =~ s+^.*/++;
+
+sub error(@)
+{
+ print STDERR "$name0:error: ", @_;
+}
+
+
+#
+# Command line parsing
+#
+
+my $Usage;
+
+sub check_opt_val($$)
+{
+ my ($option, $val) = @_;
+
+ if (defined $val)
+ {
+ error("$option can only be specified once\n");
+ $Usage = 2; # but continue processing this option
+ }
+ if (!@ARGV)
+ {
+ error("missing value for $option\n");
+ $Usage = 2;
+ return undef;
+ }
+ return shift @ARGV;
+}
+
+sub CheckAndConvertDate($)
+{
+ my ($DateStr) = @_;
+ return undef if (!defined $DateStr);
+
+ my $DateParser = DateTime::Format::Strptime->new(
+ pattern => '%Y/%m/%d',
+ time_zone => 'local',
+ );
+ my $DT = $DateParser->parse_datetime($DateStr);
+ if (!defined $DT)
+ {
+ error("'$DateStr' is not a valid timestamp\n");
+ $Usage = 2;
+ return undef;
+ }
+ return $DT->epoch;
+}
+
+my ($OptLogFile, $OptMixed, $OptStart, $OptStop, $OptMaxLines);
+
+while (@ARGV)
+{
+ my $arg = shift @ARGV;
+ if ($arg eq "--help")
+ {
+ $Usage = 0;
+ }
+ elsif ($arg eq "--mixed")
+ {
+ $OptMixed = 1;
+ }
+ elsif ($arg eq "--start")
+ {
+ $OptStart = check_opt_val($arg, $OptStart);
+ }
+ elsif ($arg eq "--stop")
+ {
+ $OptStop = check_opt_val($arg, $OptStop);
+ }
+ elsif ($arg eq "--max-lines")
+ {
+ $OptMaxLines = check_opt_val($arg, $OptMaxLines);
+ }
+ elsif (!defined $OptLogFile)
+ {
+ $OptLogFile = $arg;
+ }
+ else
+ {
+ error("unexpected argument '$arg'\n");
+ $Usage = 2;
+ }
+}
+
+if (!defined $Usage)
+{
+ if (!defined $OptLogFile)
+ {
+ error("you must specify the log file to analyze\n");
+ $Usage = 2;
+ }
+ $OptStart = CheckAndConvertDate($OptStart);
+ $OptStop = CheckAndConvertDate($OptStop);
+ if (defined $OptStart and defined $OptStop and $OptStop <= $OptStart)
+ {
+ error("the start date must be earlier than the stop date\n");
+ $Usage = 2;
+ }
+ if (defined $OptMaxLines)
+ {
+ my $oldwarn = $SIG{__WARN__};
+ $SIG{__WARN__} = sub { die $_[0] };
+ my $bad = eval { $OptMaxLines < 1 };
+ if (defined $oldwarn)
+ {
+ $SIG{__WARN__} = $oldwarn;
+ }
+ else
+ {
+ delete $SIG{__WARN__};
+ }
+ if ($bad or $@)
+ {
+ error("the maximum line count is invalid\n");
+ $Usage = 2;
+ }
+ }
+}
+if (defined $Usage)
+{
+ if ($Usage)
+ {
+ error("try '$name0 --help' for more information\n");
+ exit $Usage;
+ }
+ print "Usage: $name0 [--help] LOGFILE\n";
+ print "\n";
+ print "Analyzes a WineTestBot log file and generates a report on stdout containing the revert times per VM. The report is tab-separated and is suitable for import into a spreadsheet.\n";
+ print "\n";
+ print "Where:\n";
+ print " LOGFILE Is the log file to analyze.\n";
+ print " --mixed Report the revert times of all the VMs together instead of\n";
+ print " having a set of columns for each VM.\n";
+ print " --start DATE Only report about revert starting on or after the specified\n";
+ print " date (in yyyy/mm/dd format).\n";
+ print " --stop DATE Only report about revert ending on or before the specified\n";
+ print " date (in yyyy/mm/dd format).\n";
+ print " --max-lines COUNT The maximum number of lines to return.\n";
+ print " --help Shows this usage message.\n";
+ exit 0;
+}
+
+
+#
+# Log parsing
+#
+
+my ($Lines, %VMReverts, %VMLines);
+
+sub AddRevert($$$$)
+{
+ my ($Date, $Duration, $VM, $Snapshot) = @_;
+
+ if ($OptMixed)
+ {
+ print "$Date\t$Duration\t\"$VM\"\t\"$Snapshot\"\n";
+ $Lines++;
+ return 0 if (defined $OptMaxLines and $Lines > $OptMaxLines);
+ }
+ else
+ {
+ # Skip reverts that have errors
+ return 1 if ($Duration < 0);
+ $VMReverts{$VM} ||= [];
+ push @{$VMReverts{$VM}}, [$Date, $Duration, $Snapshot];
+ $VMLines{$VM}++;
+ return 0 if (defined $OptMaxLines and $VMLines{$VM} > $OptMaxLines);
+ }
+ return 1;
+}
+
+if (open(my $fh, "<", $OptLogFile))
+{
+ print "Timestamp\tDuration\tVM\tSnapshot\n" if ($OptMixed);
+
+ my $DateParser = DateTime::Format::Strptime->new(
+ pattern => '%a %b %d %H:%M:%S %Y',
+ time_zone => 'local',
+ );
+
+ my (%Epochs, %Dates, %Snapshots);
+ my $Skip = defined $OptStart ? 1 : defined $OptStop ? 0 : undef;
+ foreach my $Line (<$fh>)
+ {
+ next if ($Line !~ s/^(.*?) RevertVM(?:\[[0-9]*\])?: (Reverting|Letting) ([a-zA-Z0-9-]+)//);
+ my ($DateStr, $Action, $VM) = ($1, $2, $3);
+ my $DT = $DateParser->parse_datetime($DateStr);
+ my $Epoch = $DT->epoch;
+
+ if ($Skip)
+ {
+ if (defined $OptStart and $OptStart <= $Epoch)
+ {
+ $Skip = 0;
+ }
+ else
+ {
+ next;
+ }
+ }
+ elsif (defined $Skip and defined $OptStop and $Epoch > $OptStop)
+ {
+ last;
+ }
+
+ if ($Action eq "Reverting")
+ {
+ if (defined $Epochs{$VM})
+ {
+ # This revert never completed!
+ my $Snapshot = $Snapshots{$VM} || "Unknown";
+ last if (!AddRevert($Dates{$VM}, -2, $VM, $Snapshot));
+ }
+
+ $Epochs{$VM} = $Epoch;
+ $Dates{$VM} = $DT->ymd("/") . " " . $DT->hms();
+ $Snapshots{$VM} = $1 if ($Line =~ /to ([a-zA-Z0-9-]+)$/);
+ }
+ else
+ {
+ my $Snapshot = $Snapshots{$VM} || "Unknown";
+ if (!defined $Epochs{$VM})
+ {
+ # We don't have a start date for this revert!
+ last if (!AddRevert($Dates{$VM}, -1, $VM, "Unknown"));
+ }
+ else
+ {
+ my $Duration = $Epoch - $Epochs{$VM};
+ last if (!AddRevert($Dates{$VM}, $Duration, $VM, $Snapshot));
+ }
+
+ delete $Epochs{$VM};
+ delete $Dates{$VM};
+ delete $Snapshots{$VM};
+ }
+ }
+ close($fh);
+}
+else
+{
+ error("unable to open '$OptLogFile' for reading: $!\n");
+ exit 1;
+}
+
+
+#
+# Report output
+#
+
+if (!$OptMixed)
+{
+ my $First=1;
+ foreach my $VM (sort keys %VMReverts)
+ {
+ print "\t" if (!$First);
+ $First = undef;
+ print "$VM\t\t";
+ }
+ print "\n";
+
+ $First=1;
+ my $LineCount = 0;
+ foreach my $VM (sort keys %VMReverts)
+ {
+ print "\t" if (!$First);
+ $First = undef;
+ print "Date\tDuration\tSnapshot";
+ $LineCount = $VMLines{$VM} if ($LineCount < $VMLines{$VM});
+ }
+ print "\n";
+
+ for (my $i = 0; $i < $LineCount; $i++)
+ {
+ $First=1;
+ foreach my $VM (sort keys %VMReverts)
+ {
+ print "\t" if (!$First);
+ $First = undef;
+
+ my $Revert = $VMReverts{$VM}->[$i];
+ if ($Revert)
+ {
+ my ($Date, $Duration, $Snapshot) = @$Revert;
+ print "$Date\t$Duration\t$Snapshot";
+ }
+ else
+ {
+ print "\t\t";
+ }
+ }
+ print "\n";
+ }
+}
More information about the wine-cvs
mailing list