mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Add multi-threaded performance test program "tserver" to this branch. Fix bugs
in the begin-concurrent/wal2 integration revealed by the same. FossilOrigin-Name: 7bd3b35661d7d0e51113b9e4b15a0ab7f8e26edeafb43941ef5b44bb94df5109
This commit is contained in:
283
tool/tserver_test.tcl
Normal file
283
tool/tserver_test.tcl
Normal file
@@ -0,0 +1,283 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# This script is used to run the performance test cases described in
|
||||
# README-server-edition.html.
|
||||
#
|
||||
|
||||
|
||||
package require sqlite3
|
||||
|
||||
# Default values for command line switches:
|
||||
set O(-database) ""
|
||||
set O(-rows) [expr 5000000]
|
||||
set O(-mode) wal2
|
||||
set O(-tserver) "./tserver"
|
||||
set O(-seconds) 20
|
||||
set O(-writers) 1
|
||||
set O(-readers) 0
|
||||
set O(-verbose) 0
|
||||
|
||||
|
||||
proc error_out {err} {
|
||||
puts stderr $err
|
||||
exit -1
|
||||
}
|
||||
|
||||
proc usage {} {
|
||||
puts stderr "Usage: $::argv0 ?OPTIONS?"
|
||||
puts stderr ""
|
||||
puts stderr "Where OPTIONS are:"
|
||||
puts stderr " -database <database file> (default: test.db)"
|
||||
puts stderr " -mode <mode> (default: wal2)"
|
||||
puts stderr " -rows <number of rows> (default: 5000000)"
|
||||
puts stderr " -tserver <path to tserver executable> (default: ./tserver)"
|
||||
puts stderr " -seconds <time to run for in seconds> (default: 20)"
|
||||
puts stderr " -writers <number of writer clients> (default: 1)"
|
||||
puts stderr " -readers <number of reader clients> (default: 0)"
|
||||
puts stderr " -verbose 0|1 (default: 0)"
|
||||
exit -1
|
||||
}
|
||||
|
||||
for {set i 0} {$i < [llength $argv]} {incr i} {
|
||||
set opt ""
|
||||
set arg [lindex $argv $i]
|
||||
set n [expr [string length $arg]-1]
|
||||
foreach k [array names ::O] {
|
||||
if {[string range $k 0 $n]==$arg} {
|
||||
if {$opt==""} {
|
||||
set opt $k
|
||||
} else {
|
||||
error_out "ambiguous option: $arg ($k or $opt)"
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$opt==""} { usage }
|
||||
if {$i==[llength $argv]-1} {
|
||||
error_out "option requires an argument: $opt"
|
||||
}
|
||||
incr i
|
||||
set val [lindex $argv $i]
|
||||
switch -- $opt {
|
||||
-mode {
|
||||
if {$val != "wal" && $val != "wal2"} {
|
||||
set xyz "\"wal\" or \"wal2\""
|
||||
error_out "Found \"$val\" - expected $xyz"
|
||||
}
|
||||
}
|
||||
}
|
||||
set O($opt) [lindex $argv $i]
|
||||
}
|
||||
if {$O(-database)==""} {
|
||||
set O(-database) "test.db"
|
||||
}
|
||||
|
||||
set O(-rows) [expr $O(-rows)]
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Create and populate the required test database, if it is not already
|
||||
# present in the file-system.
|
||||
#
|
||||
proc create_test_database {} {
|
||||
global O
|
||||
|
||||
if {[file exists $O(-database)]} {
|
||||
sqlite3 db $O(-database)
|
||||
|
||||
# Check the schema looks Ok.
|
||||
set s [db one {
|
||||
SELECT group_concat(name||pk, '.') FROM pragma_table_info('t1');
|
||||
}]
|
||||
if {$s != "a1.b0.c0.d0"} {
|
||||
error_out "Database $O(-database) exists but is not usable (schema)"
|
||||
}
|
||||
|
||||
# Check that the row count matches.
|
||||
set n [db one { SELECT count(*) FROM t1 }]
|
||||
if {$n != $O(-rows)} {
|
||||
error_out "Database $O(-database) exists but is not usable (row-count)"
|
||||
}
|
||||
db close
|
||||
} else {
|
||||
catch { file delete -force $O(-database)-journal }
|
||||
catch { file delete -force $O(-database)-wal }
|
||||
|
||||
if {$O(-verbose)} {
|
||||
puts "Building database $O(-database)..."
|
||||
}
|
||||
|
||||
sqlite3 db $O(-database)
|
||||
db eval {
|
||||
CREATE TABLE t1(
|
||||
a INTEGER PRIMARY KEY,
|
||||
b BLOB(16),
|
||||
c BLOB(16),
|
||||
d BLOB(400)
|
||||
);
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
CREATE INDEX i2 ON t1(c);
|
||||
|
||||
WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$O(-rows))
|
||||
INSERT INTO t1
|
||||
SELECT i-1, randomblob(16), randomblob(16), randomblob(400) FROM s;
|
||||
}
|
||||
db close
|
||||
}
|
||||
|
||||
switch -- $O(-mode) {
|
||||
wal {
|
||||
sqlite3 db $O(-database)
|
||||
db eval {PRAGMA journal_mode = delete}
|
||||
db eval {PRAGMA journal_mode = wal}
|
||||
db close
|
||||
}
|
||||
|
||||
wal2 {
|
||||
sqlite3 db $O(-database)
|
||||
db eval {PRAGMA journal_mode = delete}
|
||||
db eval {PRAGMA journal_mode = wal2}
|
||||
db close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Functions to start and stop the tserver process:
|
||||
#
|
||||
# tserver_start
|
||||
# tserver_stop
|
||||
#
|
||||
set ::tserver {}
|
||||
proc tserver_start {} {
|
||||
global O
|
||||
set cmd "|$O(-tserver) -vfs unix "
|
||||
if {$O(-mode)=="wal2"} {
|
||||
append cmd " -walautocheckpoint 0 "
|
||||
}
|
||||
append cmd "$O(-database)"
|
||||
set ::tserver [open $cmd]
|
||||
fconfigure $::tserver -blocking 0
|
||||
fileevent $::tserver readable tserver_data
|
||||
}
|
||||
|
||||
proc tserver_data {} {
|
||||
global O
|
||||
if {[eof $::tserver]} {
|
||||
error_out "tserver has exited"
|
||||
}
|
||||
set line [gets $::tserver]
|
||||
if {$line != "" && $O(-verbose)} {
|
||||
puts "tserver: $line"
|
||||
}
|
||||
}
|
||||
|
||||
proc tserver_stop {} {
|
||||
close $::tserver
|
||||
set fd [socket localhost 9999]
|
||||
puts $fd ".stop"
|
||||
close $fd
|
||||
}
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
set ::nClient 0
|
||||
set ::client_output [list]
|
||||
|
||||
proc client_data {name fd} {
|
||||
global O
|
||||
if {[eof $fd]} {
|
||||
incr ::nClient -1
|
||||
close $fd
|
||||
return
|
||||
}
|
||||
set str [gets $fd]
|
||||
if {[string trim $str]!=""} {
|
||||
if {[string range $str 0 3]=="### "} {
|
||||
lappend ::client_output [concat [list name $name] [lrange $str 1 end]]
|
||||
}
|
||||
if {$O(-verbose)} {
|
||||
puts "$name: $str"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc client_launch {name script} {
|
||||
global O
|
||||
set fd [socket localhost 9999]
|
||||
fconfigure $fd -blocking 0
|
||||
puts $fd "PRAGMA synchronous = OFF;"
|
||||
puts $fd ".repeat 1"
|
||||
puts $fd ".run"
|
||||
puts $fd $script
|
||||
puts $fd ".seconds $O(-seconds)"
|
||||
puts $fd ".run"
|
||||
puts $fd ".quit"
|
||||
flush $fd
|
||||
incr ::nClient
|
||||
fileevent $fd readable [list client_data $name $fd]
|
||||
}
|
||||
|
||||
proc client_wait {} {
|
||||
while {$::nClient>0} {vwait ::nClient}
|
||||
}
|
||||
|
||||
proc script_writer {bCkpt} {
|
||||
global O
|
||||
|
||||
set commit ".mutex_commit"
|
||||
set begin "BEGIN CONCURRENT;"
|
||||
set ckpt ""
|
||||
if {$bCkpt} {
|
||||
set ckpt ".checkpoint 2000"
|
||||
}
|
||||
|
||||
set tail "randomblob(16), randomblob(16), randomblob(400));"
|
||||
return [subst -nocommands {
|
||||
$ckpt
|
||||
$begin
|
||||
REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
|
||||
$commit
|
||||
}]
|
||||
}
|
||||
|
||||
proc script_reader {} {
|
||||
global O
|
||||
|
||||
return [subst -nocommands {
|
||||
BEGIN;
|
||||
SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
|
||||
END;
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
create_test_database
|
||||
tserver_start
|
||||
|
||||
for {set i 0} {$i < $O(-writers)} {incr i} {
|
||||
client_launch w.$i [script_writer [expr {$i==0 && $O(-mode)=="wal2"}]]
|
||||
}
|
||||
for {set i 0} {$i < $O(-readers)} {incr i} {
|
||||
client_launch r.$i [script_reader]
|
||||
}
|
||||
client_wait
|
||||
|
||||
set name(w) "Writers"
|
||||
set name(r) "Readers"
|
||||
foreach r $::client_output {
|
||||
array set a $r
|
||||
set type [string range $a(name) 0 0]
|
||||
incr x($type.ok) $a(ok);
|
||||
incr x($type.busy) $a(busy);
|
||||
incr x($type.n) 1
|
||||
set t($type) 1
|
||||
}
|
||||
|
||||
foreach type [array names t] {
|
||||
set nTPS [expr $x($type.ok) / $O(-seconds)]
|
||||
set nC [expr $nTPS / $x($type.n)]
|
||||
set nTotal [expr $x($type.ok) + $x($type.busy)]
|
||||
set bp [format %.2f [expr $x($type.busy) * 100.0 / $nTotal]]
|
||||
puts "$name($type): $nTPS transactions/second ($nC per client) ($bp% busy)"
|
||||
}
|
||||
|
||||
tserver_stop
|
||||
|
Reference in New Issue
Block a user