1/*
2** Performance test for SQLite.
3**
4** This program reads ASCII text from a file named on the command-line
5** and submits that text  to SQLite for evaluation.  A new database
6** is created at the beginning of the program.  All statements are
7** timed using the high-resolution timer built into Intel-class processors.
8**
9** To compile this program, first compile the SQLite library separately
10** will full optimizations.  For example:
11**
12**     gcc -c -O6 -DSQLITE_THREADSAFE=0 sqlite3.c
13**
14** Then link against this program.  But to do optimize this program
15** because that defeats the hi-res timer.
16**
17**     gcc speedtest8.c sqlite3.o -ldl -I../src
18**
19** Then run this program with a single argument which is the name of
20** a file containing SQL script that you want to test:
21**
22**     ./a.out test.db  test.sql
23*/
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <ctype.h>
28#include <unistd.h>
29#include <stdarg.h>
30#include "sqlite3.h"
31
32#include "test_osinst.c"
33
34/*
35** Prepare and run a single statement of SQL.
36*/
37static void prepareAndRun(sqlite3_vfs *pInstVfs, sqlite3 *db, const char *zSql){
38  sqlite3_stmt *pStmt;
39  const char *stmtTail;
40  int rc;
41  char zMessage[1024];
42  zMessage[1023] = '\0';
43
44  sqlite3_uint64 iTime;
45
46  sqlite3_snprintf(1023, zMessage, "sqlite3_prepare_v2: %s", zSql);
47  sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage);
48
49  iTime = sqlite3Hwtime();
50  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &stmtTail);
51  iTime = sqlite3Hwtime() - iTime;
52  sqlite3_instvfs_binarylog_call(pInstVfs,BINARYLOG_PREPARE_V2,iTime,rc,zSql);
53
54  if( rc==SQLITE_OK ){
55    int nRow = 0;
56
57    sqlite3_snprintf(1023, zMessage, "sqlite3_step loop: %s", zSql);
58    sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage);
59    iTime = sqlite3Hwtime();
60    while( (rc=sqlite3_step(pStmt))==SQLITE_ROW ){ nRow++; }
61    iTime = sqlite3Hwtime() - iTime;
62    sqlite3_instvfs_binarylog_call(pInstVfs, BINARYLOG_STEP, iTime, rc, zSql);
63
64    sqlite3_snprintf(1023, zMessage, "sqlite3_finalize: %s", zSql);
65    sqlite3_instvfs_binarylog_marker(pInstVfs, zMessage);
66    iTime = sqlite3Hwtime();
67    rc = sqlite3_finalize(pStmt);
68    iTime = sqlite3Hwtime() - iTime;
69    sqlite3_instvfs_binarylog_call(pInstVfs, BINARYLOG_FINALIZE, iTime, rc, zSql);
70  }
71}
72
73static int stringcompare(const char *zLeft, const char *zRight){
74  int ii;
75  for(ii=0; zLeft[ii] && zRight[ii]; ii++){
76    if( zLeft[ii]!=zRight[ii] ) return 0;
77  }
78  return( zLeft[ii]==zRight[ii] );
79}
80
81static char *readScriptFile(const char *zFile, int *pnScript){
82  sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
83  sqlite3_file *p;
84  int rc;
85  sqlite3_int64 nByte;
86  char *zData = 0;
87  int flags = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_DB;
88
89  p = (sqlite3_file *)malloc(pVfs->szOsFile);
90  rc = pVfs->xOpen(pVfs, zFile, p, flags, &flags);
91  if( rc!=SQLITE_OK ){
92    goto error_out;
93  }
94
95  rc = p->pMethods->xFileSize(p, &nByte);
96  if( rc!=SQLITE_OK ){
97    goto close_out;
98  }
99
100  zData = (char *)malloc(nByte+1);
101  rc = p->pMethods->xRead(p, zData, nByte, 0);
102  if( rc!=SQLITE_OK ){
103    goto close_out;
104  }
105  zData[nByte] = '\0';
106
107  p->pMethods->xClose(p);
108  free(p);
109  *pnScript = nByte;
110  return zData;
111
112close_out:
113  p->pMethods->xClose(p);
114
115error_out:
116  free(p);
117  free(zData);
118  return 0;
119}
120
121int main(int argc, char **argv){
122
123  const char zUsageMsg[] =
124    "Usage: %s options...\n"
125    "  where available options are:\n"
126    "\n"
127    "    -db      DATABASE-FILE  (database file to operate on)\n"
128    "    -script  SCRIPT-FILE    (script file to read sql from)\n"
129    "    -log     LOG-FILE       (log file to create)\n"
130    "    -logdata                (log all data to log file)\n"
131    "\n"
132    "  Options -db, -script and -log are compulsory\n"
133    "\n"
134  ;
135
136  const char *zDb = 0;
137  const char *zScript = 0;
138  const char *zLog = 0;
139  int logdata = 0;
140
141  int ii;
142  int i, j;
143  int rc;
144
145  sqlite3_vfs *pInstVfs;                 /* Instrumentation VFS */
146
147  char *zSql = 0;
148  int nSql;
149
150  sqlite3 *db;
151
152  for(ii=1; ii<argc; ii++){
153    if( stringcompare("-db", argv[ii]) && (ii+1)<argc ){
154      zDb = argv[++ii];
155    }
156
157    else if( stringcompare("-script", argv[ii]) && (ii+1)<argc ){
158      zScript = argv[++ii];
159    }
160
161    else if( stringcompare("-log", argv[ii]) && (ii+1)<argc ){
162      zLog = argv[++ii];
163    }
164
165    else if( stringcompare("-logdata", argv[ii]) ){
166      logdata = 1;
167    }
168
169    else {
170      goto usage;
171    }
172  }
173  if( !zDb || !zScript || !zLog ) goto usage;
174
175  zSql = readScriptFile(zScript, &nSql);
176  if( !zSql ){
177    fprintf(stderr, "Failed to read script file\n");
178    return -1;
179  }
180
181  pInstVfs = sqlite3_instvfs_binarylog("logging", 0, zLog, logdata);
182
183  rc = sqlite3_open_v2(
184     zDb, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "logging"
185  );
186  if( rc!=SQLITE_OK ){
187    fprintf(stderr, "Failed to open db: %s\n", sqlite3_errmsg(db));
188    return -2;
189  }
190
191  for(i=j=0; j<nSql; j++){
192    if( zSql[j]==';' ){
193      int isComplete;
194      char c = zSql[j+1];
195      zSql[j+1] = 0;
196      isComplete = sqlite3_complete(&zSql[i]);
197      zSql[j+1] = c;
198      if( isComplete ){
199        zSql[j] = 0;
200        while( i<j && isspace(zSql[i]) ){ i++; }
201        if( i<j ){
202          prepareAndRun(pInstVfs, db, &zSql[i]);
203        }
204        zSql[j] = ';';
205        i = j+1;
206      }
207    }
208  }
209
210  sqlite3_instvfs_destroy(pInstVfs);
211  return 0;
212
213usage:
214  fprintf(stderr, zUsageMsg, argv[0]);
215  return -3;
216}
217