]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add a Tcl script to run the performance tests described in
authordan <dan@noemail.net>
Tue, 29 Aug 2017 17:52:14 +0000 (17:52 +0000)
committerdan <dan@noemail.net>
Tue, 29 Aug 2017 17:52:14 +0000 (17:52 +0000)
README-server-edition.html.

FossilOrigin-Name: 1b3df8ffc551df0e4d8bcb633e1549ba769d8866cfcffea4cb62949ecf5c4c99

manifest
manifest.uuid
src/server.c
tool/se_perf_test.tcl [new file with mode: 0644]
tool/tserver.c

index 7737c83668615e772145aba88806f3c9113b69d9..3de7b1f9768f7c1004e239ac20d193967115c282 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Ensure\sthat\swrite-locks\son\spages\sare\sdropped\sat\sthe\send\sof\seach\nwrite\stransaction,\seven\sif\sthere\sis\sstill\sa\sread\stransaction\sopen.
-D 2017-08-19T15:50:45.975
+C Add\sa\sTcl\sscript\sto\srun\sthe\sperformance\stests\sdescribed\sin\nREADME-server-edition.html.
+D 2017-08-29T17:52:14.719
 F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
@@ -456,7 +456,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c c9b3d8444bbf6f167d84f41ca6f3672e2521cb163a8c706b19058dc82fffe9b8
-F src/server.c 4215bc2287c28f37e2bc79521eb8163e1340be2ca45f0fe4b2566f5faec9300c
+F src/server.c 9af69ec201823023bfa6f52b2b8262611f2e14698cb7d5e79e7791f0e7fd7139
 F src/server.h f46be129ffe407cac9b7018e6d4851b04e685d59b6837c73a1fb69e6aab52e3a
 F src/shell.c bd6a37cbe8bf64ef6a6a74fdc50f067d3148149b4ce2b4d03154663e66ded55f
 F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
@@ -1610,6 +1610,7 @@ F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
 F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
 F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076
+F tool/se_perf_test.tcl e2a5081f9378f188a431c4a85c5f3f9e99719027df5a6faa405c981b267ad8fd
 F tool/showdb.c e6bc9dba233bf1b57ca0a525a2bba762db4e223de84990739db3f09c46151b1e
 F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
 F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
@@ -1630,7 +1631,7 @@ F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
 F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
 F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148
 F tool/tostr.tcl 96022f35ada2194f6f8ccf6fd95809e90ed277c4
-F tool/tserver.c d6b4e074dc9d11edf9aac79cfd925cf1ea71f823b00344bc443e1aaea1f16d5b
+F tool/tserver.c ac67b8fe175850b780c5bd1888c2bb2f0f5e24096f040db7fc1a2af7a4908f2b
 F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
 F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
 F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
@@ -1658,7 +1659,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P abb6e076c851c0b10f62c02d0d7e54f24d86c75f01036dddbc0a8a7dfc627a0d
-R aa6e06e084e3c3d3595864687ba9477a
+P 2dd36ade9ea948de27b217b83cbf704e071e6ea5dddb8566165a645143b0f846
+R 090737ae736ae0ec45491b46ad6ddffe
 U dan
-Z 571fa6db3e131de25960c3e8f380a0b4
+Z 196af7197d18e14a39d9e416f4edfb10
index a55ffa5f42f978cfbc8d37f951c1f0fcec659a2d..09e280d4dbb531d10a3f25217764333075b99f5d 100644 (file)
@@ -1 +1 @@
-2dd36ade9ea948de27b217b83cbf704e071e6ea5dddb8566165a645143b0f846
\ No newline at end of file
+1b3df8ffc551df0e4d8bcb633e1549ba769d8866cfcffea4cb62949ecf5c4c99
\ No newline at end of file
index f72e7a9dc9c2188c11059d61984df2a76b6aa6d3..7e663d599b14c91ee3a47fd047738ba058733fc3 100644 (file)
@@ -717,6 +717,17 @@ int sqlite3ServerEnd(Server *p){
   return SQLITE_OK;
 }
 
+#if 0
+static void dump_commit_list(ServerDb *pDb, int bRemove){
+  Server *pIter;
+  printf("commitlist(%d):", bRemove);
+  for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext ){
+    printf(" %p", (void*)pIter);
+  }
+  printf("\n");
+}
+#endif
+
 int sqlite3ServerPreCommit(Server *p, ServerPage *pPg){
   ServerDb *pDb = p->pDb;
   int rc = SQLITE_OK;
@@ -775,7 +786,6 @@ int sqlite3ServerPreCommit(Server *p, ServerPage *pPg){
   assert( p->pNext==0 );
   p->pNext = pDb->pCommit;
   pDb->pCommit = p;
-
   sqlite3_mutex_leave(pDb->mutex);
   return rc;
 }
@@ -801,7 +811,7 @@ int sqlite3ServerEndWrite(Server *p){
     }
   }
   if( pDb->pServerShm==0 ){
-    ServerDb **pp;
+    Server **pp;
     /* If this connection is in the committers list, remove it. */
     for(pp=&pDb->pCommit; *pp; pp = &((*pp)->pNext)){
       if( *pp==p ){
diff --git a/tool/se_perf_test.tcl b/tool/se_perf_test.tcl
new file mode 100644 (file)
index 0000000..8b55826
--- /dev/null
@@ -0,0 +1,303 @@
+#!/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(-mode)     "server"
+set O(-rows)     [expr 5000000]
+set O(-tserver)  "./tserver"
+set O(-seconds)  20
+set O(-writers)  2
+set O(-readers)  1
+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.$mode.db)"
+  puts stderr "  -mode server|begin-concurrent         (default: server)"
+  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: 2)"
+  puts stderr "  -readers <number of reader clients>   (default: 1)"
+  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 != "server" && $val != "begin-concurrent" 
+       && $val != "wal" && $val != "persist"
+      } {
+        set xyz "\"server\", \"begin-concurrent\", \"wal\" or \"persist\""
+        error_out "Found \"$val\" - expected $xyz"
+      }
+    }
+  }
+  set O($opt) [lindex $argv $i]
+}
+if {$O(-database)==""} {
+  set O(-database) "test.$O(-mode).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;
+    }
+    if {$O(-mode)=="server"} {
+      db eval "PRAGMA freelist_format = 2"
+    }
+    db close
+    switch -- $O(-mode) {
+      server {
+        if {![file exists $O(-database)-journal]} {
+          file mkdir $O(-database)-journal
+        }
+      }
+
+      wal {
+        sqlite3 db $O(-database)
+        db eval {PRAGMA journal_mode = wal}
+        db close
+      }
+
+      begin-concurrent {
+        sqlite3 db $O(-database)
+        db eval {PRAGMA journal_mode = wal}
+        db close
+      }
+    }
+  }
+}
+
+#-------------------------------------------------------------------------
+# Functions to start and stop the tserver process:
+#
+#   tserver_start
+#   tserver_stop
+#
+set ::tserver {}
+proc tserver_start {} {
+  global O
+  set ::tserver [open "|$O(-tserver) -vfs unix-excl $O(-database)"]
+  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
+  switch -- $O(-mode) {
+    persist {
+      puts $fd "PRAGMA journal_mode = PERSIST;"
+    }
+  }
+  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 {} {
+  global O
+  set commit "COMMIT;"
+  set begin "BEGIN;"
+  if {$O(-mode)=="begin-concurrent" || $O(-mode)=="wal"} {
+    set commit ".mutex_commit"
+    set begin "BEGIN CONCURRENT;"
+  }
+
+  if {$O(-mode)=="server"} { set beginarg "READONLY" }
+
+  set tail "randomblob(16), randomblob(16), randomblob(400));"
+  return [subst -nocommands {
+    $begin
+      REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+      REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+      REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+      REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+      REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+    $commit
+  }]
+}
+
+proc script_reader {} {
+  global O
+
+  set beginarg ""
+  if {$O(-mode)=="server"} { set beginarg "READONLY" }
+
+  return [subst -nocommands {
+    BEGIN $beginarg;
+      SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+      SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+      SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+      SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+      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]
+}
+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
+
+
index 71f5b93e73a5b0e31ab741bc879924444ecaaed0..c39cfc45ffae629203f7bc0efa373771afd7cfe4 100644 (file)
@@ -34,6 +34,7 @@
 **   .seconds N               Configure the number of seconds to ".run" for.
 **   .mutex_commit            Add a "COMMIT" protected by a g.commit_mutex
 **                            to the current SQL.
+**   .stop                    Stop the tserver process - exit(0).
 **
 ** Example input:
 **
@@ -69,6 +70,7 @@ struct TserverGlobal {
   char *zDatabaseName;             /* Database used by this server */
   char *zVfs;
   sqlite3_mutex *commit_mutex;
+  sqlite3 *db;                     /* Global db handle */
 
   /* The following use native pthreads instead of a portable interface. This
   ** is because a condition variable, as well as a mutex, is required.  */
@@ -297,7 +299,11 @@ static int handle_run_command(ClientCtx *p){
   }
 
   if( rc==SQLITE_OK ){
+    int nMs = (int)(get_timer() - t0);
     send_message(p, "ok (%d/%d SQLITE_BUSY)\n", nBusy, j);
+    if( p->nRepeat<=0 ){
+      send_message(p, "### ok %d busy %d ms %d\n", j-nBusy, nBusy, nMs);
+    }
   }
   clear_sql(p);
 
@@ -350,7 +356,7 @@ static int handle_dot_command(ClientCtx *p, const char *zCmd, int nCmd){
     rc = handle_run_command(p);
   }
 
-  else if( n>=1 && n<=7 && 0==strncmp(z, "seconds", n) ){
+  else if( n>=2 && n<=7 && 0==strncmp(z, "seconds", n) ){
     if( nArg ){
       p->nSecond = strtol(zArg, 0, 0);
       if( p->nSecond>0 ) p->nRepeat = 0;
@@ -365,6 +371,11 @@ static int handle_dot_command(ClientCtx *p, const char *zCmd, int nCmd){
     }
   }
 
+  else if( n>=2 && n<=4 && 0==strncmp(z, "stop", n) ){
+    sqlite3_close(g.db);
+    exit(0);
+  }
+
   else{
     send_message(p, 
         "unrecognized dot command: %.*s\n"
@@ -467,6 +478,7 @@ static void *handle_client(void *pArg){
   }
 
   fprintf(stdout, "Client %d disconnects\n", ctx.fd);
+  fflush(stdout);
   close(ctx.fd);
   clear_sql(&ctx);
   sqlite3_free(ctx.aPrepare);
@@ -480,7 +492,6 @@ static void usage(const char *zExec){
 }
 
 int main(int argc, char *argv[]) {
-  sqlite3 *db;
   int sfd;
   int rc;
   int yes = 1;
@@ -505,17 +516,17 @@ int main(int argc, char *argv[]) {
   pthread_mutex_init(&g.ckpt_mutex, 0);
   pthread_cond_init(&g.ckpt_cond, 0);
 
-  rc = sqlite3_open_v2(g.zDatabaseName, &db,
+  rc = sqlite3_open_v2(g.zDatabaseName, &g.db,
       SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, g.zVfs
   );
   if( rc!=SQLITE_OK ){
-    fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(db));
+    fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(g.db));
     return 1;
   }
 
-  rc = sqlite3_exec(db, "SELECT * FROM sqlite_master", 0, 0, 0);
+  rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, 0);
   if( rc!=SQLITE_OK ){
-    fprintf(stderr, "sqlite3_exec(): %s\n", sqlite3_errmsg(db));
+    fprintf(stderr, "sqlite3_exec(): %s\n", sqlite3_errmsg(g.db));
     return 1;
   }
 
@@ -557,6 +568,7 @@ int main(int argc, char *argv[]) {
     }
 
     fprintf(stdout, "Client %d connects\n", cfd);
+    fflush(stdout);
     rc = pthread_create(&tid, NULL, handle_client, (void*)(intptr_t)cfd);
     if( rc!=0 ){
       perror("pthread_create()");