#!/usr/bin/perl

# track-down-leaks.pl

use strict;
use warnings;

use FindBin qw( $Bin );
use Number::Format;

my ( %pid, %action, %last_pid, %leak_action ) = ();

die "$0 /path/to/logs.." unless @ARGV;
my $f = shift @ARGV;
my $n = Number::Format->new( thousands_sep => '.', decimal_point => ',' );

open my $fh, "<", $f or die "Cannot open '$f' for read! $@";
while( my $line = <$fh> ) {
    chomp $line;
    if ( $line =~ /^\[debug\] ([^:]+): Memory: from \d+(?:.\d+)?[KMG]? \((\d+)\) to \d+(?:.\d+)?[KMG]? \((\d+)\) diff \d+(?:.\d+)?[KMG]? \((\d+)\) \[pid=(\d+)\]/ ) {
        my ( $action, $before, $after, $diff, $pid ) = ( $1, $2, $3, $4, $5 );
        $pid{ $pid } += $diff;
        $action{ $action } += $diff;
        
        if( defined $last_pid{ $pid } && $last_pid{ $pid }->{ before } < $before ) {
            my $leak = $before - $last_pid{ $pid }->{ before };
            print "Leak in ". $last_pid{ $pid }->{ action }. " .. gestartet bei ". $n->format_bytes( $last_pid{ $pid }->{ before } ) . " und geendet bei ". $n->format_bytes( $last_pid{ $pid }->{ after } ). " .. nächster Start der PID ($pid) bei ". $n->format_bytes( $before ). "\n\t->LEAK ". $n->format_bytes( $leak ) . "\n";
            $leak_action{ $last_pid{ $pid }->{ action } } += $leak;
        }
        $last_pid{ $pid } = {
            before => $before,
            after  => $after,
            action => $action
        };
    }
    else {
        #print "ERR '$line'\n";
    }
    #print "ACTION $action, $before -> $after ($diff) for $pid\n";
}
close $fh;

print "\n\n";
print join( "\n", map {
    sprintf( '%40s : %5s', $_, $n->format_bytes( $leak_action{ $_ } ) );
} sort {
    return $leak_action{ $b } <=> $leak_action{ $a }
} keys %leak_action );
print "\n\n\n";

1;

