user1164453
user1164453

Reputation: 27

Perl subroutine running more slowly with each successive call

I have a strange problem where I call the same subroutine several times in succession, processing the same data, and my code takes successively longer with each call. My program is doing some matrix mathematics, but I am asking a more general question here to see if anyone has the same issue, so I don't know if the specifics are important. Below is code at the very bottom of my main program loop.

use Time::HiRes qw (gettimeofday);

($lus2_sec,$lus2_usec) = gettimeofday();
@blah_LU_v2 = invert_LU_v2(@zmatrix);
($lue2_sec,$lue2_usec) = gettimeofday();
$lu2_elapsed = sprintf("%.3f", ($lue2_sec+($lue2_usec/1000000))-($lus2_sec+($lus2_usec/1000000)));
syswrite STDOUT, "$lu2_elapsed seconds\n";

($lus2_sec,$lus2_usec) = gettimeofday();
@blah_LU_v2 = invert_LU_v2(@zmatrix);
($lue2_sec,$lue2_usec) = gettimeofday();
$lu2_elapsed = sprintf("%.3f", ($lue2_sec+($lue2_usec/1000000))-($lus2_sec+($lus2_usec/1000000)));
syswrite STDOUT, "$lu2_elapsed seconds\n";

Each subroutine operates on the same @zmatrix data, which it does not change. I get the exact same answer from each subroutine call (verified earlier), so I know it's not screwing up the input data. The subroutine is also a simple single threaded structure, and this is being run on an idle 12-core workstation with 96GB of RAM. There should be no disk swapping or CPU issue since this machine has more than enough power to handle this relatively small matrix. However, the output of the program results in something like this (running five successive calls of the subroutine, obviously):

96.485 seconds
99.116 seconds
100.036 seconds
100.615 seconds
101.494 seconds

The subroutine keeps getting a little slower for as many tests as I've run. If I terminate and relaunch the program from the command line, it will start out at around 96 seconds and then slow down from there every single time. Why would it be slowing down like this?

The subroutine with the issue is shown below. Note that I've now used NYTProf to nail down the time increase to calls of Math::Complex::_multiply and _minus. Each time I call the invert_LU_v2 subroutine, it makes the same number of calls to Math::Complex, but they take a few % longer on subsequent calls of invert_LU_v2. Please also feel free to critique my code and let me know what else I'm doing wrong. I am a beginner, have no training, and don't really know what I'm doing.

sub invert_LU_v2 {
    my(@junk) = (@_);
    my @matrix_local;
    my @matrix_L;
    my @matrix_B;
    my @matrix_inverse;

    my $tt;
    my $row;
    my $col;
    my $temp;
    my $reduced;
    my $normalize = 1;
    my $multiplier = 1;
    my $dimension = @junk - 1;

    for($row=1;$row<=$dimension;$row++){
        for($col=1;$col<=$dimension;$col++){
            $matrix_local[$row][$col]=$junk[$row][$col];
        }
    }

    for($row=1;$row<=$dimension;$row++){
        for($col=1;$col<=$dimension;$col++){
            if($row==$col){$matrix_L[$row][$col] = 1;$matrix_B[$row][$col] = 1;}
            else {$matrix_L[$row][$col] = 0;$matrix_B[$row][$col] = 0;}
        }
    }

    for($row=1;$row<=$dimension;$row++){

        $normalize = $matrix_local[$row][$row];
        $matrix_L[$row][$row] = $normalize;             
        for($col=1;$col<=$dimension;$col++){
            $matrix_local[$row][$col] /= $normalize;
        }

        for($temp=$row+1;$temp<=$dimension;$temp++){
            if(($temp != $row) && (abs($matrix_local[$temp][$row]) != 0)){
                $multiplier = $matrix_local[$temp][$row];
                $matrix_L[$temp][$row] = $multiplier;
                for($col=$row;$col<=$dimension;$col++){
                    $reduced = $matrix_local[$temp][$col] - $matrix_local[$row][$col]*$multiplier;
                    $matrix_local[$temp][$col] = $reduced;
                }
            }
        }
    }

    my @y_intermediate;

    for($col=1;$col<=$dimension;$col++){$y_intermediate[1][$col] = $matrix_B[1][$col]/$matrix_L[1][1]}

    for($col=1;$col<=$dimension;$col++){
        for($row=2;$row<=$dimension;$row++){
            $y_intermediate[$row][$col] = $matrix_B[$row][$col];
            for($tt=1;$tt<=($row-1);$tt++){$y_intermediate[$row][$col] -= ($matrix_L[$row][$tt]*$y_intermediate[$tt][$col])}
            $y_intermediate[$row][$col] /= $matrix_L[$row][$row];
        }
    }

    for($col=1;$col<=$dimension;$col++){$matrix_inverse[$dimension][$col] = $y_intermediate[$dimension][$col]/$matrix_local[$dimension][$dimension]}

    for($col=1;$col<=$dimension;$col++){
        for($row=($dimension-1);$row>=1;$row--){
            $matrix_inverse[$row][$col] = $y_intermediate[$row][$col];
            for($tt=($row+1);$tt<=$dimension;$tt++){$matrix_inverse[$row][$col] -= ($matrix_local[$row][$tt]*$matrix_inverse[$tt][$col])}
            $matrix_inverse[$row][$col] /= $matrix_local[$row][$row];
        }
    }

    return(@matrix_inverse);
}

Upvotes: 0

Views: 193

Answers (1)

user1126070
user1126070

Reputation: 5069

Use Benchmark to do benchmarks :-)

Maybe the problem not in your program but in your measurment?

Use Devel::NYTProf for debug. It will show you a lot of useful info, timings, etc.

Upvotes: 3

Related Questions