From 73c1e466d77e5ab4d8c95f5f5a97c007121b8e32 Mon Sep 17 00:00:00 2001 From: Brian Fraser Date: Mon, 30 Jan 2012 17:44:18 -0300 Subject: [PATCH] Several fixes & changes: * qtime and stime computed correctly * Interactive mode and changing groups doesn't fail * Interactive mode no longer uses a file to gather samples. --- bin/pt-diskstats | 304 +++++++++--------- lib/Diskstats.pm | 38 ++- lib/DiskstatsGroupByAll.pm | 50 +-- lib/DiskstatsGroupByDisk.pm | 7 - lib/DiskstatsGroupBySample.pm | 3 +- lib/DiskstatsMenu.pm | 199 ++++++------ t/lib/Diskstats.t | 6 +- t/pt-diskstats/expected/all_int_small.txt | 50 +++ t/pt-diskstats/expected/disk_int_small.txt | 5 + t/pt-diskstats/expected/sample_int_small.txt | 9 + t/pt-diskstats/pt-diskstats.t | 45 ++- t/pt-diskstats/samples/small.txt | 319 +++++++++++++++++++ 12 files changed, 723 insertions(+), 312 deletions(-) create mode 100644 t/pt-diskstats/expected/all_int_small.txt create mode 100644 t/pt-diskstats/expected/disk_int_small.txt create mode 100644 t/pt-diskstats/expected/sample_int_small.txt create mode 100644 t/pt-diskstats/samples/small.txt diff --git a/bin/pt-diskstats b/bin/pt-diskstats index 4741358e..32636377 100755 --- a/bin/pt-diskstats +++ b/bin/pt-diskstats @@ -1602,6 +1602,10 @@ sub new { WRITTEN_KBS MS_SPENT_DOING_IO MS_WEIGHTED + READ_KBS + WRITTEN_KBS + IOS_REQUESTED + IOS_IN_BYTES ) ], _stats_for => {}, @@ -1617,6 +1621,11 @@ sub new { return bless $self, $class; } +sub new_from_object { + my ($self, $class) = @_; + return bless $self, $class; +} + sub active_device { my ( $self, $dev ) = @_; @@ -1633,7 +1642,6 @@ sub clear_active_devices { return $self->{_active_devices} = {}; } - sub automatic_headers { my ($self) = @_; return $self->{automatic_headers}; @@ -1774,11 +1782,13 @@ sub set_force_header { } sub clear_state { - my ($self) = @_; + my ($self, %args) = @_; $self->set_force_header(1); $self->clear_curr_stats(); - $self->clear_prev_stats(); - $self->clear_first_stats(); + if ( $args{force} || !$self->interactive() ) { + $self->clear_first_stats(); + $self->clear_prev_stats(); + } $self->clear_ts(); $self->clear_ordered_devs(); } @@ -1808,6 +1818,11 @@ sub _clear_stats_common { sub clear_curr_stats { my ( $self, @args ) = @_; + + if ( $self->has_stats() ) { + $self->_save_curr_as_prev(); + } + $self->_clear_stats_common( "_stats_for", @args ); } @@ -1882,7 +1897,6 @@ sub _save_curr_as_first { map { $_ => [@{$curr->{$_}}] } keys %$curr }; $self->set_first_ts($self->curr_ts()); - $self->{_first} = undef; } } @@ -1995,7 +2009,7 @@ sub parse_from { elsif ( $args{data} ) { open( my $fh, "<", ref($args{data}) ? $args{data} : \$args{data} ) or die "Couldn't parse data: $OS_ERROR"; - my $lines_read = $self->_parse_from_filehandle( + $lines_read = $self->_parse_from_filehandle( $fh, $args{sample_callback} ); close $fh or warn "Cannot close: $OS_ERROR"; @@ -2161,7 +2175,7 @@ sub _calc_misc_stats { * $delta_for->{ms_spent_doing_io} / ( 1000 * $elapsed * $devs_in_group ); # Highlighting failure: / - my $number_of_ios = $stats->{ios_requested}; + my $number_of_ios = $delta_for->{ios_requested}; my $total_ms_spent_on_io = $delta_for->{ms_spent_reading} + $delta_for->{ms_spent_writing}; @@ -2229,7 +2243,7 @@ sub _mark_if_active { return unless $curr && $first; - if ( first { $curr->[$_] != $first->[$_] } READS..MS_WEIGHTED ) { + if ( first { $curr->[$_] != $first->[$_] } READS..IOS_IN_BYTES ) { $self->set_active_device($dev, 1); return $dev; } @@ -2301,9 +2315,9 @@ sub _calc_deltas { sub force_print_header { my ($self, @args) = @_; my $orig = $self->force_header(); - $self->force_header(1); + $self->set_force_header(1); $self->print_header(@args); - $self->force_header($orig); + $self->set_force_header($orig); return; } @@ -2356,7 +2370,9 @@ sub print_deltas { if ( $self->automatic_headers() && !$self->isa("DiskstatsGroupByAll") ) { - local $self->{force_header} = 1; + $header_method = ref($header_method) + ? $header_method + : "force_print_header"; $self->$header_method( $header, "#ts", "device" ); } } @@ -2443,41 +2459,25 @@ use base qw( Diskstats ); sub group_by { my ($self, %args) = @_; - $self->clear_state(); + $self->clear_state() unless $self->interactive(); - if (!$self->interactive()) { - $self->parse_from( - filehandle => $args{filehandle}, - filename => $args{filename}, - data => $args{data}, - sample_callback => sub { - $self->print_deltas( - header_callback => $args{header_callback}, - rows_callback => $args{rows_callback}, - ); + my $header_callback = $args{header_callback} + || sub { + my ($self, @args) = @_; + $self->print_header(@args); + $self->{_print_header} = 0; + }; + $self->parse_from( + filehandle => $args{filehandle}, + filename => $args{filename}, + data => $args{data}, + sample_callback => sub { + $self->print_deltas( + header_callback => $header_callback, + rows_callback => $args{rows_callback}, + ); }, - ); - } - else { - my $orig = tell $args{filehandle} if $args{filehandle}; - my $header_callback = $args{header_callback} || sub { - my ($self, @args) = @_; - $self->print_header(@args) if $self->{_print_header}; - $self->{_print_header} = 0; - }; - $self->parse_from( - filehandle => $args{filehandle}, - filename => $args{filename}, - data => $args{data}, - sample_callback => sub { - $self->print_deltas( - header_callback => $header_callback, - rows_callback => $args{rows_callback}, - ); - }, - ); - seek $args{filehandle}, $orig, 0 unless $self->prev_ts(); - } + ); return; } @@ -2583,8 +2583,6 @@ sub group_by { }, rows_callback => $args{rows_callback}, ); - - $self->{_iterations} = -1; return; } } @@ -2596,11 +2594,6 @@ sub group_by { ); if ($self->interactive()) { - if ($self->{_iterations} != -1 && defined($original_offset) - && eof($args{filehandle} || $args{data}) ) { - $self->clear_state; - seek( ($args{filehandle} || $args{data}), $original_offset, 0); - } return $lines_read; } @@ -2707,7 +2700,6 @@ sub group_by { data => $args{data}, ); - $self->clear_state() unless $self->interactive(); return; } @@ -2781,7 +2773,7 @@ sub compute_dev { $devs ||= $self->compute_devs_in_group(); return $devs > 1 ? "{" . $devs . "}" - : $self->{ordered_devs}->[0]; + : $self->{_ordered_devs}->[0]; } sub _calc_stats_for_deltas { @@ -2912,11 +2904,8 @@ my %actions = ( "Enter a disk/device pattern: " ), 'q' => sub { return 'last' }, 'p' => sub { - my (@args) = @_; print "Paused - press any key to continue\n"; - pause(@args); - $Diskstats::printed_lines--; - print_header(@args) unless $Diskstats::printed_lines; + pause(@_); return; }, ' ' => \&print_header, @@ -2947,34 +2936,57 @@ sub run_interactive { my ($tmp_fh, $filename, $child_pid, $child_fh); if ( $filename = $args{filename} ) { - open $tmp_fh, "<", $filename - or die "Cannot open $filename: $OS_ERROR"; + if ( ref $filename ) { + $tmp_fh = $filename; + undef $args{filename}; + } + else { + open $tmp_fh, "<", $filename + or die "Cannot open $filename: $OS_ERROR"; + } } else { - ($tmp_fh, $filename) = file_to_use( $o->get('save-samples') ); + $filename = $o->get('save-samples'); - $child_pid = open $child_fh, "|-"; + if ( $filename ) { + unlink $filename; + open my $tmp_fh, "+>", $filename + or die "Cannot open $filename: $OS_ERROR"; + } + + $child_pid = open $child_fh, "-|"; die "Cannot fork: $OS_ERROR" unless defined $child_pid; if ( !$child_pid ) { - + STDOUT->autoflush(1); local $PROGRAM_NAME = "$PROGRAM_NAME (data-gathering daemon)"; - close $tmp_fh; + close $tmp_fh if $tmp_fh; + PTDEBUG && _d("Child is [$PROGRAM_NAME] in ps aux and similar"); + gather_samples( gather_while => sub { getppid() }, samples_to_gather => $o->get('iterations'), filename => $filename, ); - - unlink $filename unless $o->get('save-samples'); + if ( $filename ) { + unlink $filename unless $o->get('save-samples'); + } exit(0); } + else { + PTDEBUG && _d("Forked, child is", $child_pid); + $tmp_fh = $child_fh; + $tmp_fh->blocking(0); + } } - PTDEBUG && _d("Using filename", $filename); + PTDEBUG && _d( + $filename + ? ("Using file", $filename) + : "Not using a file to store samples"); local $SIG{CHLD} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; @@ -2995,15 +3007,22 @@ sub run_interactive { my $header_callback = $o->get("current_group_by_obj") ->can("print_header"); + my $redraw = 0; + if ( $args{filename} ) { + PTDEBUG && _d("Passed a file from the command line,", + "rendering from scratch before looping"); + $redraw = 1; group_by( header_callback => $header_callback, select_obj => $sel, OptionParser => $o, filehandle => $tmp_fh, input => substr(ucfirst($group_by), 0, 1), + redraw_all => $redraw, ); if ( !-t STDOUT && !tied *STDIN ) { + PTDEBUG && _d("Not connected to a tty and not in testing. Quitting"); return 0 } } @@ -3014,25 +3033,30 @@ sub run_interactive { while ($run) { my $refresh_interval = $o->get('refresh-interval'); my $time = scalar Time::HiRes::gettimeofday(); - my $sleep = $refresh_interval - fmod( $time, ($refresh_interval + 0.5) ); + my $sleep = $refresh_interval - fmod( $time, $refresh_interval ); - if ( my $input = read_command_timeout($sel, $sleep ) ) { + if ( my $input = read_command_timeout( $sel, $sleep ) ) { if ($actions{$input}) { + PTDEBUG && _d("Got [$input] and have an action for it"); my $ret = $actions{$input}->( select_obj => $sel, OptionParser => $o, input => $input, filehandle => $tmp_fh, + redraw_all => $redraw, ) || ''; last MAIN_LOOP if $ret eq 'last'; if ( $args{filename} && !grep { $input eq $_ } qw( A S D ), ' ', "\n" ) { + PTDEBUG && _d("Got a file from the command line, redrawing", + "from the beginning after getting an option"); my $obj = $o->get("current_group_by_obj"); - $obj->clear_state(); + $obj->clear_state( force => 1 ); local $obj->{force_header} = 1; group_by( + redraw_all => 1, select_obj => $sel, OptionParser => $o, input => substr(ref($obj), 16, 1), @@ -3049,18 +3073,20 @@ sub run_interactive { } if ( !$args{filename} && $o->get('iterations') && waitpid($child_pid, WNOHANG) != 0 ) { + PTDEBUG && _d("Child quit as expected after", + $o->get("iterations"), + "iterations. Quitting."); $run = 0; } } ReadKeyMini::cooked(); - if ( !$args{filename} && !defined $o->get('iterations') + if ( $child_pid && !$args{filename} && !defined $o->get('iterations') && kill 0, $child_pid ) { - $child_fh->printflush("End\n"); + kill 9, $child_pid; waitpid $child_pid, 0; } - close $tmp_fh or die "Cannot close: $OS_ERROR"; return 0; # Exit status } @@ -3075,28 +3101,30 @@ sub read_command_timeout { sub gather_samples { my (%args) = @_; my $samples = 0; + my $fh; - STDIN->blocking(0); - my $sel = IO::Select->new(\*STDIN); - my $filename = $args{filename}; + if ( my $filename = $args{filename} ) { + open $fh, ">>", $filename + or die "Cannot open $filename for appending: $OS_ERROR"; + } + else { + $fh = \*STDOUT; + } - open my $fh, ">>", $filename - or die "Cannot open $filename for appending: $OS_ERROR"; + $fh->autoflush(1); GATHER_DATA: while ( $args{gather_while}->() ) { - my $time = scalar Time::HiRes::gettimeofday(); - my $sleep = 1 - fmod( $time, 1 ); - if ( read_command_timeout( $sel, $sleep ) ) { - last GATHER_DATA; - } + my $sleep = 1 - fmod( scalar(Time::HiRes::gettimeofday()), 1 ); + Time::HiRes::sleep($sleep); + open my $diskstats_fh, "<", "/proc/diskstats" or die "Cannot open /proc/diskstats: $OS_ERROR"; my @to_print = timestamp(); push @to_print, <$diskstats_fh>; - $fh->printflush(@to_print); + print { $fh } @to_print; close $diskstats_fh or die $OS_ERROR; $samples++; @@ -3131,55 +3159,58 @@ sub group_by { } my ($o, $input) = @args{@required_args}; + my $old_obj = $o->get("current_group_by_obj"); + if ( ref( $o->get("current_group_by_obj") ) ne $input_to_object{$input} ) { $o->set("current_group_by_obj", undef); - $o->set("current_group_by_obj", - $input_to_object{$input}->new( - OptionParser => $o, - interactive => 1, - ) - ); + $o->set( "current_group_by_obj", $input_to_object{$input}->new(OptionParser=>$o, interactive => 1) ); + if ( !$args{redraw_all} ) { + print_header(%args); + } } - seek $args{filehandle}, 0, 0; for my $obj ( $o->get("current_group_by_obj") ) { - if ( $obj->isa("DiskstatsGroupBySample") ) { - $obj->set_interactive(1); + if ( $args{redraw_all} ) { + seek $args{filehandle}, 0, 0; + if ( $obj->isa("DiskstatsGroupBySample") ) { + $obj->set_interactive(1); + } + else { + $obj->set_interactive(0); + } + + my $print_header; + my $header_callback = $args{header_callback} || sub { + my ($self, @args) = @_; + $self->print_header(@args) unless $print_header++ + }; + + $obj->group_by( + filehandle => $args{filehandle}, + header_callback => $header_callback, + ); } - else { - $obj->set_interactive(0); - } - - my $print_header; - my $header_callback = $args{header_callback} || sub { - my ($self, @args) = @_; - $self->print_header(@args) unless $print_header++ - }; - - $obj->group_by( - filehandle => $args{filehandle}, - header_callback => $header_callback, - ); $obj->set_interactive(1); $obj->set_force_header(0); } + } sub help { - my (%args) = @_; - my $obj = $args{OptionParser}->get("current_group_by_obj"); - my $mode = substr ref($obj), 16, 1; - my $column_re = $args{OptionParser}->get('columns-regex'); - my $device_re = $args{OptionParser}->get('devices-regex'); - my $interval = $obj->sample_time() || '(none)'; - my $disp_int = $args{OptionParser}->get('refresh-interval'); - my $inact_disk = $obj->show_inactive() ? 'no' : 'yes'; + my (%args) = @_; + my $obj = $args{OptionParser}->get("current_group_by_obj"); + my $mode = substr ref($obj), 16, 1; + my $column_re = $args{OptionParser}->get('columns-regex'); + my $device_re = $args{OptionParser}->get('devices-regex'); + my $interval = $obj->sample_time() || '(none)'; + my $disp_int = $args{OptionParser}->get('refresh-interval'); + my $inact_disk = $obj->show_inactive() ? 'no' : 'yes'; for my $re ( $column_re, $device_re ) { $re ||= '(none)'; } - my $help = <<"HELP"; + print <<"HELP"; You can control this program by key presses: ------------------- Key ------------------- ---- Current Setting ---- A, D, S) Set the group-by mode $mode @@ -3192,54 +3223,11 @@ sub help { q) Quit the program ------------------- Press any key to continue ----------------------- HELP - print $help; -=begin IGNORE - - my $lines = $help =~ tr/\n//; - while ( $lines-- ) { - $Diskstats::printed_lines--; - print_header(%args) unless $Diskstats::printed_lines; - } -=cut pause(%args); return; } -sub file_to_use { - my ( $filename ) = @_; - - if ( !$filename ) { - PTDEBUG && _d('No explicit filename passed in,', - 'trying to get one from mktemp'); - chomp($filename = `mktemp -t pt-diskstats.$PID.XXXXXXXX`); - } - - if ( $filename ) { - unlink $filename; - open my $fh, "+>", $filename - or die "Cannot open $filename: $OS_ERROR"; - return $fh, $filename; - } - else { - PTDEBUG && _d("mktemp didn't return a filename,", - "trying to use File::Temp"); - local $EVAL_ERROR; - if ( !eval { require File::Temp } ) { - die "Can't call mktemp nor load File::Temp.", - " Install either of those, or pass in an explicit", - " filename through --save-samples."; - } - my $dir = File::Temp::tempdir( CLEANUP => 1 ); - return File::Temp::tempfile( - "pt-diskstats.$PID.XXXXXXXX", - DIR => $dir, - UNLINK => 1, - OPEN => 1, - ); - } -} - sub get_blocking_input { my ($message) = @_; diff --git a/lib/Diskstats.pm b/lib/Diskstats.pm index 7d72677f..8259e811 100644 --- a/lib/Diskstats.pm +++ b/lib/Diskstats.pm @@ -105,6 +105,10 @@ sub new { WRITTEN_KBS MS_SPENT_DOING_IO MS_WEIGHTED + READ_KBS + WRITTEN_KBS + IOS_REQUESTED + IOS_IN_BYTES ) ], _stats_for => {}, @@ -121,6 +125,11 @@ sub new { return bless $self, $class; } +sub new_from_object { + my ($self, $class) = @_; + return bless $self, $class; +} + # The next lot are accessors, plus some convenience functions. sub active_device { @@ -138,7 +147,6 @@ sub clear_active_devices { return $self->{_active_devices} = {}; } - sub automatic_headers { my ($self) = @_; return $self->{automatic_headers}; @@ -284,11 +292,13 @@ sub set_force_header { } sub clear_state { - my ($self) = @_; + my ($self, %args) = @_; $self->set_force_header(1); $self->clear_curr_stats(); - $self->clear_prev_stats(); - $self->clear_first_stats(); + if ( $args{force} || !$self->interactive() ) { + $self->clear_first_stats(); + $self->clear_prev_stats(); + } $self->clear_ts(); $self->clear_ordered_devs(); } @@ -318,6 +328,11 @@ sub _clear_stats_common { sub clear_curr_stats { my ( $self, @args ) = @_; + + if ( $self->has_stats() ) { + $self->_save_curr_as_prev(); + } + $self->_clear_stats_common( "_stats_for", @args ); } @@ -392,7 +407,6 @@ sub _save_curr_as_first { map { $_ => [@{$curr->{$_}}] } keys %$curr }; $self->set_first_ts($self->curr_ts()); - $self->{_first} = undef; } } @@ -537,7 +551,7 @@ sub parse_from { elsif ( $args{data} ) { open( my $fh, "<", ref($args{data}) ? $args{data} : \$args{data} ) or die "Couldn't parse data: $OS_ERROR"; - my $lines_read = $self->_parse_from_filehandle( + $lines_read = $self->_parse_from_filehandle( $fh, $args{sample_callback} ); close $fh or warn "Cannot close: $OS_ERROR"; @@ -730,7 +744,7 @@ sub _calc_misc_stats { * $delta_for->{ms_spent_doing_io} / ( 1000 * $elapsed * $devs_in_group ); # Highlighting failure: / - my $number_of_ios = $stats->{ios_requested}; + my $number_of_ios = $delta_for->{ios_requested}; my $total_ms_spent_on_io = $delta_for->{ms_spent_reading} + $delta_for->{ms_spent_writing}; @@ -814,7 +828,7 @@ sub _mark_if_active { return unless $curr && $first; # read 'any' instead of 'first' - if ( first { $curr->[$_] != $first->[$_] } READS..MS_WEIGHTED ) { + if ( first { $curr->[$_] != $first->[$_] } READS..IOS_IN_BYTES ) { # It's different from the first one. Mark as active and return. $self->set_active_device($dev, 1); return $dev; @@ -890,9 +904,9 @@ sub _calc_deltas { sub force_print_header { my ($self, @args) = @_; my $orig = $self->force_header(); - $self->force_header(1); + $self->set_force_header(1); $self->print_header(@args); - $self->force_header($orig); + $self->set_force_header($orig); return; } @@ -952,7 +966,9 @@ sub print_deltas { if ( $self->automatic_headers() && !$self->isa("DiskstatsGroupByAll") ) { - local $self->{force_header} = 1; + $header_method = ref($header_method) + ? $header_method + : "force_print_header"; $self->$header_method( $header, "#ts", "device" ); } } diff --git a/lib/DiskstatsGroupByAll.pm b/lib/DiskstatsGroupByAll.pm index 57140899..2cd62ca7 100644 --- a/lib/DiskstatsGroupByAll.pm +++ b/lib/DiskstatsGroupByAll.pm @@ -33,41 +33,25 @@ use base qw( Diskstats ); sub group_by { my ($self, %args) = @_; - $self->clear_state(); + $self->clear_state() unless $self->interactive(); - if (!$self->interactive()) { - $self->parse_from( - filehandle => $args{filehandle}, - filename => $args{filename}, - data => $args{data}, - sample_callback => sub { - $self->print_deltas( - header_callback => $args{header_callback}, - rows_callback => $args{rows_callback}, - ); + my $header_callback = $args{header_callback} + || sub { + my ($self, @args) = @_; + $self->print_header(@args); + $self->{_print_header} = 0; + }; + $self->parse_from( + filehandle => $args{filehandle}, + filename => $args{filename}, + data => $args{data}, + sample_callback => sub { + $self->print_deltas( + header_callback => $header_callback, + rows_callback => $args{rows_callback}, + ); }, - ); - } - else { - my $orig = tell $args{filehandle} if $args{filehandle}; - my $header_callback = $args{header_callback} || sub { - my ($self, @args) = @_; - $self->print_header(@args) if $self->{_print_header}; - $self->{_print_header} = 0; - }; - $self->parse_from( - filehandle => $args{filehandle}, - filename => $args{filename}, - data => $args{data}, - sample_callback => sub { - $self->print_deltas( - header_callback => $header_callback, - rows_callback => $args{rows_callback}, - ); - }, - ); - seek $args{filehandle}, $orig, 0 unless $self->prev_ts(); - } + ); return; } diff --git a/lib/DiskstatsGroupByDisk.pm b/lib/DiskstatsGroupByDisk.pm index f825309c..aa54a521 100644 --- a/lib/DiskstatsGroupByDisk.pm +++ b/lib/DiskstatsGroupByDisk.pm @@ -73,8 +73,6 @@ sub group_by { }, rows_callback => $args{rows_callback}, ); - - $self->{_iterations} = -1; return; } } @@ -93,11 +91,6 @@ sub group_by { # where we started, so subsequent attempts (i.e. when # the file has more data) have greater chances of succeeding, # and no data goes unreported. - if ($self->{_iterations} != -1 && defined($original_offset) - && eof($args{filehandle} || $args{data}) ) { - $self->clear_state; - seek( ($args{filehandle} || $args{data}), $original_offset, 0); - } return $lines_read; } diff --git a/lib/DiskstatsGroupBySample.pm b/lib/DiskstatsGroupBySample.pm index 2f594d74..1875fdba 100644 --- a/lib/DiskstatsGroupBySample.pm +++ b/lib/DiskstatsGroupBySample.pm @@ -58,7 +58,6 @@ sub group_by { data => $args{data}, ); - $self->clear_state() unless $self->interactive(); return; } @@ -138,7 +137,7 @@ sub compute_dev { $devs ||= $self->compute_devs_in_group(); return $devs > 1 ? "{" . $devs . "}" - : $self->{ordered_devs}->[0]; + : $self->{_ordered_devs}->[0]; } # Terrible breach of encapsulation, but it'll have to do for the moment. diff --git a/lib/DiskstatsMenu.pm b/lib/DiskstatsMenu.pm index ecfb9710..735d4811 100644 --- a/lib/DiskstatsMenu.pm +++ b/lib/DiskstatsMenu.pm @@ -92,39 +92,63 @@ sub run_interactive { # Here's a big crux of the program. If we have a filename, we don't # need to fork and create a child, just read from it. if ( $filename = $args{filename} ) { - open $tmp_fh, "<", $filename - or die "Cannot open $filename: $OS_ERROR"; + # INTERNAL: For testing. + if ( ref $filename ) { + $tmp_fh = $filename; + undef $args{filename}; + } + else { + open $tmp_fh, "<", $filename + or die "Cannot open $filename: $OS_ERROR"; + } } else { - ($tmp_fh, $filename) = file_to_use( $o->get('save-samples') ); + $filename = $o->get('save-samples'); + + if ( $filename ) { + unlink $filename; + open my $tmp_fh, "+>", $filename + or die "Cannot open $filename: $OS_ERROR"; + } # fork(), but future-proofing it in case we ever need to speak to # the child - $child_pid = open $child_fh, "|-"; + $child_pid = open $child_fh, "-|"; die "Cannot fork: $OS_ERROR" unless defined $child_pid; if ( !$child_pid ) { # Child - + STDOUT->autoflush(1); # Bit of helpful magic: Changes how the program's name is displayed, # so it's easier to track in things like ps. local $PROGRAM_NAME = "$PROGRAM_NAME (data-gathering daemon)"; - close $tmp_fh; + close $tmp_fh if $tmp_fh; + PTDEBUG && _d("Child is [$PROGRAM_NAME] in ps aux and similar"); + gather_samples( gather_while => sub { getppid() }, samples_to_gather => $o->get('iterations'), filename => $filename, ); - - unlink $filename unless $o->get('save-samples'); + if ( $filename ) { + unlink $filename unless $o->get('save-samples'); + } exit(0); } + else { + PTDEBUG && _d("Forked, child is", $child_pid); + $tmp_fh = $child_fh; + $tmp_fh->blocking(0); + } } - PTDEBUG && _d("Using filename", $filename); + PTDEBUG && _d( + $filename + ? ("Using file", $filename) + : "Not using a file to store samples"); # I don't think either of these are needed actually, since piped opens # are supposed to deal with children on their own, but it doesn't hurt. @@ -147,18 +171,25 @@ sub run_interactive { my $header_callback = $o->get("current_group_by_obj") ->can("print_header"); + my $redraw = 0; + if ( $args{filename} ) { + PTDEBUG && _d("Passed a file from the command line,", + "rendering from scratch before looping"); + $redraw = 1; group_by( header_callback => $header_callback, select_obj => $sel, OptionParser => $o, filehandle => $tmp_fh, input => substr(ucfirst($group_by), 0, 1), + redraw_all => $redraw, ); if ( !-t STDOUT && !tied *STDIN ) { # If we were passed down a file but aren't tied to a tty, # -and- STDIN isn't tied (so we aren't in testing mode), # then this is the end of the program. + PTDEBUG && _d("Not connected to a tty and not in testing. Quitting"); return 0 } } @@ -169,15 +200,17 @@ sub run_interactive { while ($run) { my $refresh_interval = $o->get('refresh-interval'); my $time = scalar Time::HiRes::gettimeofday(); - my $sleep = $refresh_interval - fmod( $time, ($refresh_interval + 0.5) ); + my $sleep = $refresh_interval - fmod( $time, $refresh_interval ); - if ( my $input = read_command_timeout($sel, $sleep ) ) { + if ( my $input = read_command_timeout( $sel, $sleep ) ) { if ($actions{$input}) { + PTDEBUG && _d("Got [$input] and have an action for it"); my $ret = $actions{$input}->( select_obj => $sel, OptionParser => $o, input => $input, filehandle => $tmp_fh, + redraw_all => $redraw, ) || ''; last MAIN_LOOP if $ret eq 'last'; @@ -187,11 +220,14 @@ sub run_interactive { if ( $args{filename} && !grep { $input eq $_ } qw( A S D ), ' ', "\n" ) { + PTDEBUG && _d("Got a file from the command line, redrawing", + "from the beginning after getting an option"); my $obj = $o->get("current_group_by_obj"); # Force it to print the header - $obj->clear_state(); + $obj->clear_state( force => 1 ); local $obj->{force_header} = 1; group_by( + redraw_all => 1, select_obj => $sel, OptionParser => $o, input => substr(ref($obj), 16, 1), @@ -217,6 +253,9 @@ sub run_interactive { # When that happens, we are also done. if ( !$args{filename} && $o->get('iterations') && waitpid($child_pid, WNOHANG) != 0 ) { + PTDEBUG && _d("Child quit as expected after", + $o->get("iterations"), + "iterations. Quitting."); $run = 0; } } @@ -224,13 +263,15 @@ sub run_interactive { # If we don't have a filename, the daemon might still be running. # If it is, ask it nicely to end, then wait. - if ( !$args{filename} && !defined $o->get('iterations') + if ( $child_pid && !$args{filename} && !defined $o->get('iterations') && kill 0, $child_pid ) { - $child_fh->printflush("End\n"); + #$child_fh->printflush("End\n"); + # TODO + kill 9, $child_pid; waitpid $child_pid, 0; } - close $tmp_fh or die "Cannot close: $OS_ERROR"; + #close $tmp_fh or die "Cannot close: $OS_ERROR"; return 0; # Exit status } @@ -245,21 +286,23 @@ sub read_command_timeout { sub gather_samples { my (%args) = @_; my $samples = 0; + my $fh; - STDIN->blocking(0); - my $sel = IO::Select->new(\*STDIN); - my $filename = $args{filename}; + if ( my $filename = $args{filename} ) { + open $fh, ">>", $filename + or die "Cannot open $filename for appending: $OS_ERROR"; + } + else { + $fh = \*STDOUT; + } - open my $fh, ">>", $filename - or die "Cannot open $filename for appending: $OS_ERROR"; + $fh->autoflush(1); GATHER_DATA: while ( $args{gather_while}->() ) { - my $time = scalar Time::HiRes::gettimeofday(); - my $sleep = 1 - fmod( $time, 1 ); - if ( read_command_timeout( $sel, $sleep ) ) { - last GATHER_DATA; - } + my $sleep = 1 - fmod( scalar(Time::HiRes::gettimeofday()), 1 ); + Time::HiRes::sleep($sleep); + open my $diskstats_fh, "<", "/proc/diskstats" or die "Cannot open /proc/diskstats: $OS_ERROR"; @@ -268,7 +311,7 @@ sub gather_samples { # Lovely little method from IO::Handle: turns on autoflush, # prints, and then restores the original autoflush state. - $fh->printflush(@to_print); + print { $fh } @to_print; close $diskstats_fh or die $OS_ERROR; $samples++; @@ -303,56 +346,58 @@ sub group_by { } my ($o, $input) = @args{@required_args}; + my $old_obj = $o->get("current_group_by_obj"); + if ( ref( $o->get("current_group_by_obj") ) ne $input_to_object{$input} ) { # Particularly important! Otherwise we would depend on the # object's ->new being smart about discarding unrecognized # values. $o->set("current_group_by_obj", undef); - # This would fail on a stricter constructor, so it probably - # needs fixing. - $o->set("current_group_by_obj", - $input_to_object{$input}->new( - OptionParser => $o, - interactive => 1, - ) - ); + #my $new_obj = $old_obj->new_from_object($input_to_object{$input}); + $o->set( "current_group_by_obj", $input_to_object{$input}->new(OptionParser=>$o, interactive => 1) ); + if ( !$args{redraw_all} ) { + print_header(%args); + } } - seek $args{filehandle}, 0, 0; # Just aliasing this for a bit. for my $obj ( $o->get("current_group_by_obj") ) { - if ( $obj->isa("DiskstatsGroupBySample") ) { - $obj->set_interactive(1); + if ( $args{redraw_all} ) { + seek $args{filehandle}, 0, 0; + if ( $obj->isa("DiskstatsGroupBySample") ) { + $obj->set_interactive(1); + } + else { + $obj->set_interactive(0); + } + + my $print_header; + my $header_callback = $args{header_callback} || sub { + my ($self, @args) = @_; + $self->print_header(@args) unless $print_header++ + }; + + $obj->group_by( + filehandle => $args{filehandle}, + # Only print the header once, as if in interactive. + header_callback => $header_callback, + ); } - else { - $obj->set_interactive(0); - } - - my $print_header; - my $header_callback = $args{header_callback} || sub { - my ($self, @args) = @_; - $self->print_header(@args) unless $print_header++ - }; - - $obj->group_by( - filehandle => $args{filehandle}, - # Only print the header once, as if in interactive. - header_callback => $header_callback, - ); $obj->set_interactive(1); $obj->set_force_header(0); } + } sub help { - my (%args) = @_; - my $obj = $args{OptionParser}->get("current_group_by_obj"); - my $mode = substr ref($obj), 16, 1; - my $column_re = $args{OptionParser}->get('columns-regex'); - my $device_re = $args{OptionParser}->get('devices-regex'); - my $interval = $obj->sample_time() || '(none)'; - my $disp_int = $args{OptionParser}->get('refresh-interval'); - my $inact_disk = $obj->show_inactive() ? 'no' : 'yes'; + my (%args) = @_; + my $obj = $args{OptionParser}->get("current_group_by_obj"); + my $mode = substr ref($obj), 16, 1; + my $column_re = $args{OptionParser}->get('columns-regex'); + my $device_re = $args{OptionParser}->get('devices-regex'); + my $interval = $obj->sample_time() || '(none)'; + my $disp_int = $args{OptionParser}->get('refresh-interval'); + my $inact_disk = $obj->show_inactive() ? 'no' : 'yes'; for my $re ( $column_re, $device_re ) { $re ||= '(none)'; @@ -376,40 +421,6 @@ HELP return; } -sub file_to_use { - my ( $filename ) = @_; - - if ( !$filename ) { - PTDEBUG && _d('No explicit filename passed in,', - 'trying to get one from mktemp'); - chomp($filename = `mktemp -t pt-diskstats.$PID.XXXXXXXX`); - } - - if ( $filename ) { - unlink $filename; - open my $fh, "+>", $filename - or die "Cannot open $filename: $OS_ERROR"; - return $fh, $filename; - } - else { - PTDEBUG && _d("mktemp didn't return a filename,", - "trying to use File::Temp"); - local $EVAL_ERROR; - if ( !eval { require File::Temp } ) { - die "Can't call mktemp nor load File::Temp.", - " Install either of those, or pass in an explicit", - " filename through --save-samples."; - } - my $dir = File::Temp::tempdir( CLEANUP => 1 ); - return File::Temp::tempfile( - "pt-diskstats.$PID.XXXXXXXX", - DIR => $dir, - UNLINK => 1, - OPEN => 1, - ); - } -} - sub get_blocking_input { my ($message) = @_; diff --git a/t/lib/Diskstats.t b/t/lib/Diskstats.t index 7a9e19fe..b5548435 100644 --- a/t/lib/Diskstats.t +++ b/t/lib/Diskstats.t @@ -379,6 +379,8 @@ is_deeply( writes_merged => 270, written_kbs => 1229, written_sectors => 2458, + ios_in_bytes => 1262080, + ios_requested => 57, }, "_calc_delta_for works" ); @@ -441,9 +443,9 @@ is_deeply( { busy => '0.6', line_ts => ' 0.0', - qtime => 0, + qtime => '0.929824561403509', s_spent_doing_io => '0.053', - stime => 0, + stime => '0.210526315789474', }, "_calc_misc_stats works" ); diff --git a/t/pt-diskstats/expected/all_int_small.txt b/t/pt-diskstats/expected/all_int_small.txt new file mode 100644 index 00000000..a8953328 --- /dev/null +++ b/t/pt-diskstats/expected/all_int_small.txt @@ -0,0 +1,50 @@ + #ts device qtime stime + 1.0 sda 12.5 0.2 + 1.0 sdb 0.7 0.7 + 1.0 dm-0 5.1 1.5 + 1.0 dm-1 12.9 0.2 + #ts device qtime stime + 2.0 sda 0.0 0.0 + 2.0 sdb 0.0 0.0 + 2.0 dm-0 0.0 0.0 + 2.0 dm-1 0.0 0.0 + #ts device qtime stime + 2.8 sda 0.0 0.0 + 2.8 sdb 0.0 0.0 + 2.8 dm-0 0.0 0.0 + 2.8 dm-1 0.0 0.0 + #ts device qtime stime + 3.5 sda 0.0 0.0 + 3.5 sdb 0.0 0.0 + 3.5 dm-0 0.0 0.0 + 3.5 dm-1 0.0 0.0 + #ts device qtime stime + 4.5 sda 0.7 0.7 + 4.5 sdb 0.0 0.0 + 4.5 dm-0 0.0 0.0 + 4.5 dm-1 0.2 0.2 + #ts device qtime stime + 6.2 sda 0.8 0.4 + 6.2 sdb 0.0 1.0 + 6.2 dm-0 1.0 0.1 + 6.2 dm-1 0.0 0.0 + #ts device qtime stime + 6.4 sda 0.0 0.0 + 6.4 sdb 1.0 0.5 + 6.4 dm-0 0.0 0.0 + 6.4 dm-1 0.0 0.0 + #ts device qtime stime + 7.4 sda 0.0 0.0 + 7.4 sdb 0.0 0.0 + 7.4 dm-0 0.2 0.2 + 7.4 dm-1 0.0 0.0 + #ts device qtime stime + 8.4 sda 29.1 0.7 + 8.4 sdb 0.9 0.5 + 8.4 dm-0 0.0 0.0 + 8.4 dm-1 23.2 0.5 + #ts device qtime stime + 9.4 sda 0.0 0.0 + 9.4 sdb 0.0 0.0 + 9.4 dm-0 0.0 0.0 + 9.4 dm-1 0.0 0.0 diff --git a/t/pt-diskstats/expected/disk_int_small.txt b/t/pt-diskstats/expected/disk_int_small.txt new file mode 100644 index 00000000..71b2c771 --- /dev/null +++ b/t/pt-diskstats/expected/disk_int_small.txt @@ -0,0 +1,5 @@ + #ts device qtime stime + {10} sda 22.7 0.6 + {10} sdb 0.8 0.6 + {10} dm-0 2.6 0.7 + {10} dm-1 21.1 0.4 diff --git a/t/pt-diskstats/expected/sample_int_small.txt b/t/pt-diskstats/expected/sample_int_small.txt new file mode 100644 index 00000000..8a58846f --- /dev/null +++ b/t/pt-diskstats/expected/sample_int_small.txt @@ -0,0 +1,9 @@ + #ts device qtime stime + 1.0 {4} 11.9 0.3 + 2.0 {4} 0.0 0.0 + 3.5 {4} 0.0 0.0 + 4.5 {4} 0.5 0.5 + 6.2 {4} 0.8 0.3 + 7.4 {4} 0.2 0.2 + 8.4 {4} 25.1 0.6 + 9.4 {4} 0.0 0.0 diff --git a/t/pt-diskstats/pt-diskstats.t b/t/pt-diskstats/pt-diskstats.t index 1a1d4d36..6d83bdd6 100644 --- a/t/pt-diskstats/pt-diskstats.t +++ b/t/pt-diskstats/pt-diskstats.t @@ -9,7 +9,7 @@ BEGIN { use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); -use Test::More tests => 22; +use Test::More tests => 25; use File::Temp (); @@ -22,7 +22,9 @@ require "$trunk/bin/pt-diskstats"; # so that we can fake sending pt-diskstats menu commands via STDIN. # All we do is send 'q', the command to quit. See the note in the bottom # of this file about *DATA. Please don't close it. +my $called_seek_on_handle = 0; { +$TestInteractive::first = 1; sub TestInteractive::TIEHANDLE { my ($class, @cmds) = @_; push @cmds, "q"; @@ -36,9 +38,32 @@ sub TestInteractive::FILENO { sub TestInteractive::READLINE { my ($self) = @_; my $cmd = shift @$self; - print $cmd if $cmd =~ /\n/; + return unless $cmd; + print $cmd if $cmd =~ /\n/ && !-t STDOUT; + if ($cmd =~ /^TS/) { + if ( $TestInteractive::first ) { + $TestInteractive::first = 0; + } + else { + splice @$self, 1, 0, (undef) x 50; + } + } return $cmd; } + +sub TestInteractive::EOF { + my ($self) = @_; + return @$self ? undef : 1; +} + +sub TestInteractive::CLOSE { 1 } + +sub TestInteractive::TELL {} + +sub TestInteractive::SEEK { + $called_seek_on_handle++; +} + } sub test_diskstats_file { @@ -50,6 +75,13 @@ sub test_diskstats_file { ( my $x = $_ ) =~ s/\n/\\n/g; $x } @commands; + my @options = $args{options} + ? @{ $args{options} } + : ( + '--show-inactive', + '--no-automatic-headers', + '--columns-regex','cnc|rt|mb|busy|prg', + ); die "$file does not exist" unless -f $file; foreach my $groupby ( qw(all disk sample) ) { ok( @@ -57,10 +89,8 @@ sub test_diskstats_file { sub { tie local *STDIN, TestInteractive => @commands; pt_diskstats::main( - '--show-inactive', - '--no-automatic-headers', + @options, '--group-by', $groupby, - '--columns-regex','cnc|rt|mb|busy|prg', $file); }, "t/pt-diskstats/expected/${groupby}_int_$args{file}", @@ -85,6 +115,11 @@ test_diskstats_file( commands => [ "i", "/", "cciss\n", "q" ] ); +test_diskstats_file( + file => "small.txt", + options => [ '--no-automatic-headers', '--columns-regex','time', ], +); + # ########################################################################### # --save-samples and --iterations # ########################################################################### diff --git a/t/pt-diskstats/samples/small.txt b/t/pt-diskstats/samples/small.txt new file mode 100644 index 00000000..88ab0be2 --- /dev/null +++ b/t/pt-diskstats/samples/small.txt @@ -0,0 +1,319 @@ +TS 1327510177.628000 2012-01-25T10:49:37 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745383 846485907 11060948316 2055732382 0 545004107 197928245 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679759 3054471032 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827300 3707258504 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339337 483516351 5022900400 109665845 0 699286938 2601866158 + 8 17 sdb1 155688199 3589800804 627862340 727932176 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403807 0 591870544 1142786100 0 43867855 1164431937 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423519 0 3115388152 4250610633 0 349314969 2030031267 +TS 1327510178.635000 2012-01-25T10:49:38 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745448 846485919 11060948932 2055733196 0 545004122 197929059 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679759 3054471032 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827377 3707259120 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339340 483516367 5022900552 109665847 0 699286940 2601866160 + 8 17 sdb1 155688199 3589800804 627862359 727932328 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403817 0 591870624 1142786151 0 43867870 1164431988 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423586 0 3115388688 4250611498 0 349314984 2030032132 +TS 1327510179.669000 2012-01-25T10:49:39 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745448 846485919 11060948932 2055733196 0 545004122 197929059 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679759 3054471032 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827377 3707259120 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339340 483516367 5022900552 109665847 0 699286940 2601866160 + 8 17 sdb1 155688199 3589800804 627862359 727932328 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403817 0 591870624 1142786151 0 43867870 1164431988 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423586 0 3115388688 4250611498 0 349314984 2030032132 +TS 1327510180.4705000 2012-01-25T10:49:40 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745448 846485919 11060948932 2055733196 0 545004122 197929059 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679759 3054471032 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827377 3707259120 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339340 483516367 5022900552 109665847 0 699286940 2601866160 + 8 17 sdb1 155688199 3589800804 627862359 727932328 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403817 0 591870624 1142786151 0 43867870 1164431988 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423586 0 3115388688 4250611498 0 349314984 2030032132 +TS 1327510181.1748000 2012-01-25T10:49:41 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745448 846485919 11060948932 2055733196 0 545004122 197929059 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679759 3054471032 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827377 3707259120 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339340 483516367 5022900552 109665847 0 699286940 2601866160 + 8 17 sdb1 155688199 3589800804 627862359 727932328 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403817 0 591870624 1142786151 0 43867870 1164431988 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423586 0 3115388688 4250611498 0 349314984 2030032132 +TS 1327510182.1766000 2012-01-25T10:49:42 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745454 846485950 11060949228 2055733200 0 545004126 197929063 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679792 3054471296 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827381 3707259152 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339340 483516367 5022900552 109665847 0 699286940 2601866160 + 8 17 sdb1 155688199 3589800804 627862359 727932328 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403817 0 591870624 1142786151 0 43867870 1164431988 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423590 0 3115388720 4250611499 0 349314985 2030032133 +TS 1327510183.843000 2012-01-25T10:49:43 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745472 846486004 11060949804 2055733214 0 545004133 197929077 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679857 3054471816 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827388 3707259208 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339341 483516380 5022900576 109665847 1 699286941 2601866161 + 8 17 sdb1 155688199 3589800804 627862374 727932448 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403824 0 591870680 1142786158 0 43867871 1164431995 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423590 0 3115388720 4250611499 0 349314985 2030032133 +TS 1327510183.999864000 2012-01-25T10:49:43 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745472 846486004 11060949804 2055733214 0 545004133 197929077 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679857 3054471816 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827388 3707259208 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339343 483516380 5022900680 109665849 0 699286942 2601866162 + 8 17 sdb1 155688199 3589800804 627862375 727932456 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403824 0 591870680 1142786158 0 43867871 1164431995 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423590 0 3115388720 4250611499 0 349314985 2030032133 +TS 1327510184.999903000 2012-01-25T10:49:44 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958345 9208182 2671393219 2437232103 534745476 846486006 11060949852 2055733214 0 545004133 197929077 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679857 3054471816 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211345 1915333340 462827394 3707259256 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339343 483516380 5022900680 109665849 0 699286942 2601866162 + 8 17 sdb1 155688199 3589800804 627862375 727932456 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403830 0 591870728 1142786159 0 43867872 1164431996 + 253 1 dm-1 67512604 0 1473349498 2074313873 389423590 0 3115388720 4250611499 0 349314985 2030032133 +TS 1327510185.999958000 2012-01-25T10:49:45 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958350 9208182 2671393259 2437232181 534745670 846486098 11060952148 2055738921 0 545004273 197934862 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679857 3054471816 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211350 1915333380 462827681 3707261552 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339353 483516406 5022900968 109665858 0 699286947 2601866171 + 8 17 sdb1 155688199 3589800804 627862411 727932744 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403830 0 591870728 1142786159 0 43867872 1164431996 + 253 1 dm-1 67512609 0 1473349538 2074313951 389423877 0 3115391016 4250618205 0 349315125 2030038917 +TS 1327510186.999984000 2012-01-25T10:49:46 + 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 + 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 + 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 + 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 + 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 + 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 + 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 + 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 + 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 + 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 + 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 + 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 + 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 + 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 + 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 + 8 0 sda 85958350 9208182 2671393259 2437232181 534745670 846486098 11060952148 2055738921 0 545004273 197934862 + 8 1 sda1 5024 46400 6662 13324 + 8 2 sda2 23671288 753256530 918679857 3054471816 + 8 3 sda3 306655 2443289 529697 4237576 + 8 4 sda4 10 20 0 0 + 8 5 sda5 71211350 1915333380 462827681 3707261552 + 8 16 sdb 145329387 10397919 3590114436 2492237855 144339353 483516406 5022900968 109665858 0 699286947 2601866171 + 8 17 sdb1 155688199 3589800804 627862411 727932744 + 2 0 fd0 0 0 0 0 0 0 0 0 0 0 0 + 9 0 md0 0 0 0 0 0 0 0 0 0 0 0 + 253 0 dm-0 3698313 0 441982922 21577627 73403830 0 591870728 1142786159 0 43867872 1164431996 + 253 1 dm-1 67512609 0 1473349538 2074313951 389423877 0 3115391016 4250618205 0 349315125 2030038917