xref: /sqlite-3.40.0/test/kvtest.c (revision a2e71ced)
1 /*
2 ** 2016-12-28
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** This file implements "key-value" performance test for SQLite.  The
14 ** purpose is to compare the speed of SQLite for accessing large BLOBs
15 ** versus reading those same BLOB values out of individual files in the
16 ** filesystem.
17 **
18 ** Run "kvtest" with no arguments for on-line help, or see comments below.
19 **
20 ** HOW TO COMPILE:
21 **
22 ** (1) Gather this source file and a recent SQLite3 amalgamation with its
23 **     header into the working directory.  You should have:
24 **
25 **          kvtest.c       >--- this file
26 **          sqlite3.c      \___ SQLite
27 **          sqlite3.h      /    amlagamation & header
28 **
29 ** (2) Run you compiler against the two C source code files.
30 **
31 **    (a) On linux or mac:
32 **
33 **        OPTS="-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION"
34 **        gcc -Os -I. $OPTS kvtest.c sqlite3.c -o kvtest
35 **
36 **             The $OPTS options can be omitted.  The $OPTS merely omit
37 **             the need to link against -ldl and -lpthread, or whatever
38 **             the equivalent libraries are called on your system.
39 **
40 **    (b) Windows with MSVC:
41 **
42 **        cl -I. kvtest.c sqlite3.c
43 **
44 ** USAGE:
45 **
46 ** (1) Create a test database by running "kvtest init" with appropriate
47 **     options.  See the help message for available options.
48 **
49 ** (2) Construct the corresponding pile-of-files database on disk using
50 **     the "kvtest export" command.
51 **
52 ** (3) Run tests using "kvtest run" against either the SQLite database or
53 **     the pile-of-files database and with appropriate options.
54 **
55 ** For example:
56 **
57 **       ./kvtest init x1.db --count 100000 --size 10000
58 **       mkdir x1
59 **       ./kvtest export x1.db x1
60 **       ./kvtest run x1.db --count 10000 --max-id 1000000
61 **       ./kvtest run x1 --count 10000 --max-id 1000000
62 */
63 static const char zHelp[] =
64 "Usage: kvtest COMMAND ARGS...\n"
65 "\n"
66 "   kvtest init DBFILE --count N --size M --pagesize X\n"
67 "\n"
68 "        Generate a new test database file named DBFILE containing N\n"
69 "        BLOBs each of size M bytes.  The page size of the new database\n"
70 "        file will be X.  Additional options:\n"
71 "\n"
72 "           --variance V           Randomly vary M by plus or minus V\n"
73 "\n"
74 "   kvtest export DBFILE DIRECTORY\n"
75 "\n"
76 "        Export all the blobs in the kv table of DBFILE into separate\n"
77 "        files in DIRECTORY.\n"
78 "\n"
79 "   kvtest stat DBFILE\n"
80 "\n"
81 "        Display summary information about DBFILE\n"
82 "\n"
83 "   kvtest run DBFILE [options]\n"
84 "\n"
85 "        Run a performance test.  DBFILE can be either the name of a\n"
86 "        database or a directory containing sample files.  Options:\n"
87 "\n"
88 "           --asc                  Read blobs in ascending order\n"
89 "           --blob-api             Use the BLOB API\n"
90 "           --cache-size N         Database cache size\n"
91 "           --count N              Read N blobs\n"
92 "           --desc                 Read blobs in descending order\n"
93 "           --integrity-check      Run 'PRAGMA integrity_check' after test\n"
94 "           --max-id N             Maximum blob key to use\n"
95 "           --mmap N               Mmap as much as N bytes of DBFILE\n"
96 "           --jmode MODE           Set MODE journal mode prior to starting\n"
97 "           --random               Read blobs in a random order\n"
98 "           --start N              Start reading with this blob key\n"
99 "           --stats                Output operating stats before exiting\n"
100 "           --update               To an overwrite test\n"
101 ;
102 
103 /* Reference resources used */
104 #include <stdio.h>
105 #include <stdlib.h>
106 #include <sys/types.h>
107 #include <sys/stat.h>
108 #include <assert.h>
109 #include <string.h>
110 #include "sqlite3.h"
111 
112 #ifndef _WIN32
113 # include <unistd.h>
114 #else
115   /* Provide Windows equivalent for the needed parts of unistd.h */
116 # include <io.h>
117 # define R_OK 2
118 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
119 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
120 # define access _access
121 #endif
122 
123 #include <stdint.h>
124 #include <inttypes.h>
125 
126 /*
127 ** The following macros are used to cast pointers to integers and
128 ** integers to pointers.  The way you do this varies from one compiler
129 ** to the next, so we have developed the following set of #if statements
130 ** to generate appropriate macros for a wide range of compilers.
131 **
132 ** The correct "ANSI" way to do this is to use the intptr_t type.
133 ** Unfortunately, that typedef is not available on all compilers, or
134 ** if it is available, it requires an #include of specific headers
135 ** that vary from one machine to the next.
136 **
137 ** Ticket #3860:  The llvm-gcc-4.2 compiler from Apple chokes on
138 ** the ((void*)&((char*)0)[X]) construct.  But MSVC chokes on ((void*)(X)).
139 ** So we have to define the macros in different ways depending on the
140 ** compiler.
141 */
142 #if defined(__PTRDIFF_TYPE__)  /* This case should work for GCC */
143 # define SQLITE_INT_TO_PTR(X)  ((void*)(__PTRDIFF_TYPE__)(X))
144 # define SQLITE_PTR_TO_INT(X)  ((sqlite3_int64)(__PTRDIFF_TYPE__)(X))
145 #elif !defined(__GNUC__)       /* Works for compilers other than LLVM */
146 # define SQLITE_INT_TO_PTR(X)  ((void*)&((char*)0)[X])
147 # define SQLITE_PTR_TO_INT(X)  ((sqlite3_int64)(((char*)X)-(char*)0))
148 #elif defined(HAVE_STDINT_H)   /* Use this case if we have ANSI headers */
149 # define SQLITE_INT_TO_PTR(X)  ((void*)(intptr_t)(X))
150 # define SQLITE_PTR_TO_INT(X)  ((sqlite3_int64)(intptr_t)(X))
151 #else                          /* Generates a warning - but it always works */
152 # define SQLITE_INT_TO_PTR(X)  ((void*)(X))
153 # define SQLITE_PTR_TO_INT(X)  ((sqlite3_int64)(X))
154 #endif
155 
156 /*
157 ** Show thqe help text and quit.
158 */
159 static void showHelp(void){
160   fprintf(stdout, "%s", zHelp);
161   exit(1);
162 }
163 
164 /*
165 ** Show an error message an quit.
166 */
167 static void fatalError(const char *zFormat, ...){
168   va_list ap;
169   fprintf(stdout, "ERROR: ");
170   va_start(ap, zFormat);
171   vfprintf(stdout, zFormat, ap);
172   va_end(ap);
173   fprintf(stdout, "\n");
174   exit(1);
175 }
176 
177 /*
178 ** Return the value of a hexadecimal digit.  Return -1 if the input
179 ** is not a hex digit.
180 */
181 static int hexDigitValue(char c){
182   if( c>='0' && c<='9' ) return c - '0';
183   if( c>='a' && c<='f' ) return c - 'a' + 10;
184   if( c>='A' && c<='F' ) return c - 'A' + 10;
185   return -1;
186 }
187 
188 /*
189 ** Interpret zArg as an integer value, possibly with suffixes.
190 */
191 static int integerValue(const char *zArg){
192   int v = 0;
193   static const struct { char *zSuffix; int iMult; } aMult[] = {
194     { "KiB", 1024 },
195     { "MiB", 1024*1024 },
196     { "GiB", 1024*1024*1024 },
197     { "KB",  1000 },
198     { "MB",  1000000 },
199     { "GB",  1000000000 },
200     { "K",   1000 },
201     { "M",   1000000 },
202     { "G",   1000000000 },
203   };
204   int i;
205   int isNeg = 0;
206   if( zArg[0]=='-' ){
207     isNeg = 1;
208     zArg++;
209   }else if( zArg[0]=='+' ){
210     zArg++;
211   }
212   if( zArg[0]=='0' && zArg[1]=='x' ){
213     int x;
214     zArg += 2;
215     while( (x = hexDigitValue(zArg[0]))>=0 ){
216       v = (v<<4) + x;
217       zArg++;
218     }
219   }else{
220     while( zArg[0]>='0' && zArg[0]<='9' ){
221       v = v*10 + zArg[0] - '0';
222       zArg++;
223     }
224   }
225   for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
226     if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
227       v *= aMult[i].iMult;
228       break;
229     }
230   }
231   return isNeg? -v : v;
232 }
233 
234 
235 /*
236 ** Check the filesystem object zPath.  Determine what it is:
237 **
238 **    PATH_DIR     A directory
239 **    PATH_DB      An SQLite database
240 **    PATH_NEXIST  Does not exist
241 **    PATH_OTHER   Something else
242 */
243 #define PATH_DIR     1
244 #define PATH_DB      2
245 #define PATH_NEXIST  0
246 #define PATH_OTHER   99
247 static int pathType(const char *zPath){
248   struct stat x;
249   int rc;
250   if( access(zPath,R_OK) ) return PATH_NEXIST;
251   memset(&x, 0, sizeof(x));
252   rc = stat(zPath, &x);
253   if( rc<0 ) return PATH_OTHER;
254   if( S_ISDIR(x.st_mode) ) return PATH_DIR;
255   if( (x.st_size%512)==0 ) return PATH_DB;
256   return PATH_OTHER;
257 }
258 
259 /*
260 ** Return the size of a file in bytes.  Or return -1 if the
261 ** named object is not a regular file or does not exist.
262 */
263 static sqlite3_int64 fileSize(const char *zPath){
264   struct stat x;
265   int rc;
266   memset(&x, 0, sizeof(x));
267   rc = stat(zPath, &x);
268   if( rc<0 ) return -1;
269   if( !S_ISREG(x.st_mode) ) return -1;
270   return x.st_size;
271 }
272 
273 /*
274 ** A Pseudo-random number generator with a fixed seed.  Use this so
275 ** that the same sequence of "random" numbers are generated on each
276 ** run, for repeatability.
277 */
278 static unsigned int randInt(void){
279   static unsigned int x = 0x333a13cd;
280   static unsigned int y = 0xecb2adea;
281   x = (x>>1) ^ ((1+~(x&1)) & 0xd0000001);
282   y = y*1103515245 + 12345;
283   return x^y;
284 }
285 
286 /*
287 ** Do database initialization.
288 */
289 static int initMain(int argc, char **argv){
290   char *zDb;
291   int i, rc;
292   int nCount = 1000;
293   int sz = 10000;
294   int iVariance = 0;
295   int pgsz = 4096;
296   sqlite3 *db;
297   char *zSql;
298   char *zErrMsg = 0;
299 
300   assert( strcmp(argv[1],"init")==0 );
301   assert( argc>=3 );
302   zDb = argv[2];
303   for(i=3; i<argc; i++){
304     char *z = argv[i];
305     if( z[0]!='-' ) fatalError("unknown argument: \"%s\"", z);
306     if( z[1]=='-' ) z++;
307     if( strcmp(z, "-count")==0 ){
308       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
309       nCount = integerValue(argv[++i]);
310       if( nCount<1 ) fatalError("the --count must be positive");
311       continue;
312     }
313     if( strcmp(z, "-size")==0 ){
314       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
315       sz = integerValue(argv[++i]);
316       if( sz<1 ) fatalError("the --size must be positive");
317       continue;
318     }
319     if( strcmp(z, "-variance")==0 ){
320       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
321       iVariance = integerValue(argv[++i]);
322       continue;
323     }
324     if( strcmp(z, "-pagesize")==0 ){
325       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
326       pgsz = integerValue(argv[++i]);
327       if( pgsz<512 || pgsz>65536 || ((pgsz-1)&pgsz)!=0 ){
328         fatalError("the --pagesize must be power of 2 between 512 and 65536");
329       }
330       continue;
331     }
332     fatalError("unknown option: \"%s\"", argv[i]);
333   }
334   rc = sqlite3_open(zDb, &db);
335   if( rc ){
336     fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
337   }
338   zSql = sqlite3_mprintf(
339     "DROP TABLE IF EXISTS kv;\n"
340     "PRAGMA page_size=%d;\n"
341     "VACUUM;\n"
342     "BEGIN;\n"
343     "CREATE TABLE kv(k INTEGER PRIMARY KEY, v BLOB);\n"
344     "WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<%d)"
345     " INSERT INTO kv(k,v) SELECT x, randomblob(%d+(random()%%(%d))) FROM c;\n"
346     "COMMIT;\n",
347     pgsz, nCount, sz, iVariance+1
348   );
349   rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
350   if( rc ) fatalError("database create failed: %s", zErrMsg);
351   sqlite3_free(zSql);
352   sqlite3_close(db);
353   return 0;
354 }
355 
356 /*
357 ** Analyze an existing database file.  Report its content.
358 */
359 static int statMain(int argc, char **argv){
360   char *zDb;
361   int i, rc;
362   sqlite3 *db;
363   char *zSql;
364   sqlite3_stmt *pStmt;
365 
366   assert( strcmp(argv[1],"stat")==0 );
367   assert( argc>=3 );
368   zDb = argv[2];
369   for(i=3; i<argc; i++){
370     char *z = argv[i];
371     if( z[0]!='-' ) fatalError("unknown argument: \"%s\"", z);
372     if( z[1]=='-' ) z++;
373     fatalError("unknown option: \"%s\"", argv[i]);
374   }
375   rc = sqlite3_open(zDb, &db);
376   if( rc ){
377     fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
378   }
379   zSql = sqlite3_mprintf(
380     "SELECT count(*), min(length(v)), max(length(v)), avg(length(v))"
381     "  FROM kv"
382   );
383   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
384   if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
385   sqlite3_free(zSql);
386   if( sqlite3_step(pStmt)==SQLITE_ROW ){
387     printf("Number of entries:  %8d\n", sqlite3_column_int(pStmt, 0));
388     printf("Average value size: %8d\n", sqlite3_column_int(pStmt, 3));
389     printf("Minimum value size: %8d\n", sqlite3_column_int(pStmt, 1));
390     printf("Maximum value size: %8d\n", sqlite3_column_int(pStmt, 2));
391   }else{
392     printf("No rows\n");
393   }
394   sqlite3_finalize(pStmt);
395   zSql = sqlite3_mprintf("PRAGMA page_size");
396   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
397   if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
398   sqlite3_free(zSql);
399   if( sqlite3_step(pStmt)==SQLITE_ROW ){
400     printf("Page-size:          %8d\n", sqlite3_column_int(pStmt, 0));
401   }
402   sqlite3_finalize(pStmt);
403   zSql = sqlite3_mprintf("PRAGMA page_count");
404   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
405   if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
406   sqlite3_free(zSql);
407   if( sqlite3_step(pStmt)==SQLITE_ROW ){
408     printf("Page-count:         %8d\n", sqlite3_column_int(pStmt, 0));
409   }
410   sqlite3_finalize(pStmt);
411   sqlite3_close(db);
412   return 0;
413 }
414 
415 /*
416 ** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
417 ** is written into file X.  The number of bytes written is returned.  Or
418 ** NULL is returned if something goes wrong, such as being unable to open
419 ** file X for writing.
420 */
421 static void writefileFunc(
422   sqlite3_context *context,
423   int argc,
424   sqlite3_value **argv
425 ){
426   FILE *out;
427   const char *z;
428   sqlite3_int64 rc;
429   const char *zFile;
430 
431   zFile = (const char*)sqlite3_value_text(argv[0]);
432   if( zFile==0 ) return;
433   out = fopen(zFile, "wb");
434   if( out==0 ) return;
435   z = (const char*)sqlite3_value_blob(argv[1]);
436   if( z==0 ){
437     rc = 0;
438   }else{
439     rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
440   }
441   fclose(out);
442   printf("\r%s   ", zFile); fflush(stdout);
443   sqlite3_result_int64(context, rc);
444 }
445 
446 /*
447 **      remember(V,PTR)
448 **
449 ** Return the integer value V.  Also save the value of V in a
450 ** C-language variable whose address is PTR.
451 */
452 static void rememberFunc(
453   sqlite3_context *pCtx,
454   int argc,
455   sqlite3_value **argv
456 ){
457   sqlite3_int64 v;
458   sqlite3_int64 ptr;
459   assert( argc==2 );
460   v = sqlite3_value_int64(argv[0]);
461   ptr = sqlite3_value_int64(argv[1]);
462   *(sqlite3_int64*)SQLITE_INT_TO_PTR(ptr) = v;
463   sqlite3_result_int64(pCtx, v);
464 }
465 
466 /*
467 ** Export the kv table to individual files in the filesystem
468 */
469 static int exportMain(int argc, char **argv){
470   char *zDb;
471   char *zDir;
472   sqlite3 *db;
473   char *zSql;
474   int rc;
475   char *zErrMsg = 0;
476 
477   assert( strcmp(argv[1],"export")==0 );
478   assert( argc>=3 );
479   zDb = argv[2];
480   if( argc!=4 ) fatalError("Usage: kvtest export DATABASE DIRECTORY");
481   zDir = argv[3];
482   if( pathType(zDir)!=PATH_DIR ){
483     fatalError("object \"%s\" is not a directory", zDir);
484   }
485   rc = sqlite3_open(zDb, &db);
486   if( rc ){
487     fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
488   }
489   sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
490                           writefileFunc, 0, 0);
491   zSql = sqlite3_mprintf(
492     "SELECT writefile(printf('%s/%%06d',k),v) FROM kv;",
493     zDir
494   );
495   rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
496   if( rc ) fatalError("database create failed: %s", zErrMsg);
497   sqlite3_free(zSql);
498   sqlite3_close(db);
499   printf("\n");
500   return 0;
501 }
502 
503 /*
504 ** Read the content of file zName into memory obtained from sqlite3_malloc64()
505 ** and return a pointer to the buffer. The caller is responsible for freeing
506 ** the memory.
507 **
508 ** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
509 ** read.
510 **
511 ** For convenience, a nul-terminator byte is always appended to the data read
512 ** from the file before the buffer is returned. This byte is not included in
513 ** the final value of (*pnByte), if applicable.
514 **
515 ** NULL is returned if any error is encountered. The final value of *pnByte
516 ** is undefined in this case.
517 */
518 static unsigned char *readFile(const char *zName, int *pnByte){
519   FILE *in;               /* FILE from which to read content of zName */
520   sqlite3_int64 nIn;      /* Size of zName in bytes */
521   size_t nRead;           /* Number of bytes actually read */
522   unsigned char *pBuf;    /* Content read from disk */
523 
524   nIn = fileSize(zName);
525   if( nIn<0 ) return 0;
526   in = fopen(zName, "rb");
527   if( in==0 ) return 0;
528   pBuf = sqlite3_malloc64( nIn );
529   if( pBuf==0 ) return 0;
530   nRead = fread(pBuf, (size_t)nIn, 1, in);
531   fclose(in);
532   if( nRead!=1 ){
533     sqlite3_free(pBuf);
534     return 0;
535   }
536   if( pnByte ) *pnByte = (int)nIn;
537   return pBuf;
538 }
539 
540 /*
541 ** Overwrite a file with randomness.  Do not change the size of the
542 ** file.
543 */
544 static void updateFile(const char *zName, int *pnByte){
545   FILE *out;              /* FILE from which to read content of zName */
546   sqlite3_int64 sz;       /* Size of zName in bytes */
547   size_t nWritten;        /* Number of bytes actually read */
548   unsigned char *pBuf;    /* Content to store on disk */
549 
550   sz = fileSize(zName);
551   if( sz<0 ){
552     fatalError("No such file: \"%s\"", zName);
553   }
554   *pnByte = (int)sz;
555   if( sz==0 ) return;
556   pBuf = sqlite3_malloc64( sz );
557   if( pBuf==0 ){
558     fatalError("Cannot allocate %lld bytes\n", sz);
559   }
560   sqlite3_randomness((int)sz, pBuf);
561   out = fopen(zName, "wb");
562   if( out==0 ){
563     fatalError("Cannot open \"%s\" for writing\n", zName);
564   }
565   nWritten = fwrite(pBuf, 1, (size_t)sz, out);
566   fclose(out);
567   if( nWritten!=(size_t)sz ){
568     fatalError("Wrote only %d of %d bytes to \"%s\"\n",
569                (int)nWritten, (int)sz, zName);
570   }
571   sqlite3_free(pBuf);
572 }
573 
574 /*
575 ** Return the current time in milliseconds since the beginning of
576 ** the Julian epoch.
577 */
578 static sqlite3_int64 timeOfDay(void){
579   static sqlite3_vfs *clockVfs = 0;
580   sqlite3_int64 t;
581   if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
582   if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
583     clockVfs->xCurrentTimeInt64(clockVfs, &t);
584   }else{
585     double r;
586     clockVfs->xCurrentTime(clockVfs, &r);
587     t = (sqlite3_int64)(r*86400000.0);
588   }
589   return t;
590 }
591 
592 #ifdef __linux__
593 /*
594 ** Attempt to display I/O stats on Linux using /proc/PID/io
595 */
596 static void displayLinuxIoStats(FILE *out){
597   FILE *in;
598   char z[200];
599   sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
600   in = fopen(z, "rb");
601   if( in==0 ) return;
602   while( fgets(z, sizeof(z), in)!=0 ){
603     static const struct {
604       const char *zPattern;
605       const char *zDesc;
606     } aTrans[] = {
607       { "rchar: ",                  "Bytes received by read():" },
608       { "wchar: ",                  "Bytes sent to write():"    },
609       { "syscr: ",                  "Read() system calls:"      },
610       { "syscw: ",                  "Write() system calls:"     },
611       { "read_bytes: ",             "Bytes read from storage:"  },
612       { "write_bytes: ",            "Bytes written to storage:" },
613       { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
614     };
615     int i;
616     for(i=0; i<sizeof(aTrans)/sizeof(aTrans[0]); i++){
617       int n = (int)strlen(aTrans[i].zPattern);
618       if( strncmp(aTrans[i].zPattern, z, n)==0 ){
619         fprintf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
620         break;
621       }
622     }
623   }
624   fclose(in);
625 }
626 #endif
627 
628 /*
629 ** Display memory stats.
630 */
631 static int display_stats(
632   sqlite3 *db,                    /* Database to query */
633   int bReset                      /* True to reset SQLite stats */
634 ){
635   int iCur;
636   int iHiwtr;
637   FILE *out = stdout;
638 
639   fprintf(out, "\n");
640 
641   iHiwtr = iCur = -1;
642   sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
643   fprintf(out,
644           "Memory Used:                         %d (max %d) bytes\n",
645           iCur, iHiwtr);
646   iHiwtr = iCur = -1;
647   sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
648   fprintf(out, "Number of Outstanding Allocations:   %d (max %d)\n",
649           iCur, iHiwtr);
650   iHiwtr = iCur = -1;
651   sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
652   fprintf(out,
653       "Number of Pcache Pages Used:         %d (max %d) pages\n",
654       iCur, iHiwtr);
655   iHiwtr = iCur = -1;
656   sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
657   fprintf(out,
658           "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n",
659           iCur, iHiwtr);
660   iHiwtr = iCur = -1;
661   sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
662   fprintf(out,
663       "Number of Scratch Allocations Used:  %d (max %d)\n",
664       iCur, iHiwtr);
665   iHiwtr = iCur = -1;
666   sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
667   fprintf(out,
668           "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n",
669           iCur, iHiwtr);
670   iHiwtr = iCur = -1;
671   sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
672   fprintf(out, "Largest Allocation:                  %d bytes\n",
673           iHiwtr);
674   iHiwtr = iCur = -1;
675   sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
676   fprintf(out, "Largest Pcache Allocation:           %d bytes\n",
677           iHiwtr);
678   iHiwtr = iCur = -1;
679   sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
680   fprintf(out, "Largest Scratch Allocation:          %d bytes\n",
681           iHiwtr);
682 
683   iHiwtr = iCur = -1;
684   sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
685   fprintf(out, "Pager Heap Usage:                    %d bytes\n",
686       iCur);
687   iHiwtr = iCur = -1;
688   sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
689   fprintf(out, "Page cache hits:                     %d\n", iCur);
690   iHiwtr = iCur = -1;
691   sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
692   fprintf(out, "Page cache misses:                   %d\n", iCur);
693   iHiwtr = iCur = -1;
694   sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
695   fprintf(out, "Page cache writes:                   %d\n", iCur);
696   iHiwtr = iCur = -1;
697 
698 #ifdef __linux__
699   displayLinuxIoStats(out);
700 #endif
701 
702   return 0;
703 }
704 
705 /* Blob access order */
706 #define ORDER_ASC     1
707 #define ORDER_DESC    2
708 #define ORDER_RANDOM  3
709 
710 
711 /*
712 ** Run a performance test
713 */
714 static int runMain(int argc, char **argv){
715   int eType;                  /* Is zDb a database or a directory? */
716   char *zDb;                  /* Database or directory name */
717   int i;                      /* Loop counter */
718   int rc;                     /* Return code from SQLite calls */
719   int nCount = 1000;          /* Number of blob fetch operations */
720   int nExtra = 0;             /* Extra cycles */
721   int iKey = 1;               /* Next blob key */
722   int iMax = 0;               /* Largest allowed key */
723   int iPagesize = 0;          /* Database page size */
724   int iCache = 1000;          /* Database cache size in kibibytes */
725   int bBlobApi = 0;           /* Use the incremental blob I/O API */
726   int bStats = 0;             /* Print stats before exiting */
727   int eOrder = ORDER_ASC;     /* Access order */
728   int isUpdateTest = 0;       /* Do in-place updates rather than reads */
729   int doIntegrityCk = 0;      /* Run PRAGMA integrity_check after the test */
730   int noSync = 0;             /* Disable synchronous mode */
731   sqlite3 *db = 0;            /* Database connection */
732   sqlite3_stmt *pStmt = 0;    /* Prepared statement for SQL access */
733   sqlite3_blob *pBlob = 0;    /* Handle for incremental Blob I/O */
734   sqlite3_int64 tmStart;      /* Start time */
735   sqlite3_int64 tmElapsed;    /* Elapsed time */
736   int mmapSize = 0;           /* --mmap N argument */
737   int nData = 0;              /* Bytes of data */
738   sqlite3_int64 nTotal = 0;   /* Total data read */
739   unsigned char *pData = 0;   /* Content of the blob */
740   int nAlloc = 0;             /* Space allocated for pData[] */
741   const char *zJMode = 0;     /* Journal mode */
742 
743 
744   assert( strcmp(argv[1],"run")==0 );
745   assert( argc>=3 );
746   zDb = argv[2];
747   eType = pathType(zDb);
748   if( eType==PATH_OTHER ) fatalError("unknown object type: \"%s\"", zDb);
749   if( eType==PATH_NEXIST ) fatalError("object does not exist: \"%s\"", zDb);
750   for(i=3; i<argc; i++){
751     char *z = argv[i];
752     if( z[0]!='-' ) fatalError("unknown argument: \"%s\"", z);
753     if( z[1]=='-' ) z++;
754     if( strcmp(z, "-count")==0 ){
755       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
756       nCount = integerValue(argv[++i]);
757       if( nCount<1 ) fatalError("the --count must be positive");
758       continue;
759     }
760     if( strcmp(z, "-mmap")==0 ){
761       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
762       mmapSize = integerValue(argv[++i]);
763       if( nCount<0 ) fatalError("the --mmap must be non-negative");
764       continue;
765     }
766     if( strcmp(z, "-max-id")==0 ){
767       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
768       iMax = integerValue(argv[++i]);
769       continue;
770     }
771     if( strcmp(z, "-start")==0 ){
772       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
773       iKey = integerValue(argv[++i]);
774       if( iKey<1 ) fatalError("the --start must be positive");
775       continue;
776     }
777     if( strcmp(z, "-cache-size")==0 ){
778       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
779       iCache = integerValue(argv[++i]);
780       continue;
781     }
782     if( strcmp(z, "-jmode")==0 ){
783       if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
784       zJMode = argv[++i];
785       continue;
786     }
787     if( strcmp(z, "-random")==0 ){
788       eOrder = ORDER_RANDOM;
789       continue;
790     }
791     if( strcmp(z, "-asc")==0 ){
792       eOrder = ORDER_ASC;
793       continue;
794     }
795     if( strcmp(z, "-desc")==0 ){
796       eOrder = ORDER_DESC;
797       continue;
798     }
799     if( strcmp(z, "-blob-api")==0 ){
800       bBlobApi = 1;
801       continue;
802     }
803     if( strcmp(z, "-stats")==0 ){
804       bStats = 1;
805       continue;
806     }
807     if( strcmp(z, "-update")==0 ){
808       isUpdateTest = 1;
809       continue;
810     }
811     if( strcmp(z, "-integrity-check")==0 ){
812       doIntegrityCk = 1;
813       continue;
814     }
815     if( strcmp(z, "-nosync")==0 ){
816       noSync = 1;
817       continue;
818     }
819     fatalError("unknown option: \"%s\"", argv[i]);
820   }
821   if( eType==PATH_DB ){
822     /* Recover any prior crashes prior to starting the timer */
823     sqlite3_open(zDb, &db);
824     sqlite3_exec(db, "SELECT rowid FROM sqlite_master LIMIT 1", 0, 0, 0);
825     sqlite3_close(db);
826   }
827   tmStart = timeOfDay();
828   if( eType==PATH_DB ){
829     char *zSql;
830     rc = sqlite3_open(zDb, &db);
831     if( rc ){
832       fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
833     }
834     zSql = sqlite3_mprintf("PRAGMA mmap_size=%d", mmapSize);
835     sqlite3_exec(db, zSql, 0, 0, 0);
836     sqlite3_free(zSql);
837     zSql = sqlite3_mprintf("PRAGMA cache_size=%d", iCache);
838     sqlite3_exec(db, zSql, 0, 0, 0);
839     sqlite3_free(zSql);
840     if( noSync ){
841       sqlite3_exec(db, "PRAGMA synchronous=OFF", 0, 0, 0);
842     }
843     pStmt = 0;
844     sqlite3_prepare_v2(db, "PRAGMA page_size", -1, &pStmt, 0);
845     if( sqlite3_step(pStmt)==SQLITE_ROW ){
846       iPagesize = sqlite3_column_int(pStmt, 0);
847     }
848     sqlite3_finalize(pStmt);
849     sqlite3_prepare_v2(db, "PRAGMA cache_size", -1, &pStmt, 0);
850     if( sqlite3_step(pStmt)==SQLITE_ROW ){
851       iCache = sqlite3_column_int(pStmt, 0);
852     }else{
853       iCache = 0;
854     }
855     sqlite3_finalize(pStmt);
856     pStmt = 0;
857     if( zJMode ){
858       zSql = sqlite3_mprintf("PRAGMA journal_mode=%Q", zJMode);
859       sqlite3_exec(db, zSql, 0, 0, 0);
860       sqlite3_free(zSql);
861     }
862     sqlite3_prepare_v2(db, "PRAGMA journal_mode", -1, &pStmt, 0);
863     if( sqlite3_step(pStmt)==SQLITE_ROW ){
864       zJMode = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
865     }else{
866       zJMode = "???";
867     }
868     sqlite3_finalize(pStmt);
869     if( iMax<=0 ){
870       sqlite3_prepare_v2(db, "SELECT max(k) FROM kv", -1, &pStmt, 0);
871       if( sqlite3_step(pStmt)==SQLITE_ROW ){
872         iMax = sqlite3_column_int(pStmt, 0);
873       }
874       sqlite3_finalize(pStmt);
875     }
876     pStmt = 0;
877     sqlite3_exec(db, "BEGIN", 0, 0, 0);
878   }
879   if( iMax<=0 ) iMax = 1000;
880   for(i=0; i<nCount; i++){
881     if( eType==PATH_DIR ){
882       /* CASE 1: Reading blobs out of separate files */
883       char *zKey;
884       zKey = sqlite3_mprintf("%s/%06d", zDb, iKey);
885       nData = 0;
886       if( isUpdateTest ){
887         updateFile(zKey, &nData);
888       }else{
889         pData = readFile(zKey, &nData);
890         sqlite3_free(pData);
891       }
892       sqlite3_free(zKey);
893     }else if( bBlobApi ){
894       /* CASE 2: Reading from database using the incremental BLOB I/O API */
895       if( pBlob==0 ){
896         rc = sqlite3_blob_open(db, "main", "kv", "v", iKey,
897                                isUpdateTest, &pBlob);
898         if( rc ){
899           fatalError("could not open sqlite3_blob handle: %s",
900                      sqlite3_errmsg(db));
901         }
902       }else{
903         rc = sqlite3_blob_reopen(pBlob, iKey);
904       }
905       if( rc==SQLITE_OK ){
906         nData = sqlite3_blob_bytes(pBlob);
907         if( nAlloc<nData+1 ){
908           nAlloc = nData+100;
909           pData = sqlite3_realloc(pData, nAlloc);
910         }
911         if( pData==0 ) fatalError("cannot allocate %d bytes", nData+1);
912         if( isUpdateTest ){
913           sqlite3_randomness((int)nData, pData);
914           rc = sqlite3_blob_write(pBlob, pData, nData, 0);
915           if( rc!=SQLITE_OK ){
916             fatalError("could not write the blob at %d: %s", iKey,
917                       sqlite3_errmsg(db));
918           }
919         }else{
920           rc = sqlite3_blob_read(pBlob, pData, nData, 0);
921           if( rc!=SQLITE_OK ){
922             fatalError("could not read the blob at %d: %s", iKey,
923                       sqlite3_errmsg(db));
924           }
925         }
926       }
927     }else{
928       /* CASE 3: Reading from database using SQL */
929       if( pStmt==0 ){
930         if( isUpdateTest ){
931           sqlite3_create_function(db, "remember", 2, SQLITE_UTF8, 0,
932                                   rememberFunc, 0, 0);
933 
934           rc = sqlite3_prepare_v2(db,
935             "UPDATE kv SET v=randomblob(remember(length(v),?2))"
936             " WHERE k=?1", -1, &pStmt, 0);
937           sqlite3_bind_int64(pStmt, 2, SQLITE_PTR_TO_INT(&nData));
938         }else{
939           rc = sqlite3_prepare_v2(db,
940                  "SELECT v FROM kv WHERE k=?1", -1, &pStmt, 0);
941         }
942         if( rc ){
943           fatalError("cannot prepare query: %s", sqlite3_errmsg(db));
944         }
945       }else{
946         sqlite3_reset(pStmt);
947       }
948       sqlite3_bind_int(pStmt, 1, iKey);
949       nData = 0;
950       rc = sqlite3_step(pStmt);
951       if( rc==SQLITE_ROW ){
952         nData = sqlite3_column_bytes(pStmt, 0);
953         pData = (unsigned char*)sqlite3_column_blob(pStmt, 0);
954       }
955     }
956     if( eOrder==ORDER_ASC ){
957       iKey++;
958       if( iKey>iMax ) iKey = 1;
959     }else if( eOrder==ORDER_DESC ){
960       iKey--;
961       if( iKey<=0 ) iKey = iMax;
962     }else{
963       iKey = (randInt()%iMax)+1;
964     }
965     nTotal += nData;
966     if( nData==0 ){ nCount++; nExtra++; }
967   }
968   if( nAlloc ) sqlite3_free(pData);
969   if( pStmt ) sqlite3_finalize(pStmt);
970   if( pBlob ) sqlite3_blob_close(pBlob);
971   if( bStats ){
972     display_stats(db, 0);
973   }
974   if( db ){
975     sqlite3_exec(db, "COMMIT", 0, 0, 0);
976     sqlite3_close(db);
977   }
978   tmElapsed = timeOfDay() - tmStart;
979   if( nExtra ){
980     printf("%d cycles due to %d misses\n", nCount, nExtra);
981   }
982   if( eType==PATH_DB ){
983     printf("SQLite version: %s\n", sqlite3_libversion());
984     if( doIntegrityCk ){
985       sqlite3_open(zDb, &db);
986       sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &pStmt, 0);
987       while( sqlite3_step(pStmt)==SQLITE_ROW ){
988         printf("integrity-check: %s\n", sqlite3_column_text(pStmt, 0));
989       }
990       sqlite3_finalize(pStmt);
991       sqlite3_close(db);
992     }
993   }
994   printf("--count %d --max-id %d", nCount-nExtra, iMax);
995   switch( eOrder ){
996     case ORDER_RANDOM:  printf(" --random\n");  break;
997     case ORDER_DESC:    printf(" --desc\n");    break;
998     default:            printf(" --asc\n");     break;
999   }
1000   if( eType==PATH_DB ){
1001     printf("--cache-size %d --jmode %s\n", iCache, zJMode);
1002     printf("--mmap %d%s\n", mmapSize, bBlobApi ? " --blob-api" : "");
1003     if( noSync ) printf("--nosync\n");
1004   }
1005   if( iPagesize ) printf("Database page size: %d\n", iPagesize);
1006   printf("Total elapsed time: %.3f\n", tmElapsed/1000.0);
1007   if( isUpdateTest ){
1008     printf("Microseconds per BLOB write: %.3f\n", tmElapsed*1000.0/nCount);
1009     printf("Content write rate: %.1f MB/s\n", nTotal/(1000.0*tmElapsed));
1010   }else{
1011     printf("Microseconds per BLOB read: %.3f\n", tmElapsed*1000.0/nCount);
1012     printf("Content read rate: %.1f MB/s\n", nTotal/(1000.0*tmElapsed));
1013   }
1014   return 0;
1015 }
1016 
1017 
1018 int main(int argc, char **argv){
1019   if( argc<3 ) showHelp();
1020   if( strcmp(argv[1],"init")==0 ){
1021     return initMain(argc, argv);
1022   }
1023   if( strcmp(argv[1],"export")==0 ){
1024     return exportMain(argc, argv);
1025   }
1026   if( strcmp(argv[1],"run")==0 ){
1027     return runMain(argc, argv);
1028   }
1029   if( strcmp(argv[1],"stat")==0 ){
1030     return statMain(argc, argv);
1031   }
1032   showHelp();
1033   return 0;
1034 }
1035