Changeset 2d9e75d for memlog_analyze
- Timestamp:
- 07/22/15 14:18:06 (9 years ago)
- Branches:
- master
- Children:
- 96927c5
- Parents:
- 09f3093 (diff), 3c9fc94 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Hal Finkel <hfinkel@…> (07/22/15 14:18:06)
- git-committer:
- Hal Finkel <hfinkel@…> (07/22/15 14:18:06)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
memlog_analyze
r09f3093 r2d9e75d 42 42 use strict; 43 43 use File::Basename; 44 use File::Path qw(make_path); 45 use Getopt::Long; 46 47 my $find_leaks = 0; 48 my $print_raw_proc_name = 0; 49 my $quiet = 0; 50 my $help = 0; 51 52 sub print_usage($) { 53 my $ec = $_[0]; 54 my $usage = <<EOM; 55 Usage: $0 [options] <memlog file or glob> [<output directory>] 56 options: 57 --leaks 58 Provide information on leaks instead of peak usage 59 --print-symbol-names 60 Include symbol names and offsets in the output 61 --quiet or -q 62 Don't print status messages while running 63 EOM 64 65 print $usage; 66 exit($ec); 67 } 68 69 GetOptions("help|h|?" => \$help, 70 "leaks" => \$find_leaks, 71 "print-symbol-names" => \$print_raw_proc_name, 72 "quiet|q" => \$quiet) 73 or print_usage(1); 74 75 if ($help) { 76 print_usage(0); 77 } 78 79 if (scalar(@ARGV) > 2) { 80 print_usage(2); 81 } 44 82 45 83 my $memlog_fn = $ARGV[0]; 46 84 my $out_dir = $ARGV[1] || '.'; 47 85 48 m y $print_raw_proc_name = 0;86 make_path($out_dir); 49 87 50 88 if (! -f $memlog_fn) { 51 print "Usage: $0 <memlog file> [<output directory>]\n"; 52 exit 1; 53 } 89 my @pot_fns = glob($memlog_fn); 90 if (scalar(@pot_fns)) { 91 if (!$quiet) { 92 print "Searching all files matching '$memlog_fn'\n"; 93 } 94 95 my $pot_max_rss = 0; 96 my $pos_max_rss_fn; 97 foreach my $pot_fn (@pot_fns) { 98 my $last_line = `tail -n 1 '$pot_fn'`; 99 chomp($last_line); 100 101 my @parts = split(/\t/, $last_line); 102 103 my $op = shift(@parts); 104 my $state = shift(@parts); 105 106 my ($time, $then_max_rss, $tid, $then_arena, $then_mmap) = 107 split(/\s+/, $state); 108 if ($pot_max_rss < $then_max_rss) { 109 $pot_max_rss = $then_max_rss; 110 $pos_max_rss_fn = $pot_fn; 111 } 112 } 113 114 if (defined $pos_max_rss_fn) { 115 $memlog_fn = $pos_max_rss_fn; 116 goto have_memlog_fn; 117 } 118 } 119 120 print_usage(1); 121 } 122 have_memlog_fn: 54 123 55 124 # The version of addr2line and friends that you use can make a big difference, … … 66 135 # The first step is to determine the high-water mark. 67 136 my $max_rss = 0; 137 my $arena = 0; 138 my $mmap = 0; 68 139 foreach my $line (<MEMLOG>) { 69 140 chomp($line); … … 73 144 my $state = shift(@parts); 74 145 75 my ($time, $then_max_rss, $tid) = split(/\s+/, $state); 146 my ($time, $then_max_rss, $tid, $then_arena, $then_mmap) = 147 split(/\s+/, $state); 76 148 if ($max_rss < $then_max_rss) { 77 149 $max_rss = $then_max_rss; 150 $arena = $then_arena; 151 $mmap = $then_mmap; 78 152 } 79 153 } … … 83 157 # Scan the log for malloc/free pairings. We're interested only in active 84 158 # allocations at the time when the rss reaches the final maxrss. 85 my $max_rss_time = 0; 159 # If we're finding leaks, then go to the very end. 160 my $active_alloc_time = 0; 86 161 my %malloc_lines; 87 162 foreach my $line (<MEMLOG>) { … … 102 177 } 103 178 104 # If we've reached the max rss, we've seen all we need to see. 105 my ($time, $then_max_rss, $tid) = split(/\s+/, $state); 106 $max_rss_time = $time; 107 if ($then_max_rss == $max_rss) { 108 last; 179 my ($time, $then_max_rss, $tid, $then_arena, $then_mmap) = 180 split(/\s+/, $state); 181 $active_alloc_time = $time; 182 183 if (!$find_leaks) { 184 # If we've reached the max rss, we've seen all we need to see. 185 if ($then_max_rss == $max_rss) { 186 last; 187 } 109 188 } 110 189 } … … 114 193 # Convert maxrss, currently in KB, to bytes. 115 194 $max_rss *= 1024; 195 if (defined $arena) { 196 $arena *= 1024; 197 } 198 if (defined $mmap) { 199 $mmap *= 1024; 200 } 116 201 117 202 my $total_size = 0; … … 130 215 131 216 my ($size, $ptr) = ($op =~ /^M: (\d+) 0x(\w+)/); 132 my ($time, $then_max_rss, $tid) = split(/\s+/, $state); 217 my ($time, $then_max_rss, $tid, $then_arena, $then_mmap) = 218 split(/\s+/, $state); 133 219 134 220 $total_size += $size; … … 192 278 my $pdf_fn = "$out_dir/" . basename($memlog_fn) . ".pdf"; 193 279 280 if (!$quiet) { 281 print "Creating $txt_fn\n"; 282 } 283 194 284 open(TXT, ">$txt_fn") || die "Can't open $txt_fn: $!"; 285 286 if (!$quiet) { 287 print "Creating $dot_fn\n"; 288 } 289 195 290 open(DOT, ">$dot_fn") || die "Can't open $dot_fn: $!"; 196 291 … … 208 303 } 209 304 305 sub format_bytes_or_unk($) { 306 my $b = $_[0]; 307 return defined($b) ? format_bytes($b) : "(unknown)"; 308 } 309 210 310 print DOT ("digraph \"memlog\" {\n"); 211 311 print DOT ("size=\"8,11\";\n"); 212 312 print DOT ("node [width=0.375,height=0.25];\n"); 213 313 214 printf DOT ("Legend [shape=box, fontsize=100, shape=oval," . 215 "label=\"Total: %s active at maxrss = %s after %s s\"];\n", 216 format_bytes($total_size), format_bytes($max_rss), $max_rss_time); 217 218 printf TXT ("memlog: Total: %s active at maxrss = %s after %s s\n\n", 219 format_bytes($total_size), format_bytes($max_rss), $max_rss_time); 314 my $find_type = $find_leaks ? " (leaks)" : ""; 315 print DOT "subgraph cluster_key {\n"; 316 print DOT "\trank=min;\n"; 317 print DOT "\tlabel=\"memlog\";\n"; 318 print DOT "\tfontsize=100;\n"; 319 print DOT "\trankdir=UR;\n"; 320 printf DOT ("Legend [shape=box, fontsize=100, shape=plaintext," . 321 "label=\"Total: %s active$find_type at maxrss = %s after %s s\\narena: %s\\nmmap: %s\"];\n", 322 format_bytes($total_size), format_bytes($max_rss), 323 $active_alloc_time, format_bytes_or_unk($arena), 324 format_bytes_or_unk($mmap)); 325 print DOT "}\n"; 326 327 printf TXT ("memlog: Total: %s active$find_type at maxrss = %s after %s s\n\tarena: %s\tmmap: %s\n\n", 328 format_bytes($total_size), format_bytes($max_rss), 329 $active_alloc_time, format_bytes_or_unk($arena), 330 format_bytes_or_unk($mmap)); 220 331 221 332 my %cached_names; … … 277 388 $ret .= $func . '\n'; 278 389 279 if ($loc !~ /^ \?/) {390 if ($loc !~ /^[:?]/) { 280 391 $ret .= $loc . '\n'; 281 392 } … … 395 506 close(DOT); 396 507 508 if (!$quiet) { 509 print "Creating $ps_fn\n"; 510 } 511 397 512 system("dot -Tps2 < '$dot_fn' > '$ps_fn'"); 513 514 if (!$quiet) { 515 print "Creating $pdf_fn\n"; 516 } 517 398 518 system("ps2pdf '$ps_fn' '$pdf_fn'"); 399 519
Note: See TracChangeset
for help on using the changeset viewer.