(unnamed)

text/plain

Filename: (unnamed)
Type: text/plain
Part: 1
Message: Re: shared-memory based stats collector
#! /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);
}