aboutsummaryrefslogtreecommitdiff
path: root/test/speedtest1.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/speedtest1.c')
-rw-r--r--test/speedtest1.c282
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 ){