diff options
Diffstat (limited to 'test/speedtest1.c')
-rw-r--r-- | test/speedtest1.c | 282 |
1 files changed, 254 insertions, 28 deletions
diff --git a/test/speedtest1.c b/test/speedtest1.c index 68ca5788c..723c8cffb 100644 --- a/test/speedtest1.c +++ b/test/speedtest1.c @@ -7,7 +7,7 @@ static const char zHelp[] = "Usage: %s [--options] DATABASE\n" "Options:\n" " --autovacuum Enable AUTOVACUUM mode\n" - " --cachesize N Set the cache size to N\n" + " --cachesize N Set the cache size to N\n" " --exclusive Enable locking_mode=EXCLUSIVE\n" " --explain Like --sqlonly but with added EXPLAIN keywords\n" " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" @@ -15,11 +15,13 @@ static const char zHelp[] = " --journal M Set the journal_mode to M\n" " --key KEY Set the encryption key to KEY\n" " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" + " --memdb Use an in-memory database\n" " --mmap SZ MMAP the first SZ bytes of the database file\n" " --multithread Set multithreaded mode\n" " --nomemstat Disable memory statistics\n" " --nosync Set PRAGMA synchronous=OFF\n" " --notnull Add NOT NULL constraints to table columns\n" + " --output FILE Store SQL output in FILE\n" " --pagesize N Set the page size to N\n" " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" " --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n" @@ -41,7 +43,6 @@ static const char zHelp[] = " --without-rowid Use WITHOUT ROWID where appropriate\n" ; - #include "sqlite3.h" #include <assert.h> #include <stdio.h> @@ -61,6 +62,20 @@ static const char zHelp[] = # define sqlite3_int64 sqlite_int64 #endif +typedef sqlite3_uint64 u64; + +/* +** State structure for a Hash hash in progress +*/ +typedef struct HashContext HashContext; +struct HashContext { + unsigned char isInit; /* True if initialized */ + unsigned char i, j; /* State variables */ + unsigned char s[256]; /* State variables */ + unsigned char r[32]; /* Result */ +}; + + /* All global state is held in this structure */ static struct Global { sqlite3 *db; /* The open database connection */ @@ -80,8 +95,13 @@ static struct Global { const char *zNN; /* Might be NOT NULL */ const char *zPK; /* Might be UNIQUE or PRIMARY KEY */ unsigned int x, y; /* Pseudo-random number generator state */ + u64 nResByte; /* Total number of result bytes */ int nResult; /* Size of the current result */ char zResult[3000]; /* Text of the current result */ +#ifndef SPEEDTEST_OMIT_HASH + FILE *hashFile; /* Store all hash results in this file */ + HashContext hash; /* Hash of all output */ +#endif } g; /* Return " TEMP" or "", as appropriate for creating a table. @@ -90,7 +110,6 @@ static const char *isTemp(int N){ return g.eTemp>=N ? " TEMP" : ""; } - /* Print an error message and exit */ static void fatal_error(const char *zMsg, ...){ va_list ap; @@ -100,6 +119,72 @@ static void fatal_error(const char *zMsg, ...){ exit(1); } +#ifndef SPEEDTEST_OMIT_HASH +/**************************************************************************** +** Hash algorithm used to verify that compilation is not miscompiled +** in such a was as to generate an incorrect result. +*/ + +/* +** Initialize a new hash. iSize determines the size of the hash +** in bits and should be one of 224, 256, 384, or 512. Or iSize +** can be zero to use the default hash size of 256 bits. +*/ +static void HashInit(void){ + unsigned int k; + g.hash.i = 0; + g.hash.j = 0; + for(k=0; k<256; k++) g.hash.s[k] = k; +} + +/* +** Make consecutive calls to the HashUpdate function to add new content +** to the hash +*/ +static void HashUpdate( + const unsigned char *aData, + unsigned int nData +){ + unsigned char t; + unsigned char i = g.hash.i; + unsigned char j = g.hash.j; + unsigned int k; + if( g.hashFile ) fwrite(aData, 1, nData, g.hashFile); + for(k=0; k<nData; k++){ + j += g.hash.s[i] + aData[k]; + t = g.hash.s[j]; + g.hash.s[j] = g.hash.s[i]; + g.hash.s[i] = t; + i++; + } + g.hash.i = i; + g.hash.j = j; +} + +/* +** After all content has been added, invoke HashFinal() to compute +** the final hash. The hash result is stored in g.hash.r[]. +*/ +static void HashFinal(void){ + unsigned int k; + unsigned char t, i, j; + i = g.hash.i; + j = g.hash.j; + for(k=0; k<32; k++){ + i++; + t = g.hash.s[i]; + j += t; + g.hash.s[i] = g.hash.s[j]; + g.hash.s[j] = t; + t += g.hash.s[i]; + g.hash.r[k] = g.hash.s[t]; + } +} + +/* End of the Hash hashing logic +*****************************************************************************/ +#endif /* SPEEDTEST_OMIT_HASH */ + /* ** Return the value of a hexadecimal digit. Return -1 if the input ** is not a hex digit. @@ -324,6 +409,21 @@ void speedtest1_final(void){ printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots, (int)(g.iTotal/1000), (int)(g.iTotal%1000)); } + if( g.bVerify ){ +#ifndef SPEEDTEST_OMIT_HASH + int i; +#endif + printf("Verification Hash: %llu ", g.nResByte); +#ifndef SPEEDTEST_OMIT_HASH + HashUpdate((const unsigned char*)"\n", 1); + HashFinal(); + for(i=0; i<24; i++){ + printf("%02x", g.hash.r[i]); + } + if( g.hashFile && g.hashFile!=stdout ) fclose(g.hashFile); +#endif + printf("\n"); + } } /* Print an SQL statement to standard output */ @@ -372,6 +472,36 @@ void speedtest1_exec(const char *zFormat, ...){ speedtest1_shrink_memory(); } +/* Run SQL and return the first column of the first row as a string. The +** returned string is obtained from sqlite_malloc() and must be freed by +** the caller. +*/ +char *speedtest1_once(const char *zFormat, ...){ + va_list ap; + char *zSql; + sqlite3_stmt *pStmt; + char *zResult = 0; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( g.bSqlOnly ){ + printSql(zSql); + }else{ + int rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); + if( rc ){ + fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db)); + } + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *z = (const char*)sqlite3_column_text(pStmt, 0); + if( z ) zResult = sqlite3_mprintf("%s", z); + } + sqlite3_finalize(pStmt); + } + sqlite3_free(zSql); + speedtest1_shrink_memory(); + return zResult; +} + /* Prepare an SQL statement */ void speedtest1_prepare(const char *zFormat, ...){ va_list ap; @@ -404,6 +534,39 @@ void speedtest1_run(void){ const char *z = (const char*)sqlite3_column_text(g.pStmt, i); if( z==0 ) z = "nil"; len = (int)strlen(z); +#ifndef SPEEDTEST_OMIT_HASH + if( g.bVerify ){ + int eType = sqlite3_column_type(g.pStmt, i); + unsigned char zPrefix[2]; + zPrefix[0] = '\n'; + zPrefix[1] = "-IFTBN"[eType]; + if( g.nResByte ){ + HashUpdate(zPrefix, 2); + }else{ + HashUpdate(zPrefix+1, 1); + } + if( eType==SQLITE_FLOAT ){ + /* Omit the value of floating-point results from the verification + ** hash. The only thing we record is the fact that the result was + ** a floating-point value. */ + g.nResByte += 2; + }else if( eType==SQLITE_BLOB ){ + int nBlob = sqlite3_column_bytes(g.pStmt, i); + int iBlob; + unsigned char zChar[2]; + const unsigned char *aBlob = sqlite3_column_blob(g.pStmt, i); + for(iBlob=0; iBlob<nBlob; iBlob++){ + zChar[0] = "0123456789abcdef"[aBlob[iBlob]>>4]; + zChar[1] = "0123456789abcdef"[aBlob[iBlob]&15]; + HashUpdate(zChar,2); + } + g.nResByte += nBlob*2 + 2; + }else{ + HashUpdate((unsigned char*)z, len); + g.nResByte += len + 2; + } + } +#endif if( g.nResult+len<sizeof(g.zResult)-2 ){ if( g.nResult>0 ) g.zResult[g.nResult++] = ' '; memcpy(g.zResult + g.nResult, z, len+1); @@ -1987,7 +2150,8 @@ int main(int argc, char **argv){ int showStats = 0; /* True for --stats */ int nThread = 0; /* --threads value */ int mmapSize = 0; /* How big of a memory map to use */ - const char *zTSet = "main"; /* Which --testset torun */ + int memDb = 0; /* --memdb. Use an in-memory database */ + char *zTSet = "main"; /* Which --testset torun */ int doTrace = 0; /* True for --trace */ const char *zEncoding = 0; /* --utf16be or --utf16le */ const char *zDbName = 0; /* Name of the test database */ @@ -2000,7 +2164,7 @@ int main(int argc, char **argv){ int rc; /* API return code */ /* Display the version of SQLite being tested */ - printf("-- Speedtest1 for SQLite %s %.50s\n", + printf("-- Speedtest1 for SQLite %s %.48s\n", sqlite3_libversion(), sqlite3_sourceid()); /* Process command-line arguments */ @@ -2042,6 +2206,8 @@ int main(int argc, char **argv){ nLook = integerValue(argv[i+1]); szLook = integerValue(argv[i+2]); i += 2; + }else if( strcmp(z,"memdb")==0 ){ + memDb = 1; #if SQLITE_VERSION_NUMBER>=3006000 }else if( strcmp(z,"multithread")==0 ){ sqlite3_config(SQLITE_CONFIG_MULTITHREAD); @@ -2057,6 +2223,22 @@ int main(int argc, char **argv){ noSync = 1; }else if( strcmp(z,"notnull")==0 ){ g.zNN = "NOT NULL"; + }else if( strcmp(z,"output")==0 ){ +#ifdef SPEEDTEST_OMIT_HASH + fatal_error("The --output option is not supported with" + " -DSPEEDTEST_OMIT_HASH\n"); +#else + if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); + i++; + if( strcmp(argv[i],"-")==0 ){ + g.hashFile = stdout; + }else{ + g.hashFile = fopen(argv[i], "wb"); + if( g.hashFile==0 ){ + fatal_error("cannot open \"%s\" for writing\n", argv[i]); + } + } +#endif }else if( strcmp(z,"pagesize")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); pageSize = integerValue(argv[++i]); @@ -2110,6 +2292,9 @@ int main(int argc, char **argv){ zEncoding = "utf16be"; }else if( strcmp(z,"verify")==0 ){ g.bVerify = 1; +#ifndef SPEEDTEST_OMIT_HASH + HashInit(); +#endif }else if( strcmp(z,"without-rowid")==0 ){ g.zWR = "WITHOUT ROWID"; g.zPK = "PRIMARY KEY"; @@ -2151,13 +2336,13 @@ int main(int argc, char **argv){ sqlite3_initialize(); /* Open the database and the input file */ - if( sqlite3_open(zDbName, &g.db) ){ + if( sqlite3_open(memDb ? ":memory:" : zDbName, &g.db) ){ fatal_error("Cannot open database file: %s\n", zDbName); } #if SQLITE_VERSION_NUMBER>=3006001 if( nLook>0 && szLook>0 ){ pLook = malloc( nLook*szLook ); - rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook); + rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook); if( rc ) fatal_error("lookaside configuration failed: %d\n", rc); } #endif @@ -2167,6 +2352,9 @@ int main(int argc, char **argv){ #ifndef SQLITE_OMIT_DEPRECATED if( doTrace ) sqlite3_trace(g.db, traceCallback, 0); #endif + if( memDb>0 ){ + speedtest1_exec("PRAGMA temp_store=memory"); + } if( mmapSize>0 ){ speedtest1_exec("PRAGMA mmap_size=%d", mmapSize); } @@ -2197,30 +2385,68 @@ int main(int argc, char **argv){ } if( g.bExplain ) printf(".explain\n.echo on\n"); - if( strcmp(zTSet,"main")==0 ){ - testset_main(); - }else if( strcmp(zTSet,"debug1")==0 ){ - testset_debug1(); - }else if( strcmp(zTSet,"orm")==0 ){ - testset_orm(); - }else if( strcmp(zTSet,"cte")==0 ){ - testset_cte(); - }else if( strcmp(zTSet,"fp")==0 ){ - testset_fp(); - }else if( strcmp(zTSet,"trigger")==0 ){ - testset_trigger(); - }else if( strcmp(zTSet,"rtree")==0 ){ + do{ + char *zThisTest = zTSet; + char *zComma = strchr(zThisTest,','); + if( zComma ){ + *zComma = 0; + zTSet = zComma+1; + }else{ + zTSet = ""; + } + if( g.iTotal>0 || zComma!=0 ){ + printf(" Begin testset \"%s\"\n", zThisTest); + } + if( strcmp(zThisTest,"main")==0 ){ + testset_main(); + }else if( strcmp(zThisTest,"debug1")==0 ){ + testset_debug1(); + }else if( strcmp(zThisTest,"orm")==0 ){ + testset_orm(); + }else if( strcmp(zThisTest,"cte")==0 ){ + testset_cte(); + }else if( strcmp(zThisTest,"fp")==0 ){ + testset_fp(); + }else if( strcmp(zThisTest,"trigger")==0 ){ + testset_trigger(); + }else if( strcmp(zThisTest,"rtree")==0 ){ #ifdef SQLITE_ENABLE_RTREE - testset_rtree(6, 147); + testset_rtree(6, 147); #else - fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable " - "the R-Tree tests\n"); + fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable " + "the R-Tree tests\n"); #endif - }else{ - fatal_error("unknown testset: \"%s\"\n" - "Choices: cte debug1 fp main orm rtree trigger\n", - zTSet); - } + }else{ + fatal_error("unknown testset: \"%s\"\n" + "Choices: cte debug1 fp main orm rtree trigger\n", + zThisTest); + } + if( zTSet[0] ){ + char *zSql, *zObj; + speedtest1_begin_test(999, "Reset the database"); + while( 1 ){ + zObj = speedtest1_once( + "SELECT name FROM main.sqlite_master" + " WHERE sql LIKE 'CREATE %%TABLE%%'"); + if( zObj==0 ) break; + zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj); + speedtest1_exec(zSql); + sqlite3_free(zSql); + sqlite3_free(zObj); + } + while( 1 ){ + zObj = speedtest1_once( + "SELECT name FROM temp.sqlite_master" + " WHERE sql LIKE 'CREATE %%TABLE%%'"); + if( zObj==0 ) break; + zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj); + speedtest1_exec(zSql); + sqlite3_free(zSql); + sqlite3_free(zObj); + } + speedtest1_end_test(); + } + }while( zTSet[0] ); speedtest1_final(); if( showStats ){ |