root/trunk/extras/thetop

Revision 134, 4.9 kB (checked in by garth, 3 years ago)

Code to allow a 'top' like view of runnin schwartz workers.

  • Property svn:executable set to *
Line 
1#!/usr/bin/perl -w
2
3=pod
4
5=head1 NAME
6
7thetop - A 'top' utility for the schwartz
8
9=head1 SYNOPSIS
10
11  thetop [--func FORMAT] [--arg FORMAT] [--sort ARGS] [--delay SECS] [--score-dir DIR]
12
13=head1 DESCRIPTION
14
15
16=cut
17
18#--------------------------------------#
19# Dependencies
20
21use strict;
22
23use Getopt::Long;
24use Term::Cap;
25use POSIX;
26
27#--------------------------------------#
28# Global Variables
29
30use vars qw( $OSPEED );
31
32BEGIN {
33    my $termios = POSIX::Termios->new;
34    $termios->getattr;
35    $OSPEED = $termios->getospeed || 9600;
36};
37
38our $TERM = Term::Cap->Tgetent({OSPEED=>$OSPEED});
39
40#--------------------------------------#
41# Main Program
42
43my ($score_dir, $delay, $func_col, @arg_col, $sort);
44
45GetOptions('score-dir=s' => \$score_dir,
46           'delay|d=s'   => \$delay,
47           'func=s'      => \$func_col,
48           'arg=s'       => \@arg_col,
49           'sort|s=s'    => \$sort,
50          );
51
52# Make sure we know where to find the scoreboard files
53unless ($score_dir) {
54    foreach my $d (qw(/var/run /dev/shm /tmp)) {
55        if (-e "$d/theschwartz") {
56            $score_dir = "$d/theschwartz";
57            last;
58        }
59    }
60
61    die "Can't find scoreboard directory.  Use '--score-dir'\n"
62      unless $score_dir;
63}
64
65# If we got some formatting instructions for the arg column, parse it out
66my %arg_col_by_func;
67if (@arg_col) {
68    foreach my $a (@arg_col) {
69        if ($a =~ /=/) {
70            my ($func, $fmt) = split('=', $a);
71            $arg_col_by_func{$func} = $fmt;
72        } else {
73            $arg_col_by_func{'__ALL__'} = $a;
74        }
75    }
76}
77
78# Make sure to give a reasonable default for delay
79$delay ||= 3;
80
81# Start reporting
82clr_screen();
83while (1) {
84    report($score_dir, $func_col, \%arg_col_by_func, $sort);
85    sleep($delay);
86    clr_screen();
87}
88
89################################################################################
90
91sub report {
92    my ($dir, $func_col, $arg_col_by_func, $sort) = @_;
93
94    # Find the files available
95    opendir(SD, $dir) or die "Can't read directory '$dir': $!\n";
96    my @files = map { $dir."/$_" } readdir(SD);
97    closedir(SD);
98
99    # Grab the data out of them
100    my @data;
101    foreach my $f (@files) {
102        next unless $f =~ /scoreboard\.[0-9]+$/;
103        open(SF, '<', $f) or die "Can't open score file '$f': $!\n";
104        my %dat = map { chomp; split('=') } <SF>;
105        close(SF);
106
107        $dat{arg_array} = [split(',', $dat{arg}||'')];
108        push @data, \%dat;
109    }
110
111    my $num = scalar(@data);
112    my $width = 80-17-$num;
113    printf("Workers: %d total %${width}s\n\n", $num, scalar localtime);
114    printf("% 5s % 20s % 2s % 7s % 41s\n", 'PID', 'FUNC', 'S', 'TIME', 'ARGS');
115    foreach my $d (sort { order_by($sort, $a, $b) } @data) {
116        my $func_str = fmt_func($d, $func_col);
117
118        printf("% 5s % 20s % 2s % 7s % 41s\n",
119               $d->{pid},
120               $func_str,
121               ($d->{done} ? 'S' : 'R'),
122               fmt_time($d),
123               fmt_arg($d, $arg_col_by_func, $func_str),
124              );
125    }
126}
127
128sub order_by {
129    my ($sort, $a, $b) = @_;
130
131    if ($sort) {
132
133    } else {
134        # Default to push running tasks to the top
135        return ($a->{done}||0) <=> ($b->{done}||0) ||
136               ($a->{started}||0) <=> ($b->{started}||0);
137    }
138}
139
140sub fmt_func {
141    my ($d, $fmt) = @_;
142    my $val = $d->{funcname};
143
144    if ($fmt) {
145        if ($fmt eq 'trim') {
146            $val =~ s/^.+:://g;
147        } else {
148            $val =~ /($fmt)/;
149            $val = $1;
150        }
151    }
152
153    return substr($val, 0, 20),
154}
155
156sub fmt_time {
157    my ($d) = @_;
158    my $secs = ($d->{done}||time) - $d->{started};
159
160    if ($secs < 60) {
161        return sprintf("%02d:%02d", 0, $secs);
162    } elsif ($secs < 3600) {
163        my $min = int($secs/60);
164        $secs = $secs%60;
165        return sprintf("%02d:%02d", $min, $secs);
166    } else {
167        my $hr  = int($secs/60/60);
168        my $min = int($secs/60%60);
169        $secs = $secs%60;
170        return sprintf("%d:%02d:%02d", $hr, $min, $secs);
171    }
172}
173
174## Format the arguments by interpreting the args as either a hash or an array
175## and printing out the appropriate element.
176
177sub fmt_arg {
178    my ($d, $arg_col_by_func, $func_str) = @_;
179    my $val = $d->{arg};
180    my $func_orig = $d->{funcname};
181
182    if ($arg_col_by_func) {
183        my $fmt = ($arg_col_by_func{$func_str}  ||
184                   $arg_col_by_func{$func_orig} ||
185                   $arg_col_by_func{'__ALL__'});
186        if ($fmt) {
187            my $arg_array = $d->{arg_array};
188
189            # If its a number treat the args as an array
190            if ($fmt =~ /^[0-9]+$/) {
191                $val = $arg_array->[$fmt];
192            }
193            # otherwise, treat the args as a hash
194            else {
195                # Compensate for odd numbers of args
196                push @$arg_array, undef if scalar(@$arg_array) % 2;
197
198                my %h = @$arg_array;
199                $val = $h{$fmt};
200            }
201        }
202    }
203
204    return substr($val||'', 0, 41),
205}
206
207sub clr_screen {
208    $TERM->Tputs('cl', 1, \*STDOUT);
209}
Note: See TracBrowser for help on using the browser.