summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorgavin <gavin@FreeBSD.org>2014-06-22 16:35:03 +0000
committergavin <gavin@FreeBSD.org>2014-06-22 16:35:03 +0000
commita1fd834d280fdb600af24f39450f1a7c7262b4f3 (patch)
treeb44d11724f0f917006c6ff6281569cce81b0ef45 /tools
parent409266d9a5390d93c3c5ae6488911b4ea24bed4e (diff)
downloadFreeBSD-src-a1fd834d280fdb600af24f39450f1a7c7262b4f3.zip
FreeBSD-src-a1fd834d280fdb600af24f39450f1a7c7262b4f3.tar.gz
With the migration from GNATS to Bugzilla, we no longer need a tool to
graph GNATS PR statistics. It would be nice to have a similar tool for the new bug database, but that would likely be a from-scratch rewrite.
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/README1
-rw-r--r--tools/tools/prstats/prstats.pl357
2 files changed, 0 insertions, 358 deletions
diff --git a/tools/tools/README b/tools/tools/README
index ef05ee0..44d13bd 100644
--- a/tools/tools/README
+++ b/tools/tools/README
@@ -55,7 +55,6 @@ pciid Generate src/share/misc/pci_vendors.
pciroms A tool for dumping PCI ROM images. WARNING: alpha quality.
pirtool A tool for dumping the $PIR table on i386 machines at runtime.
portsinfo Generate list of new ports for last two weeks.
-prstats Generate statistics about the PR database.
recoverdisk Copy as much data as possible from a defective disk.
scsi-defects Get at the primary or grown defect list of a SCSI disk.
sysdoc Build a manual page with available sysctls for a specific
diff --git a/tools/tools/prstats/prstats.pl b/tools/tools/prstats/prstats.pl
deleted file mode 100644
index c31241e..0000000
--- a/tools/tools/prstats/prstats.pl
+++ /dev/null
@@ -1,357 +0,0 @@
-#!/usr/bin/perl -w
-#-
-# Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer
-# in this position and unchanged.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. The name of the author may not be used to endorse or promote products
-# derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# $FreeBSD$
-#
-
-use strict;
-use Data::Dumper;
-use Fcntl;
-use POSIX qw(isatty mktime strftime tzset);
-use vars qw($TTY $NOW %MONTH %PR @EVENTS @COUNT @AGE);
-use vars qw(%STATE %CATEGORY %OWNER %CLOSER);
-
-%MONTH = (
- 'Jan' => 1,
- 'Feb' => 2,
- 'Mar' => 3,
- 'Apr' => 4,
- 'May' => 5,
- 'Jun' => 6,
- 'Jul' => 7,
- 'Aug' => 8,
- 'Sep' => 9,
- 'Oct' => 10,
- 'Nov' => 11,
- 'Dec' => 12,
-);
-
-@AGE = (
- [ 0, 7, 0 ], # Less than one week
- [ 7, 30, 0 ], # One week to one month
- [ 30, 90, 0 ], # One to three months
- [ 90, 365, 0 ], # Three months to a year
- [ 365, 1095, 0 ], # One to three years
- [ 1095, 999999, 0 ], # More than three years
-);
-
-sub GNATS_DIR { "/home/gnats" }
-sub GNATS_TZ { "America/Los_Angeles" }
-sub DATFILE { "/tmp/prstats.dat.$$" }
-sub GNUPLOT { "|/usr/local/bin/gnuplot /dev/stdin" }
-sub TIMEFMT { "%Y-%m-%d/%H:%M:%S" }
-
-sub parse_date($) {
- my $date = shift; # Date to parse
-
- my $year;
- my $month;
- my $day;
- my $hour;
- my $minute;
- my $second;
-
- $date =~ s/\s+/ /g;
- $date =~ s/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\w*\s*//;
- if ($date =~ m/^(\w{3}) (\d\d?) (\d\d):(\d\d):(\d\d) [A-Z ]*(\d{4})$/) {
- ($month, $day, $hour, $minute, $second, $year) =
- ($1, $2, $3, $4, $5, $6);
- } else {
- die("Unrecognized date format: $date\n");
- }
- defined($month = $MONTH{$month})
- or die("Invalid month: $month\n");
- return mktime($second, $minute, $hour, $day, $month - 1, $year - 1900);
-}
-
-sub scan_pr($) {
- my $fn = shift; # File name
-
- local *FILE; # File handle
- my $pr = {}; # PR hash
- my $age; # PR age
-
- sysopen(FILE, $fn, O_RDONLY)
- or die("$fn: open(): $!\n");
- while (<FILE>) {
- if (m/^>([A-Za-z-]+):\s+(.*?)\s*$/o ||
- m/^(Category|Responsible|State-Changed-[A-Za-z-]+):\s+(.*?)\s*$/o) {
- $pr->{lc($1)} = $2;
- }
- }
-
- exists($PR{$pr->{'number'}})
- and die("$fn: PR $pr->{'number'} already exists\n");
-
- if ($TTY) {
- print(" "x40, "\r", scalar(keys(%PR)),
- " $pr->{'category'}/$pr->{'number'} ");
- }
-
- foreach ('arrival-date', 'closed-date', 'last-modified',
- 'state-changed-when') {
- if (defined($pr->{$_}) && length($pr->{$_})) {
- $pr->{$_} = parse_date($pr->{$_});
- }
- }
-
- $pr->{'_created'} = $pr->{'arrival-date'};
- if ($pr->{'state'} eq 'closed') {
- $pr->{'_closed'} = $pr->{'closed-date'} || $pr->{'state-changed-when'};
- $pr->{'_closed_by'} = $pr->{'state-changed-by'};
- if (!defined($pr->{'_closed_by'})) {
- warn("PR $pr->{'category'}/$pr->{'number'} is incomplete\n");
- return;
- }
- ++$CLOSER{$pr->{'_closed_by'}};
- } else {
- $age = $pr->{'arrival-date'} / 86400;
- foreach (@AGE) {
- if ($age >= $_->[0] && $age < $_->[1]) {
- ++$_->[2];
- last;
- }
- }
- ++$CATEGORY{$pr->{'category'}};
- ++$OWNER{$pr->{'responsible'}};
- }
- ++$STATE{$pr->{'state'}};
-
- $PR{$pr->{'number'}} = {
- 'category' => $pr->{'category'},
- #'number' => $pr->{'number'},
- 'responsible' => $pr->{'responsible'},
- 'created' => $pr->{'created'},
- 'closed' => $pr->{'closed'},
- 'closer' => $pr->{'_closed_by'},
- };
- push(@EVENTS, [ $pr->{'_created'}, +1 ]);
- push(@EVENTS, [ $pr->{'_closed'}, -1 ])
- if defined($pr->{'_closed'});
-}
-
-sub scan_recurse($);
-sub scan_recurse($) {
- my $dn = shift; # Directory name
-
- local *DIR; # Directory handle
- my $entry; # Entry
-
- opendir(DIR, $dn)
- or die("$dn: opendir(): $!\n");
- while ($entry = readdir(DIR)) {
- next if ($entry eq '.' || $entry eq '..');
- if (-d "$dn/$entry") {
- scan_recurse("$dn/$entry");
- } elsif ($entry =~ m/^\d+$/) {
- eval {
- scan_pr("$dn/$entry");
- };
- }
- }
- closedir(DIR);
-}
-
-sub count_prs() {
-
- my $pr; # Iterator
- my @events; # Creations or closures
- my $event; # Iterator
- my $count; # PR count
-
- if ($TTY) {
- print(int(@EVENTS), " events\n");
- }
- @COUNT = ( [ 0, 0 ] );
- foreach $event (sort({ $a->[0] <=> $b->[0] } @EVENTS)) {
- if ($event->[0] == $COUNT[-1]->[0]) {
- $COUNT[-1]->[1] += $event->[1];
- } else {
- push(@COUNT, [ $event->[0], $COUNT[-1]->[1] + $event->[1] ]);
- }
- }
- if (@COUNT > 1) {
- $COUNT[0]->[0] = $COUNT[1]->[0] - 1;
- unshift(@COUNT, [ 0, 0 ]);
- }
-}
-
-sub gnuplot(@) {
- my @commands = @_; # Commands
-
- my $pid; # Child PID
- local *PIPE; # Pipe
-
- open(PIPE, &GNUPLOT)
- or die("fork(): $!\n");
- print(PIPE join("\n", @commands, ""));
- close(PIPE);
- if ($? & 0x7f) {
- die("gnuplot caught a signal " . ($? & 0x7f) . "\n");
- } elsif ($?) {
- die("gunplot returned exit code " . ($? >> 8) . "\n");
- }
-}
-
-sub write_dat_file($) {
- my $fn = shift; # File name
-
- local *FILE; # File handle
- my $datum; # Iterator
-
- sysopen(FILE, $fn, O_RDWR|O_CREAT|O_TRUNC, 0640)
- or die("$fn: open(): $!\n");
- foreach $datum (@COUNT) {
- print(FILE strftime(&TIMEFMT, localtime($datum->[0])),
- " ", $datum->[1],
- " ", $COUNT[-1]->[1],
- "\n");
- }
- close(FILE);
-}
-
-sub graph_open_prs($$$$$) {
- my $datfn = shift; # Data file name
- my $fn = shift; # File name
- my $start = shift; # Starting date
- my $end = shift; # Ending date
- my $title = shift; # Title
-
- my $tickfmt; # Tick format
- my $timefmt; # Time format
-
- if ($end - $start > 86400 * 30) {
- $tickfmt = "%Y-%m-%d";
- } else {
- $tickfmt = "%m-%d";
- }
- $start = strftime(&TIMEFMT, localtime($start));
- $end = strftime(&TIMEFMT, localtime($end));
- $timefmt = &TIMEFMT;
- gnuplot("
-set term png small color
-set xdata time
-set timefmt '$timefmt'
-set data style line
-set grid
-set output '$fn'
-set format x '$tickfmt'
-set xrange ['$start':'$end']
-set yrange [0:*]
-set title '$title'
-plot '$datfn' using 1:2 title 'Open PRs'
-");
-}
-
-sub pr_stat_summary() {
-
- my $n; # Loop counter
-
- # Overall stats
- printf("Total PRs in database: %d\n", scalar(keys(%PR)));
- printf("Open PRs: %d\n", scalar(keys(%PR)) - $STATE{'closed'});
- print("\n");
-
- # Category ranking
- print("Number of PRs in each category:\n");
- foreach (sort({ $CATEGORY{$b} <=> $CATEGORY{$a} } keys(%CATEGORY))) {
- printf("%12s: %d\n", $_, $CATEGORY{$_});
- }
- print("\n");
-
- # State ranking
- print("Number of PRs in each state:\n");
- foreach (sort({ $STATE{$b} <=> $STATE{$a} } keys(%STATE))) {
- printf("%12s: %d\n", $_, $STATE{$_});
- }
- print("\n");
-
- # Closer ranking
- print("Top ten PR busters:\n");
- $n = 0;
- foreach (sort({ $CLOSER{$b} <=> $CLOSER{$a} } keys(%CLOSER))) {
- printf(" %2d. %s (%d)\n", ++$n, $_, $CLOSER{$_});
- last if ($n == 10);
- }
- print("\n");
-
- # Owner ranking
- print("Top ten owners of open PRs:\n");
- $n = 0;
- foreach (sort({ $OWNER{$b} <=> $OWNER{$a} } keys(%OWNER))) {
- next if (m/^freebsd-(bugs|doc|ports)$/);
- printf(" %2d. %s (%d)\n", ++$n, $_, $OWNER{$_});
- last if ($n == 10);
- }
- print("\n");
-
-}
-
-MAIN:{
- $| = 1;
- $TTY = isatty(*STDOUT);
-
- # Perl lacks strptime(), and its mktime() doesn't accept a
- # timezone argument, so we set our local timezone to that of the
- # FreeBSD cluster and use localtime() instead.
- $ENV{'TZ'} = &GNATS_TZ;
- tzset();
- $NOW = time();
-
- # Read and count PRs
- if (@ARGV) {
- foreach (@ARGV) {
- scan_recurse(join('/', &GNATS_DIR, $_));
- }
- } else {
- scan_recurse(&GNATS_DIR);
- }
- if ($TTY) {
- print("\r", scalar(keys(%PR)), " problem reports scanned\n");
- }
-
- # Generate graphs
- if (0) {
- count_prs();
- write_dat_file(&DATFILE);
- graph_open_prs(&DATFILE, "week.png", $NOW - (86400 * 7) + 1, $NOW,
- "Open FreeBSD problem reports (week view)");
- graph_open_prs(&DATFILE, "month.png", $NOW - (86400 * 30) + 1, $NOW,
- "Open FreeBSD problem reports (month view)");
- graph_open_prs(&DATFILE, "year.png", $NOW - (86400 * 365) + 1, $NOW,
- "Open FreeBSD problem reports (year view)");
- graph_open_prs(&DATFILE, "ever.png", $COUNT[1]->[0], $NOW,
- "Open FreeBSD problem reports (project history)");
- graph_open_prs(&DATFILE, "drive.png", mktime(0, 0, 0, 29, 4, 101), $NOW,
- "Open FreeBSD problem reports (drive progress)");
- unlink(&DATFILE);
- }
-
- # Print summary
- pr_stat_summary();
-}
OpenPOWER on IntegriCloud