/ Check-in [208b2b04]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Re-implement the core of the multi-threaded sorter tests in sort4.test using C. Run each test in sort4.test ten times, or repeat all tests for 300 seconds as part of the "multithread" permutation test.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | threads
Files: files | file ages | folders
SHA1: 208b2b04d4d282bec4424ea7160a123ba549d118
User & Date: dan 2014-05-06 15:38:07
Context
2014-05-06
16:21
Add a little extra variety to the tests in sort4.test. check-in: 7de6aee6 user: dan tags: threads
15:38
Re-implement the core of the multi-threaded sorter tests in sort4.test using C. Run each test in sort4.test ten times, or repeat all tests for 300 seconds as part of the "multithread" permutation test. check-in: 208b2b04 user: dan tags: threads
2014-05-05
20:03
Add test file sort4.test, containing brute force tests for the multi-theaded sorter. check-in: 9cc364c4 user: dan tags: threads
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test1.c.

  6366   6366       }
  6367   6367     }
  6368   6368   
  6369   6369     Tcl_ResetResult(interp);
  6370   6370     return TCL_OK;
  6371   6371   }
  6372   6372   
         6373  +/*
         6374  +**     sorter_test_sort4_helper DB SQL1 NSTEP SQL2
         6375  +**
         6376  +** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, 
         6377  +** check that the leftmost and rightmost columns returned are both integers,
         6378  +** and that both contain the same value.
         6379  +**
         6380  +** Then execute statement $SQL2. Check that the statement returns the same
         6381  +** set of integers in the same order as in the previous step (using $SQL1).
         6382  +*/
         6383  +static int sorter_test_sort4_helper(
         6384  +  void * clientData,
         6385  +  Tcl_Interp *interp,
         6386  +  int objc,
         6387  +  Tcl_Obj *CONST objv[]
         6388  +){
         6389  +  const char *zSql1;
         6390  +  const char *zSql2;
         6391  +  int nStep; 
         6392  +  int iStep; 
         6393  +  int iCksum1 = 0; 
         6394  +  int iCksum2 = 0; 
         6395  +  int rc;
         6396  +  int iB;
         6397  +  sqlite3 *db;
         6398  +  sqlite3_stmt *pStmt;
         6399  +  
         6400  +  if( objc!=5 ){
         6401  +    Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2");
         6402  +    return TCL_ERROR;
         6403  +  }
         6404  +
         6405  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         6406  +  zSql1 = Tcl_GetString(objv[2]);
         6407  +  if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR;
         6408  +  zSql2 = Tcl_GetString(objv[4]);
         6409  +
         6410  +  rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
         6411  +  if( rc!=SQLITE_OK ) goto sql_error;
         6412  +
         6413  +  iB = sqlite3_column_count(pStmt)-1;
         6414  +  for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
         6415  +    int a = sqlite3_column_int(pStmt, 0);
         6416  +    if( a!=sqlite3_column_int(pStmt, iB) ){
         6417  +      Tcl_AppendResult(interp, "data error: (a!=b)", 0);
         6418  +      return TCL_ERROR;
         6419  +    }
         6420  +
         6421  +    iCksum1 += (iCksum1 << 3) + a;
         6422  +  }
         6423  +  rc = sqlite3_finalize(pStmt);
         6424  +  if( rc!=SQLITE_OK ) goto sql_error;
         6425  +
         6426  +  rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
         6427  +  if( rc!=SQLITE_OK ) goto sql_error;
         6428  +  for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
         6429  +    int a = sqlite3_column_int(pStmt, 0);
         6430  +    iCksum2 += (iCksum2 << 3) + a;
         6431  +  }
         6432  +  rc = sqlite3_finalize(pStmt);
         6433  +  if( rc!=SQLITE_OK ) goto sql_error;
         6434  +
         6435  +  if( iCksum1!=iCksum2 ){
         6436  +    Tcl_AppendResult(interp, "checksum mismatch", 0);
         6437  +    return TCL_ERROR;
         6438  +  }
         6439  +
         6440  +  return TCL_OK;
         6441  + sql_error:
         6442  +  Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
         6443  +  return TCL_ERROR;
         6444  +}
         6445  +
  6373   6446   
  6374   6447   /*
  6375   6448   ** Register commands with the TCL interpreter.
  6376   6449   */
  6377   6450   int Sqlitetest1_Init(Tcl_Interp *interp){
  6378   6451     extern int sqlite3_search_count;
  6379   6452     extern int sqlite3_found_count;
................................................................................
  6600   6673   #endif
  6601   6674        { "sqlite3_test_control", test_test_control },
  6602   6675   #if SQLITE_OS_UNIX
  6603   6676        { "getrusage", test_getrusage },
  6604   6677   #endif
  6605   6678        { "load_static_extension", tclLoadStaticExtensionCmd },
  6606   6679        { "sorter_test_fakeheap", sorter_test_fakeheap },
         6680  +     { "sorter_test_sort4_helper", sorter_test_sort4_helper },
  6607   6681     };
  6608   6682     static int bitmask_size = sizeof(Bitmask)*8;
  6609   6683     int i;
  6610   6684     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  6611   6685     extern int sqlite3_opentemp_count;
  6612   6686     extern int sqlite3_like_count;
  6613   6687     extern int sqlite3_xferopt_count;

Changes to test/permutations.test.

   465    465     sqlite3_shutdown
   466    466     catch {sqlite3_config multithread}
   467    467     sqlite3_initialize
   468    468     autoinstall_test_functions
   469    469   } -files {
   470    470     delete.test   delete2.test  insert.test  rollback.test  select1.test
   471    471     select2.test  trans.test    update.test  vacuum.test    types.test
   472         -  types2.test   types3.test
          472  +  types2.test   types3.test   sort4.test
   473    473   } -shutdown {
   474    474     catch {db close}
   475    475     sqlite3_shutdown
   476    476     catch {sqlite3_config serialized}
   477    477     sqlite3_initialize
   478    478     autoinstall_test_functions
   479    479   }

Changes to test/sort4.test.

    14     14   # sorter.
    15     15   #
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   set testprefix sort4
    20     20   
           21  +# Configure the sorter to use 3 background threads.
    21     22   catch { db close }
    22     23   sqlite3_shutdown
    23     24   sqlite3_config_worker_threads 3
    24     25   sqlite3_initialize
    25     26   reset_db
           27  +
           28  +# Minimum number of seconds to run for. If the value is 0, each test
           29  +# is run exactly once. Otherwise, tests are repeated until the timeout
           30  +# expires.
           31  +set SORT4TIMEOUT 0
           32  +if {[permutation] == "multithread"} { set SORT4TIMEOUT 300 }
    26     33   
    27     34   #--------------------------------------------------------------------
    28     35   # Set up a table "t1" containing $nRow rows. Each row contains also
    29         -# contains blob fields that total to at least $nPayload bytes of 
    30         -# content.
           36  +# contains blob fields that collectively contain at least $nPayload 
           37  +# bytes of content. The table schema is as follows:
           38  +#
           39  +#   CREATE TABLE t1(a INTEGER, <extra-columns>, b INTEGER);
           40  +#
           41  +# For each row, the values of columns "a" and "b" are set to the same
           42  +# pseudo-randomly selected integer. The "extra-columns", of which there
           43  +# are at most eight, are named c0, c1, c2 etc. Column c0 contains a 4
           44  +# byte string. Column c1 an 8 byte string. Field c2 16 bytes, and so on.
           45  +#
           46  +# This table is intended to be used for testing queries of the form: 
           47  +#
           48  +#   SELECT a, <cols>, b FROM t1 ORDER BY a;
           49  +#
           50  +# The test code checks that rows are returned in order, and that the 
           51  +# values of "a" and "b" are the same for each row (the idea being that
           52  +# if field "b" at the end of the sorter record has not been corrupted, 
           53  +# the rest of the record is probably Ok as well).
    31     54   #
    32     55   proc populate_table {nRow nPayload} {
    33     56     set nCol 0
    34     57   
    35     58     set n 0
    36     59     for {set nCol 0} {$n < $nPayload} {incr nCol} {
    37     60       incr n [expr (4 << $nCol)]
................................................................................
    53     76         execsql $insert
    54     77       }
    55     78     }
    56     79   }
    57     80   
    58     81   # Helper for [do_sorter_test]
    59     82   #
    60         -proc sorter_test {nRow nRead {nPayload 100} {cache_size 10}} {
    61         -  db eval "PRAGMA cache_size = $cache_size"
           83  +proc sorter_test {nRow nRead nPayload} {
    62     84     set res [list]
    63     85   
    64     86     set nLoad [expr ($nRow > $nRead) ? $nRead : $nRow]
    65     87   
    66     88     set nPayload [expr (($nPayload+3)/4) * 4]
    67     89     set cols [list]
    68     90     foreach {mask col} { 
    69     91       0x04  c0 0x08  c1 0x10  c2 0x20  c3 
    70     92       0x40  c4 0x80  c5 0x100 c6 0x200 c7 
    71     93     } {
    72     94       if {$nPayload & $mask} { lappend cols $col }
    73     95     }
    74     96   
    75         -  set n 0
    76         -  db eval "SELECT a, [join $cols ,], b FROM t1 WHERE rowid<=$nRow ORDER BY a" {
    77         -    if {$a!=$b} { error "a!=b (a=$a b=$b)" }
    78         -    lappend res $a
    79         -    incr n
    80         -    if {$n==$nLoad} break
    81         -  }
           97  +  # Create two SELECT statements. Statement $sql1 uses the sorter to sort
           98  +  # $nRow records of a bit over $nPayload bytes each read from the "t1"
           99  +  # table created by [populate_table] proc above. Rows are sorted in order
          100  +  # of the integer field in each "t1" record.
          101  +  #
          102  +  # The second SQL statement sorts the same set of rows as the first, but
          103  +  # uses a LIMIT clause, causing SQLite to use a temp table instead of the
          104  +  # sorter for sorting.
          105  +  #
          106  +  set sql1 "SELECT a, [join $cols ,], b FROM t1 WHERE rowid<=$nRow ORDER BY a"
          107  +  set sql2 "SELECT a FROM t1 WHERE rowid<=$nRow ORDER BY a LIMIT $nRead"
    82    108   
    83         -
    84         -  set sql {SELECT a FROM t1 WHERE rowid<=$nRow ORDER BY a LIMIT $nRead}
    85         -  if {$res != [db eval $sql]} {
    86         -    puts $res
    87         -    puts [db eval {SELECT a FROM t1 WHERE rowid<=$nLoad ORDER BY a}]
    88         -    error "data no good"
    89         -  }
    90         -
          109  +  # Pass the two SQL statements to a helper command written in C. This
          110  +  # command steps statement $sql1 $nRead times and compares the integer
          111  +  # values in the rows returned with the results of executing $sql2. If
          112  +  # the comparison fails (indicating some bug in the sorter), a Tcl
          113  +  # exception is thrown.
          114  +  #
          115  +  sorter_test_sort4_helper db $sql1 $nRead $sql2
    91    116     set {} {} 
    92    117   }
    93    118   
    94    119   # Usage:
    95    120   #
    96    121   #   do_sorter_test <testname> <args>...
    97    122   #
................................................................................
   115    140         unset a(-cachesize)
   116    141         set optlist "[join [array names a] ,] or -cachesize"
   117    142         error "Unknown option $s, expected $optlist"
   118    143       }
   119    144       set a($s) $val
   120    145     }
   121    146   
   122         -  for {set i 0} {$i < $a(-repeats)} {incr i} {
   123         -    set cmd [list sorter_test $a(-rows) $a(-read) $a(-payload) $a(-cachesize)]
   124         -    do_test $tn.$i $cmd {}
   125         -  }
          147  +  db eval "PRAGMA cache_size = $a(-cachesize)"
          148  +
          149  +  do_test $tn [subst -nocommands {
          150  +    for {set i 0} {[set i] < $a(-repeats)} {incr i} {
          151  +      sorter_test $a(-rows) $a(-read) $a(-payload)
          152  +    }
          153  +  }] {}
          154  +}
          155  +
          156  +proc clock_seconds {} {
          157  +  db one {SELECT strftime('%s')}
   126    158   }
   127    159   
          160  +#-------------------------------------------------------------------------
          161  +# Begin tests here.
          162  +
          163  +# Create a test database.
   128    164   do_test 1 {
   129    165     execsql "PRAGMA page_size = 4096"
   130    166     populate_table 100000 500
   131    167   } {}
   132    168   
   133         -do_sorter_test 2 -repeats 10 -rows 1000   -read 100
   134         -do_sorter_test 3 -repeats 10 -rows 100000 -read 1000
   135         -do_sorter_test 4 -repeats 10 -rows 100000 -read 1000 -payload 500
   136         -do_sorter_test 5 -repeats 10 -rows 100000 -read 100000 -payload 8
   137         -do_sorter_test 6 -repeats 10 -rows 100000 -read 10 -payload 8
          169  +set iTimeLimit [expr [clock_seconds] + $SORT4TIMEOUT]
          170  +
          171  +for {set tn 2} {1} {incr tn} {
          172  +  do_sorter_test $tn.2 -repeats 10 -rows 1000   -read 100
          173  +  do_sorter_test $tn.3 -repeats 10 -rows 100000 -read 1000
          174  +  do_sorter_test $tn.4 -repeats 10 -rows 100000 -read 1000 -payload 500
          175  +  do_sorter_test $tn.5 -repeats 10 -rows 100000 -read 100000 -payload 8
          176  +  do_sorter_test $tn.6 -repeats 10 -rows 100000 -read 10 -payload 8
          177  +
          178  +  set iNow [clock_seconds]
          179  +  if {$iNow>=$iTimeLimit} break
          180  +  do_test "$testprefix-([expr $iTimeLimit-$iNow] seconds remain)" {} {}
          181  +}
   138    182   
   139    183   catch { db close }
   140    184   sqlite3_shutdown
   141    185   sqlite3_config_worker_threads 0
   142    186   sqlite3_initialize
   143    187   finish_test
   144         -
   145    188