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