SQLite

Check-in [a1c071ea18]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:If compiled with the -DVDBE_PROFILE=1 option, special code is inserted that uses the pentium RDTSC instruction to compute very precise runtimes on all VDBE opcodes. (This only works on i586 processors, of course.) The results are written into the vdbe_profile.out file for analysis. Hopefully, this new feature will reveal hot spots that can be optimized to make the VDBE run faster. (CVS 807)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a1c071ea18766932c90275c704e078134c67be68
User & Date: drh 2003-01-01 23:06:21.000
Context
2003-01-02
14:43
Code optimizations to help the library run faster. (CVS 808) (check-in: db745e87dc user: drh tags: trunk)
2003-01-01
23:06
If compiled with the -DVDBE_PROFILE=1 option, special code is inserted that uses the pentium RDTSC instruction to compute very precise runtimes on all VDBE opcodes. (This only works on i586 processors, of course.) The results are written into the vdbe_profile.out file for analysis. Hopefully, this new feature will reveal hot spots that can be optimized to make the VDBE run faster. (CVS 807) (check-in: a1c071ea18 user: drh tags: trunk)
2002-12-28
01:26
Version 2.7.5 (CVS 806) (check-in: ee95eefe12 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.187 2002/12/04 22:29:29 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.188 2003/01/01 23:06:21 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
      break;
    }
  }
  zBuf[i]  = 0;
  return i>0 ? zBuf : 0;
}

#ifndef NDEBUG
/*
** Print a single opcode.  This routine is used for debugging only.
*/
static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){
  char *zP3;
  char zPtr[40];
  if( pOp->p3type==P3_POINTER ){







|







1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
      break;
    }
  }
  zBuf[i]  = 0;
  return i>0 ? zBuf : 0;
}

#if !defined(NDEBUG) || defined(VDBE_PROFILE)
/*
** Print a single opcode.  This routine is used for debugging only.
*/
static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){
  char *zP3;
  char zPtr[40];
  if( pOp->p3type==P3_POINTER ){
1333
1334
1335
1336
1337
1338
1339
















1340
1341
1342
1343
1344
1345
1346
    if( aCsr==0 ) return 1;
    p->aCsr = aCsr;
    memset(&p->aCsr[p->nCursor], 0, sizeof(Cursor)*(mxCursor+1-p->nCursor));
    p->nCursor = mxCursor+1;
  }
  return 0;
}

















/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
    if( aCsr==0 ) return 1;
    p->aCsr = aCsr;
    memset(&p->aCsr[p->nCursor], 0, sizeof(Cursor)*(mxCursor+1-p->nCursor));
    p->nCursor = mxCursor+1;
  }
  return 0;
}

#ifdef VDBE_PROFILE
/*
** The following routine only works on pentium-class processors.
** It uses the RDTSC opcode to read cycle count value out of the
** processor and returns that value.  This can be used for high-res
** profiling.
*/
__inline__ unsigned long long int hwtime(void){
  unsigned long long int x;
  __asm__("rdtsc\n\t"
          "mov %%edx, %%ecx\n\t"
          :"=A" (x));
  return x;
}
#endif

/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.
1382
1383
1384
1385
1386
1387
1388



1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401









1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416



1417
1418
1419
1420
1421
1422
1423
  unsigned uniqueCnt = 0;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction = OE_Abort; /* Recovery action to do in case of an error */
  int undoTransOnError = 0;   /* If error, either ROLLBACK or COMMIT */
  int inTempTrans = 0;        /* True if temp database is transactioned */
  char zBuf[100];             /* Space to sprintf() an integer */
  int returnStack[100];     /* Return address stack for OP_Gosub & OP_Return */
  int returnDepth = 0;      /* Next unused element in returnStack[] */





  /* No instruction ever pushes more than a single element onto the
  ** stack.  And the stack never grows on successive executions of the
  ** same loop.  So the total number of instructions is an upper bound
  ** on the maximum stack depth required.
  **
  ** Allocation all the stack space we will ever need.
  */
  NeedStack(p, p->nOp);
  zStack = p->zStack;
  aStack = p->aStack;
  p->tos = -1;










  /* Initialize the aggregrate hash table.
  */
  sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
  p->agg.pSearch = 0;

  rc = SQLITE_OK;
#ifdef MEMORY_DEBUG
  if( access("vdbe_trace",0)==0 ){
    p->trace = stdout;
  }
#endif
  if( sqlite_malloc_failed ) goto no_mem;
  for(pc=0; !sqlite_malloc_failed && rc==SQLITE_OK && pc<p->nOp
             VERIFY(&& pc>=0); pc++){



    pOp = &p->aOp[pc];

    /* Interrupt processing if requested.
    */
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;
      if( db->magic!=SQLITE_MAGIC_BUSY ){







>
>
>













>
>
>
>
>
>
>
>
>















>
>
>







1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
  unsigned uniqueCnt = 0;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction = OE_Abort; /* Recovery action to do in case of an error */
  int undoTransOnError = 0;   /* If error, either ROLLBACK or COMMIT */
  int inTempTrans = 0;        /* True if temp database is transactioned */
  char zBuf[100];             /* Space to sprintf() an integer */
  int returnStack[100];     /* Return address stack for OP_Gosub & OP_Return */
  int returnDepth = 0;      /* Next unused element in returnStack[] */
#ifdef VDBE_PROFILE
  unsigned long long start;
#endif


  /* No instruction ever pushes more than a single element onto the
  ** stack.  And the stack never grows on successive executions of the
  ** same loop.  So the total number of instructions is an upper bound
  ** on the maximum stack depth required.
  **
  ** Allocation all the stack space we will ever need.
  */
  NeedStack(p, p->nOp);
  zStack = p->zStack;
  aStack = p->aStack;
  p->tos = -1;
#ifdef VDBE_PROFILE
  {
    int i;
    for(i=0; i<p->nOp; i++){
      p->aOp[i].cnt = 0;
      p->aOp[i].cycles = 0;
    }
  }
#endif

  /* Initialize the aggregrate hash table.
  */
  sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
  p->agg.pSearch = 0;

  rc = SQLITE_OK;
#ifdef MEMORY_DEBUG
  if( access("vdbe_trace",0)==0 ){
    p->trace = stdout;
  }
#endif
  if( sqlite_malloc_failed ) goto no_mem;
  for(pc=0; !sqlite_malloc_failed && rc==SQLITE_OK && pc<p->nOp
             VERIFY(&& pc>=0); pc++){
#ifdef VDBE_PROFILE
    start = hwtime();
#endif
    pOp = &p->aOp[pc];

    /* Interrupt processing if requested.
    */
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;
      if( db->magic!=SQLITE_MAGIC_BUSY ){
4061
4062
4063
4064
4065
4066
4067

4068
4069
4070

4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
** table or index.  If there is no previous key/value pairs then fall through
** to the following instruction.  But if the cursor backup was successful,
** jump immediately to P2.
*/
case OP_Prev:
case OP_Next: {
  int i = pOp->p1;

  BtCursor *pCrsr;

  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){

    int res;
    if( p->aCsr[i].nullRow ){
      res = 1;
    }else{
      rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) :
                                  sqliteBtreePrevious(pCrsr, &res);
      p->aCsr[i].nullRow = res;
    }
    if( res==0 ){
      pc = pOp->p2 - 1;
      sqlite_search_count++;
    }
    p->aCsr[i].recnoIsValid = 0;
  }
  break;
}

/* Opcode: IdxPut P1 P2 P3
**
** The top of the stack hold an SQL index key made using the







>


|
>

|




|





|







4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
** table or index.  If there is no previous key/value pairs then fall through
** to the following instruction.  But if the cursor backup was successful,
** jump immediately to P2.
*/
case OP_Prev:
case OP_Next: {
  int i = pOp->p1;
  Cursor *pC;
  BtCursor *pCrsr;

  if( VERIFY( i>=0 && i<p->nCursor && ) 
      (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
    int res;
    if( pC->nullRow ){
      res = 1;
    }else{
      rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) :
                                  sqliteBtreePrevious(pCrsr, &res);
      pC->nullRow = res;
    }
    if( res==0 ){
      pc = pOp->p2 - 1;
      sqlite_search_count++;
    }
    pC->recnoIsValid = 0;
  }
  break;
}

/* Opcode: IdxPut P1 P2 P3
**
** The top of the stack hold an SQL index key made using the
5316
5317
5318
5319
5320
5321
5322





5323
5324
5325
5326
5327
5328
5329
/*****************************************************************************
** The cases of the switch statement above this line should all be indented
** by 6 spaces.  But the left-most 6 spaces have been removed to improve the
** readability.  From this point on down, the normal indentation rules are
** restored.
*****************************************************************************/
    }






    /* The following code adds nothing to the actual functionality
    ** of the program.  It is only here for testing and debugging.
    ** On the other hand, it does burn CPU cycles every time through
    ** the evaluator loop.  So we can leave it out when NDEBUG is defined.
    */
#ifndef NDEBUG







>
>
>
>
>







5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
/*****************************************************************************
** The cases of the switch statement above this line should all be indented
** by 6 spaces.  But the left-most 6 spaces have been removed to improve the
** readability.  From this point on down, the normal indentation rules are
** restored.
*****************************************************************************/
    }

#ifdef VDBE_PROFILE
    pOp->cycles += hwtime() - start;
    pOp->cnt++;
#endif

    /* The following code adds nothing to the actual functionality
    ** of the program.  It is only here for testing and debugging.
    ** On the other hand, it does burn CPU cycles every time through
    ** the evaluator loop.  So we can leave it out when NDEBUG is defined.
    */
#ifndef NDEBUG
5413
5414
5415
5416
5417
5418
5419






















5420
5421
5422
5423
5424
5425
5426
      }
    }
    sqliteRollbackInternalChanges(db);
  }
  sqliteBtreeCommitCkpt(pBt);
  if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
  assert( p->tos<pc || sqlite_malloc_failed==1 );






















  return rc;

  /* Jump to here if a malloc() fails.  It's hard to get a malloc()
  ** to fail on a modern VM computer, so this code is untested.
  */
no_mem:
  sqliteSetString(pzErrMsg, "out of memory", 0);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
      }
    }
    sqliteRollbackInternalChanges(db);
  }
  sqliteBtreeCommitCkpt(pBt);
  if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
  assert( p->tos<pc || sqlite_malloc_failed==1 );
#ifdef VDBE_PROFILE
  {
    FILE *out = fopen("vdbe_profile.out", "a");
    if( out ){
      int i;
      fprintf(out, "---- ");
      for(i=0; i<p->nOp; i++){
        fprintf(out, "%02x", p->aOp[i].opcode);
      }
      fprintf(out, "\n");
      for(i=0; i<p->nOp; i++){
        fprintf(out, "%6d %10lld %8lld ",
           p->aOp[i].cnt,
           p->aOp[i].cycles,
           p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
        );
        vdbePrintOp(out, i, &p->aOp[i]);
      }
      fclose(out);
    }
  }
#endif
  return rc;

  /* Jump to here if a malloc() fails.  It's hard to get a malloc()
  ** to fail on a modern VM computer, so this code is untested.
  */
no_mem:
  sqliteSetString(pzErrMsg, "out of memory", 0);
Changes to src/vdbe.h.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.60 2002/09/08 00:04:53 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.61 2003/01/01 23:06:21 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
35
36
37
38
39
40
41




42
43
44
45
46
47
48
*/
struct VdbeOp {
  int opcode;         /* What operation to perform */
  int p1;             /* First operand */
  int p2;             /* Second parameter (often the jump destination) */
  char *p3;           /* Third parameter */
  int p3type;         /* P3_STATIC, P3_DYNAMIC or P3_POINTER */




};
typedef struct VdbeOp VdbeOp;

/*
** Allowed values of VdbeOp.p3type
*/
#define P3_NOTUSED    0   /* The P3 parameter is not used */







>
>
>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
*/
struct VdbeOp {
  int opcode;         /* What operation to perform */
  int p1;             /* First operand */
  int p2;             /* Second parameter (often the jump destination) */
  char *p3;           /* Third parameter */
  int p3type;         /* P3_STATIC, P3_DYNAMIC or P3_POINTER */
#ifdef VDBE_PROFILE
  int cnt;            /* Number of times this instruction was executed */
  long long cycles;   /* Total time spend executing this instruction */
#endif
};
typedef struct VdbeOp VdbeOp;

/*
** Allowed values of VdbeOp.p3type
*/
#define P3_NOTUSED    0   /* The P3 parameter is not used */