#! /usr/bin/perl use strict; use IPC::Open2; use Time::HiRes qw (gettimeofday tv_interval); my $tupperpage = 226; my $large_size = 100000000; my @time = (); sub bench { my ($header, $nprocs, $ntups, $threshold, $ddlcount) = @_; my @result = (); my @rds = (); for (my $ip = 0 ; $ip < $nprocs ; $ip++) { pipe(my $rd, my $wr); $rds[$ip] = $rd; my $pid = fork(); die "fork failed: $!\n" if ($pid < 0); if ($pid == 0) { close($rd); my $pid = open2(my $psqlrd, my $psqlwr, "psql postgres > /dev/null"); if ($threshold >= 0) { print $psqlwr "SET wal_skip_threshold to $threshold;\n"; } print $psqlwr "DROP TABLE IF EXISTS t$ip;"; print $psqlwr "CREATE TABLE t$ip (a int);\n"; my @st = gettimeofday(); for (my $i = 0 ; $i < $ddlcount ; $i++) { print $psqlwr "BEGIN;"; print $psqlwr "TRUNCATE t$ip;"; print $psqlwr "INSERT INTO t$ip (SELECT a FROM generate_series(1, $ntups) a);"; print $psqlwr "COMMIT;"; } close($psqlwr); waitpid($pid, 0); print $wr $ip, " ", 1000 * tv_interval(\@st, [gettimeofday]), "\n"; exit; } close($wr); } my $rpid; while (($rpid = wait()) == 0) {} my $sum = 0; for (my $ip = 0 ; $ip < $nprocs ; $ip++) { my $ret = readline($rds[$ip]); die "format? $ret\n" if ($ret !~ /^([0-9]+) ([0-9.]+)$/); $sum += $2; } printf "$header: procs $nprocs: time %.0f\n", $sum / $nprocs; } sub log10 { return log($_[0]) / log(10); } # benchmark for wal_level = replica, the third parameter of bench # doesn't affect sub bench1 { my $ddlcount = 5; $ddlcount = $ARGV[1] if ($#ARGV > 0); print "benchmark for wal_level = replica\n"; for (my $s = 0 ; $s <= 4 ; $s += 0.25) { my $ss = int(10 ** $s); bench("size $ss", 1, $ss * $tupperpage, 0, $ddlcount); } } # benchmark for wal_level = minimal. sub bench2 { my $ddlcount = 5; $ddlcount = $ARGV[1] if ($#ARGV > 0); print "benchmark for wal_level = minimal\n"; for (my $s = 0 ; $s <= 4.5 ; $s += 0.25) { my $ss = int(10 ** $s); bench("size $ss: SYNC ", 1, $ss * $tupperpage, 0, $ddlcount); bench("size $ss: WAL ", 1, $ss * $tupperpage, $large_size, $ddlcount); } } # find crossing point of WAL and SYNC by bisecting sub bench3 { my $ddlcount = 5; $ddlcount = $ARGV[1] if ($#ARGV > 0); print "find crossing point of WAL and SYNC by bisecting\n"; bench("SYNC: size 0", 1, 1, 8); bench("WAL : size 0", 1, 1, 16); my $s = 1; my $st = 10000; while (1) { my $ts = bench("SYNC: size $s", $tupperpage * $s, 0, $ddlcount); my $tw = bench("WAL : size $s", $tupperpage * $s, $large_size, $ddlcount); if ($st < 1.0){ print "DONE\n"; exit(0); } if ($ts > $tw) { $s += $st; $st /= 2; } else { $s -= $st; $st /= 2; } } } # benchmark with multiple processes sub bench4 { my $ddlcount = 5; my $nprocs = 10; $nprocs = $ARGV[1] if ($#ARGV > 0); $ddlcount = $ARGV[2] if ($#ARGV > 1); print "benchmark for wal_level = minimal, $nprocs processes\n"; print "bench 4: nprocs = $nprocs, DDL count = $ddlcount\n"; for (my $s = 1.0 ; $s <= 3.5 ; $s += 0.25) { my $ss = int(10 ** $s); bench("pages $ss: SYNC ", $nprocs, $ss * $tupperpage, 0, 5); bench("pages $ss: WAL ", $nprocs, $ss * $tupperpage, $large_size, 5); } } sub bench5 { my $ddlcount = 5; my $pages = 100; my $mode = "s"; my $threshold = 0; $ddlcount = $ARGV[1] if ($#ARGV > 0); $pages = $ARGV[2] if ($#ARGV > 1); $mode = $ARGV[3] if ($#ARGV > 2); if ($mode eq 's') { $threshold = 0; } elsif ($mode eq 's') { $threshold = $large_size; } elsif ($mode eq 'n') { $threshold = -1; } elsif ($mode eq 'w') { $threshold = $large_size; } else { die "mode must be s, w or n\n"; } print "bench 5: mode = $mode, DDL count = $ddlcount, pages = $pages\n"; bench("size $pages", 1, $pages * $tupperpage, $threshold, $ddlcount); } bench1() if ($ARGV[0] == 1); bench2() if ($ARGV[0] == 2); bench3() if ($ARGV[0] == 3); bench4() if ($ARGV[0] == 4); bench5() if ($ARGV[0] == 5);