Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.2 KiB

  1. #!/usr/bin/perl -w
  2. BEGIN {
  3. # Ensure that we have the MIME::Entity package installed first
  4. eval { require MIME::Entity };
  5. if ($@) {
  6. $ENV{http_proxy}='http://squid.valvesoftware.com/';
  7. system('ppm', 'install', 'MIME::Entity');
  8. }
  9. }
  10. use Getopt::Long;
  11. use Pod::Usage;
  12. use MIME::Entity;
  13. use File::Basename;
  14. use Archive::Zip;
  15. use FindBin;
  16. use Win32;
  17. use strict;
  18. my @NOTIFICATION_LIST = qw([email protected] [email protected]);
  19. my $LOGMAN_EXE = "$ENV{SystemRoot}\\System32\\logman.exe";
  20. my $log = undef;
  21. my $help = 0;
  22. my $man = 0;
  23. my $collection = "bad";
  24. my $run_for = 15;
  25. GetOptions("log=s" => \$log,
  26. "bad" => sub { $collection = "bad" },
  27. "ok" => sub { $collection = "ok" },
  28. "runfor=i" => \$run_for,
  29. "help|?" => \$help,
  30. "man" => \$man) or pod2usage(2);
  31. pod2usage(1) if $help;
  32. pod2usage(-exitstatus => 0, -verbose => 2) if $man;
  33. if ($log) {
  34. SendLog($log);
  35. }
  36. else {
  37. StartLogging($collection);
  38. }
  39. exit 0;
  40. sub SendLog {
  41. my $log = shift;
  42. my $logname = basename($log, ".blg");
  43. print "Compressing $log to $logname.zip\n";
  44. my $zip = Archive::Zip->new();
  45. $zip->addFile($log);
  46. $zip->writeToFileNamed("$logname.zip");
  47. my $user = Win32::LoginName();
  48. $user =~ s|^\\valve\\||i;
  49. my $machine = uc Win32::NodeName();
  50. print "Sending: $logname.zip from $user\@$machine\n";
  51. my $message = MIME::Entity->build(Type => "multipart/mixed",
  52. From => "$user\@valvesoftware.com",
  53. To => join(", ", @NOTIFICATION_LIST),
  54. Subject => "WTF: $machine: $logname");
  55. $message->attach(Path => "$logname.zip",
  56. Type => "binary/octet-stream",
  57. Encoding => "base64");
  58. $message->send("smtp", Server => "exchange3.valvesoftware.com");
  59. unlink("$logname.zip");
  60. }
  61. sub StartLogging {
  62. my $collection = shift;
  63. unless (CheckCollection($collection)) {
  64. InstallCollection($collection) || die "Failed to install collection\n";
  65. }
  66. StopCollection($collection);
  67. if (StartCollection($collection)) {
  68. local $| = 1;
  69. print "Collecting samples: ";
  70. while($run_for > 0) {
  71. print $run_for % 5 ? "." : $run_for;
  72. #IsRunningCollection($collection);
  73. sleep(1);
  74. $run_for--;
  75. }
  76. print "Done\n";
  77. if (StopCollection($collection)) {
  78. my $log = FindLog($collection);
  79. if ($log) {
  80. SendLog($log);
  81. }
  82. }
  83. }
  84. }
  85. sub CheckCollection {
  86. my $collection = shift;
  87. if (open(my $pipe, "$LOGMAN_EXE query WTF-$collection |")) {
  88. while(my $line = <$pipe>) {
  89. if ($line =~ /Collection "WTF-$collection" does not exist/) {
  90. return;
  91. }
  92. elsif ($line =~ /Name:\s+WTF-$collection/) {
  93. return 1;
  94. }
  95. }
  96. }
  97. return;
  98. }
  99. sub IsRunningCollection {
  100. my $collection = shift;
  101. if (open(my $pipe, "$LOGMAN_EXE query WTF-$collection |")) {
  102. while(my $line = <$pipe>) {
  103. if ($line =~ /^Status:\s+(\w+)/) {
  104. my $status = $1;
  105. print "STATUS: $status\n";
  106. return 1 if ($status eq 'Running');
  107. return 1 if ($status eq 'Pending');
  108. return 0;
  109. }
  110. }
  111. }
  112. return 0;
  113. }
  114. sub InstallCollection {
  115. my $collection = shift;
  116. print "Create WTF-$collection collection\n";
  117. system("$LOGMAN_EXE", "create", "counter", "WTF-$collection", "-si", 1, "-cf", "$FindBin::Bin\\wtf.txt");
  118. return if ($?);
  119. return 1;
  120. }
  121. sub StartCollection {
  122. my $collection = shift;
  123. print "Start WTF-$collection collection\n";
  124. eval {
  125. system("$LOGMAN_EXE", "start", "WTF-$collection");
  126. die "Starting Collection: $!\n" if ($?);
  127. };
  128. return 1;
  129. }
  130. sub StopCollection {
  131. my $collection = shift;
  132. print "Stop WTF-$collection collection\n";
  133. eval {
  134. system("$LOGMAN_EXE", "stop", "WTF-$collection");
  135. die "Stopping Collection: $!\n" if ($?);
  136. while (IsRunningCollection($collection)) {
  137. sleep 1;
  138. }
  139. };
  140. return 1;
  141. }
  142. sub FindLog {
  143. my $collection = shift;
  144. if (opendir(my $dirh, "C:\\PerfLogs")) {
  145. my @files = sort { (stat("c:\\PerfLogs\\$a"))[9] <=> (stat("c:\\PerfLogs\\$b"))[9] } grep {
  146. /^WTF-$collection\_\d+\.blg$/
  147. } readdir($dirh);
  148. my $log = $files[-1];
  149. print "Located latest log: $log\n";
  150. return "C:\\PerfLogs\\$log";
  151. }
  152. print "No log found\n";
  153. return;
  154. }
  155. END {
  156. if (IsRunningCollection($collection)) {
  157. StopCollection($collection);
  158. }
  159. }
  160. __END__
  161. =head1 NAME
  162. wtf.pl - Grabs a small capture of the performance data for the local machine and sends the information to the VMPI maintainers
  163. =head1 SYNOPSIS
  164. wtf.pl [-runfor <time>] [-help|-?] [-man] -log <log> | -bad | -good
  165. Options:
  166. -bad Captures the data to the "bad" log (default)
  167. -good Captures the data to the "good" log
  168. -log Specifies the log to send
  169. -runfor Specified the amount of time to sample for
  170. -help|-? Display command line usage
  171. -man Display full documentation
  172. =head1 DESCRIPTION
  173. B<wtf.pl> is for capturing information about your system when VMPI is
  174. doing something "bad". The default behaviour is to capture 15 seconds
  175. of data and send the performance log to the VMPI maintainers. You can
  176. optionally run another capture to show a "good" situation for a
  177. baseline to compare against.
  178. =head1 BUGS
  179. The logman program that is used by wtf.pl does not support the -rc
  180. command properly, so I cannot register wtf.pl to automatically send
  181. the log when the capture ends. Instead I must manually start/wait/stop.
  182. =cut