contrib/mpoolparse/poolsize.pl
34e79a80
 #!/usr/bin/perl
 
 use strict;
 use warnings;
 
f4c37854
 use constant PERM => 0;
 use constant TEMP => 1;
 use constant MAXA => 2;
 use constant REAS => 3;
 
 use constant TAKE => PERM;
 
 # usage poolsize.pl < mpool_allocfile
34e79a80
 
 my $sizeof_void_ptr;
 my $overhead = 0;
 
 my %ptrs;
 my %sizes;
f4c37854
 my %maxes;
34e79a80
 
 my $maxsz = 0;
 
f4c37854
 print STDERR "Parsing allocations...\n";
34e79a80
 while(<>) {
     if(/malloc @(0x[0-9a-z]+) size (\d+) \((.*)\)/) {
 	die "ptr $1 re-malloc" if defined $ptrs{$1};
 	$ptrs{$1} = $2;
f4c37854
 	$sizes{$ptrs{$1}} = [0, 0, 0, 'UNUSED'] unless defined $sizes{$ptrs{$1}};
 	$maxes{$ptrs{$1}} = [0, 0] unless defined $maxes{$ptrs{$1}};
 	$maxes{$ptrs{$1}}[0]++;
 	$maxes{$ptrs{$1}}[1] = $maxes{$ptrs{$1}}[0] unless $maxes{$ptrs{$1}}[1] >= $maxes{$ptrs{$1}}[0];
34e79a80
 	$maxsz = $2 unless $maxsz >= $2;
 	$overhead++ if $3 eq 'new map';
 	next;
     }
     if(/free @(0x[0-9a-z]+)/) {
 	die "ptr $1 invalid free" unless defined $ptrs{$1};
f4c37854
 	$sizes{$ptrs{$1}}[TEMP]++;
 	$maxes{$ptrs{$1}}[0]--;
34e79a80
 	delete $ptrs{$1};
 	next;
     }
     if(/Map created @.*voidptr=(\d+)/) {
 	$sizeof_void_ptr = $1;
 	next;
     }
     chomp;
     print STDERR "warning bogus line:\n$_\n";
 }
 
 $overhead *= $sizeof_void_ptr;
f4c37854
 print STDERR "Parsing complete (size overhead = $overhead)\n";
34e79a80
 
f4c37854
 $sizes{$ptrs{$_}}[PERM]++ foreach (keys %ptrs);
 undef %ptrs;
 
 $sizes{$_}[MAXA] = $maxes{$_}[1] foreach (keys %maxes);
 undef %maxes;
34e79a80
 
 $maxsz |= $maxsz>>16;
 $maxsz |= $maxsz>>8;
 $maxsz |= $maxsz>>4;
 $maxsz |= $maxsz>>2;
 $maxsz |= $maxsz>>1;
 $maxsz++;
 
 while($maxsz) {
f4c37854
     my $nextsz = $maxsz>>1;
34e79a80
     if(defined $sizes{$maxsz}) {
f4c37854
 	$sizes{$maxsz}[REAS] = 'POW2';
34e79a80
     } else {
f4c37854
 	$sizes{$maxsz} = [0, 0, 0, 'POW2'];
34e79a80
     }
f4c37854
     my $nextpow2 = $nextsz;
     while(1) {
 	my $refsz = $maxsz;
 	my @group;
 	foreach (sort { $b <=> $a } keys %sizes) {
 	    next unless $_ > $nextpow2;
 	    next unless $_ <= $maxsz;
 	    next unless ($sizes{$_}[TAKE] > 0 || $_ == $maxsz);
 	    $nextsz = $_;
 	    last unless ($refsz - $_) * $sizes{$_}[TAKE] <= $overhead;
 	    $refsz = $_;
 	    push @group, $_;
 	}
 	while($#group >= 23) {
 	    my $items = $#group / 2;
 	    $nextsz = $group[$items + 1];
 	    @group = @group[0..$items];
 	}
 	print STDERR "Processing group $maxsz -> $nextsz (count ".($#group + 1).")\n";
 	my @topscore; # 0 => score | 1 => used bits | origbits
 	for(my $origbits = 0; $origbits < 1<<$#group ; $origbits++) {
 	    my $bits = $origbits;
 	    my $bitcnt = 0;
 	    my $score = $overhead;
 	    my $grp_size = $maxsz;
34e79a80
 
f4c37854
 	    printf STDERR "%3i%%\r", $origbits * 100 / (1<<$#group) unless ($origbits & 1);
 	    for (my $i = 1; $i<= $#group; $i++) {
 		if($bits & 1) {
 		    $score +=  $overhead + $sizes{$group[$i]}[TAKE] * $group[$i];
 		    $bitcnt++;
 		    $grp_size = $group[$i];
 		} else {
 		    $score += $sizes{$group[$i]}[TAKE] * $grp_size;
 		}
 		$bits>>=1;
 	    }
 	    if(!defined $topscore[0] || $score < $topscore[0] || ($score == $topscore[0] && $bitcnt > $topscore[1])) {
 		@topscore = ($score, $bitcnt, $origbits);
 	    }
34e79a80
 	}
f4c37854
 	my $bits = ($topscore[2]<<1) | 1;
 	for (my $i = 0; $i<=$#group; $i++) {
 	    if ($bits & 1) {
 		$sizes{$group[$i]}[REAS] = "USE";
 	    } else {
 		$sizes{$group[$i]}[REAS] = "GROUP";
 	    }
 	    $bits>>=1;
 	}
 	last unless $nextsz < $maxsz;
 	$maxsz = $nextsz;
34e79a80
     }
f4c37854
     $maxsz = $nextpow2;
34e79a80
 }
 
f4c37854
 print "/* SIZE        PERM    TEMP     MAX    ACT! */\n";
34e79a80
 foreach (sort { $a <=> $b } keys %sizes) {
f4c37854
     printf "%7u, /* %7u %7u %7u %8s */\n", $_, $sizes{$_}[PERM], $sizes{$_}[TEMP], $sizes{$_}[MAXA], $sizes{$_}[REAS];
34e79a80
 }