Advertisement
tangent

Summarize reads and writes in dtruss output

Sep 3rd, 2016
372
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.64 KB | None | 0 0
  1. #!/usr/bin/env perl -w
  2. ########################################################################
  3. # sum-io - Given one or more files containing dtruss output and a
  4. #          pattern matching the file name(s) you are interested in,
  5. #          report the number of bytes written to and read from the
  6. #          matched file(s) according to dtruss.
  7. #
  8. # To collect suitable output, say something like this:
  9. #
  10. #    $ sudo dtruss -p $(pgrep TargetProgram) 2>&1 | tee results
  11. #
  12. # Hit Ctrl-C when you've collected sufficient results.  (The tee(1) lets
  13. # you monitor TargetProgram to see when it stops issuing interesting
  14. # syscalls.)  Then run this script on the results file:
  15. #
  16. #    $ sum-io file_re results
  17. #
  18. # The file_re argument can be any Perl regex.
  19. #
  20. # Created 2016.09.03 by Warren Young
  21. #
  22. # LICENSE: https://creativecommons.org/licenses/by-sa/3.0/
  23. ########################################################################
  24.  
  25. use File::Basename;
  26. use List::MoreUtils qw(uniq);
  27. use Number::Format qw(format_bytes);
  28.  
  29. my ($file_re, @dtruss_results) = @ARGV;
  30. die "usage: $0 <filename-regex> <dtruss-results> [more-results...]\n\n"
  31.         unless length($file_re) && @dtruss_results;
  32.  
  33. my (%read, %written, $target_fd, $target_fn) = (0, 0);
  34. for my $results (@dtruss_results) {
  35.     open my $rf, '<', $results
  36.             or die "Cannot read dtruss result file $results: $!\n";
  37.  
  38.     while (<$rf>) {
  39.         my ($sc, $path, $ret) = /^(\w+)\((".*\\0")?.*= (\d+)/;
  40.         next unless length($sc) && length($ret);
  41.  
  42.         if ($sc eq 'open' && /$file_re/) {
  43.             # Save the return value of open(2) as the target FD.  The
  44.             # base conversion is necessary because dtruss prints syscall
  45.             # results as dec but syscall integer *args* as hex.  Grrr.
  46.             $target_fd = sprintf("0x%X", int($ret));
  47.             $target_fn = basename(substr $path, 1, -3);
  48.         }
  49.         elsif ($target_fd) {
  50.             # Does this look like a syscall involving the target file?
  51.             my ($call_fd) = /^\w+\((0x[0-9A-F]+)/;
  52.             if ($call_fd && $call_fd eq $target_fd) {
  53.                 if ($sc eq 'close') {
  54.                     # The target file is closed now.  Forget it.
  55.                     undef $target_fd;
  56.                     undef $target_fn;
  57.                 }
  58.                 elsif ($sc =~ /read/) {
  59.                     $read{$target_fn} += $ret;
  60.                 }
  61.                 elsif ($sc =~ /write/) {
  62.                     $written{$target_fn} += $ret;
  63.                 }
  64.                 # else, syscall is uninteresting
  65.             }
  66.         }
  67.         # else, haven't found the open(2) call for the target file yet
  68.     }
  69.  
  70.     close $rf;
  71. }
  72.  
  73. for my $f (uniq(sort(keys %read, keys %written))) {
  74.     my ($r, $w) = ($read{$f}, $written{$f});
  75.     if ($r or $w) {
  76.         print "Data I/O for file $f:\n";
  77.         print "    ", format_bytes($read{$f}), " read\n" if $r;
  78.         print "    ", format_bytes($written{$f}), " written\n" if $w;
  79.     }
  80. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement