#! /usr/bin/perl use strict; use IPC::Open2; use Time::HiRes qw( usleep ualarm gettimeofday tv_interval ); use Errno qw/ECHILD/; my $ndbs = 50; my $ntbls = 100; my $loops = 6; my $chiter = 2000; my $chtrlen = 10; my $nprocs = 90; my $trg_file = '/tmp/dbrun_pl.trg'; my $refresult_file = '/tmp/refresult.txt'; # title loops,ndbs,clnts,ntbls,childiter , xactlen,refprocs testrun("A1", $loops, 1, 1, 1, $chiter*10, $chtrlen, 0); testrun("A2", $loops, 1, 1, 1, $chiter*10, $chtrlen, 1); testrun("B1", $loops, 1, 90, 1, $chiter , $chtrlen, 0); testrun("B2", $loops, 1, 90, 1, $chiter , $chtrlen, 1); testrun("C1", $loops, 1, 90, 50, $chiter , $chtrlen, 0); testrun("C2", $loops, 1, 90, 50, $chiter , $chtrlen, 10); testrun("D1", $loops, 50, 90, 1, $chiter , $chtrlen, 0); testrun("D2", $loops, 50, 90, 1, $chiter , $chtrlen, 1); testrun("E1", $loops, 50, 90, 1, $chiter , $chtrlen, 10); testrun("F1", $loops , 1, 10, 1, $chiter , $chtrlen, 90); exit; sub testrun { my ($test_name, $loops, $ndbs, $nprocs, $ntbls, $childiter, $childtrlen, $nreferers) = @_; my @results = (); my @refresults = (); # run each iteration for (my $l = 0 ; $l < $loops ; $l++) { my %starttime = (); my %endtime = (); # This file is used for stopping free-running processes. open(OUT, '>', $trg_file) || die "failed to open file:$!\n"; print OUT "$$\n"; close(OUT); # It's very mysterious that one dummy subprocess makes things # stable. Perl runs slowly if there's only one psql process # without this... { my $pid = fork; if ($pid == 0) { while (-f $trg_file) { usleep (500000); } exit; } } # start referer processes, collecting how many times the query ran. pipe(my $refresrd, my $refreswr); for(my $i = 0 ; $i < $nreferers ; $i++) { my $pid = fork; if ($pid < 0) { die "fork referer process failed : $!\n"; } if ($pid == 0) { my $pid = open2(my $psqlrd, my $psqlwr, "psql postgres"); my $count = 0; close($refresrd); if ($pid < 0) { die "fork psql failed : $!\n"; } while (-f $trg_file) { print $psqlwr "select * from pg_stat_user_tables;\n"; while (<$psqlrd>) { last if ($_ =~ /rows\)/); } $count++; } print $refreswr "$count\n"; exit; } } close($refreswr); # launch updator processes for (my $i = 0 ; $i < $nprocs ; $i++) { my $dbn = rand($ndbs); # equal dist. my $dbname = sprintf("db%03d", $dbn); my $pid = fork; if ($pid < 0) { die "fork failed: $!\n"; } elsif ($pid == 0) { my $pid = open2(my $rd, my $wr, "psql $dbname > /dev/null"); if ($pid < 0) { die "sub fork failed: $!\n"; } my $ncmd = $childtrlen; #print $wr "set log_min_duration_statement to 0;\n"; print $wr "begin;\n"; for (my $i = 0 ; $i < $childiter ; $i++) { my $tbn = rand($ntbls); # equal dist. printf $wr "select /* $dbname\[$i\]*/ count(*) from t%03d;\n", $tbn; if (--$ncmd == 0) { print $wr "commit;begin;\n"; $ncmd = $childtrlen; } } print $wr "commit;\n"; print $wr "\\q\n"; my $res = <$rd>; exit; } (my $sec, my $usec) = &gettimeofday(); $starttime{$pid} = $sec * 1000 + $usec / 1000; # print "start\[$pid\] = $starttime{$pid}\n"; } # wait for updateors to finish for (my $i = 0 ; $i < $nprocs ; $i++) { my $pid = wait(); if ($pid < 0) { if ($! != ECHILD) {die "???: $!\n"; }} redo if (!defined $starttime{$pid}); (my $sec, my $usec) = &gettimeofday(); $endtime{$pid} = $sec * 1000 + $usec / 1000; # printf "%d[%d]: %d - %d = %d ms\n", $i, $pid, $endtime{$pid}, $starttime{$pid}, $endtime{$pid} - $starttime{$pid}; } my $sum = 0; foreach my $pid (keys %starttime) { $sum += $endtime{$pid} - $starttime{$pid}; # printf "[%d]: %d ms (%d, %d)\n", $pid, $endtime{$pid} - $starttime{$pid}, $starttime{$pid}, $endtime{$pid}; } push(@results, $sum / $nprocs); # kill referers if any (and dummy process) unlink($trg_file); while (wait() == 0) {} my $nrefs = 0; my $refcount = 0; while(<$refresrd>) { chomp; $refcount += $_; $nrefs++; } close($refresrd); push (@refresults, $refcount / $nrefs) if ($nrefs > 0); } # calculate stdev (my $updmean, my $updstdev) = stdev(@results); (my $refmean, my $refstdev) = stdev(@refresults); printf "$test_name (l:%d, d:%d, t:%d, i:%d, tr:%d): %.2f ms (stdev %.2f) / %d updprocs, %.2f refs (stdev %.2f) / %d refprocs\n", $loops, $ndbs, $ntbls, $childiter, $childtrlen, $updmean, $updstdev, $nprocs, $refmean, $refstdev, $nreferers; } sub stdev { my $sum = 0; my $sqsum = 0; my $count = $#_ + 1; return (0, 0) if $count == 0; foreach my $el (@_) { $sum += 1.0 * $el; $sqsum += 1.0 * $el * $el; } my $mean = $sum / $count; my $stdev = sqrt($sqsum / $count - $mean * $mean); return ($mean, $stdev); }