When constructing records and index keys, use static string space rather than

mallocing (when possible) for a small speed improvement. (CVS 817)

FossilOrigin-Name: 657c9fb5133aef93e4edd433912e6942ad9674ec
This commit is contained in:
drh 2003-01-07 13:43:45 +00:00
parent caec2f12a9
commit 371ac44d1c
3 changed files with 91 additions and 43 deletions

View File

@ -1,5 +1,5 @@
C More\soptimizations.\s(CVS\s816) C When\sconstructing\srecords\sand\sindex\skeys,\suse\sstatic\sstring\sspace\srather\sthan\nmallocing\s(when\spossible)\sfor\sa\ssmall\sspeed\simprovement.\s(CVS\s817)
D 2003-01-07T02:47:48 D 2003-01-07T13:43:46
F Makefile.in 868c17a1ae1c07603d491274cc8f86c04acf2a1e F Makefile.in 868c17a1ae1c07603d491274cc8f86c04acf2a1e
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -52,7 +52,7 @@ F src/tokenize.c 7ac1c33e0149647c9eb5959c48992df6906d4809
F src/trigger.c 5ba917fc226b96065108da28186c2efaec53e481 F src/trigger.c 5ba917fc226b96065108da28186c2efaec53e481
F src/update.c 881e4c8e7c786545da4fd2d95da19252b2e31137 F src/update.c 881e4c8e7c786545da4fd2d95da19252b2e31137
F src/util.c e2d108842e02810d3d3242cac0e024b09cdb3c4a F src/util.c e2d108842e02810d3d3242cac0e024b09cdb3c4a
F src/vdbe.c a92cbde50ab9ddd6eeee086531252211ce00e3f9 F src/vdbe.c 07570003d3378b668408d8e54f4b137a12ca4df6
F src/vdbe.h 754eba497cfe0c3e352b9c101ab2f811f10d0a55 F src/vdbe.h 754eba497cfe0c3e352b9c101ab2f811f10d0a55
F src/where.c af235636b7bc7f7f42ee1c7162d1958ad0102cab F src/where.c af235636b7bc7f7f42ee1c7162d1958ad0102cab
F test/all.test 873d30e25a41b3aa48fec5633a7ec1816e107029 F test/all.test 873d30e25a41b3aa48fec5633a7ec1816e107029
@ -152,7 +152,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 032b3daa1d3cf3e00a4a6ba0b09624f1aba6445c P a362981b20fd33254ad498619eedf75b576682e3
R 049c740e00e3ae1c8ab222520497ef43 R 167f2117e4d0226460f1cb7008234b4d
U drh U drh
Z e3868eb77f429973c82f0ac95cfb0d3a Z 09ee972659cfc232fea37abfb187e33e

View File

@ -1 +1 @@
a362981b20fd33254ad498619eedf75b576682e3 657c9fb5133aef93e4edd433912e6942ad9674ec

View File

@ -36,7 +36,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.192 2003/01/07 02:47:48 drh Exp $ ** $Id: vdbe.c,v 1.193 2003/01/07 13:43:46 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -776,14 +776,11 @@ static AggElem *_AggInFocus(Agg *p){
/* /*
** Convert the given stack entity into a string if it isn't one ** Convert the given stack entity into a string if it isn't one
** already. Return non-zero if we run out of memory. ** already.
**
** NULLs are converted into an empty string.
*/ */
#define Stringify(P,I) ((aStack[I].flags & STK_Str)==0 ? hardStringify(P,I) : 0) #define Stringify(P,I) if((aStack[I].flags & STK_Str)==0){hardStringify(P,I);}
static int hardStringify(Vdbe *p, int i){ static int hardStringify(Vdbe *p, int i){
Stack *pStack = &p->aStack[i]; Stack *pStack = &p->aStack[i];
char **pzStack = &p->zStack[i];
int fg = pStack->flags; int fg = pStack->flags;
if( fg & STK_Real ){ if( fg & STK_Real ){
sprintf(pStack->z,"%.15g",pStack->r); sprintf(pStack->z,"%.15g",pStack->r);
@ -792,12 +789,36 @@ static int hardStringify(Vdbe *p, int i){
}else{ }else{
pStack->z[0] = 0; pStack->z[0] = 0;
} }
*pzStack = pStack->z; p->zStack[i] = pStack->z;
pStack->n = strlen(*pzStack)+1; pStack->n = strlen(pStack->z)+1;
pStack->flags = STK_Str; pStack->flags = STK_Str;
return 0; return 0;
} }
/*
** Convert the given stack entity into a string that has been obtained
** from sqliteMalloc(). This is different from Stringify() above in that
** Stringify() will use the NBFS bytes of static string space if the string
** will fit but this routine always mallocs for space.
** Return non-zero if we run out of memory.
*/
#define Dynamicify(P,I) ((aStack[I].flags & STK_Dyn)==0 ? hardDynamicify(P,I):0)
static int hardDynamicify(Vdbe *p, int i){
Stack *pStack = &p->aStack[i];
int fg = pStack->flags;
char *z;
if( (fg & STK_Str)==0 ){
hardStringify(p, i);
}
assert( (fg & STK_Dyn)==0 );
z = sqliteMallocRaw( pStack->n );
if( z==0 ) return 1;
memcpy(z, p->zStack[i], pStack->n);
p->zStack[i] = z;
pStack->flags |= STK_Dyn;
return 0;
}
/* /*
** An ephemeral string value (signified by the STK_Ephem flag) contains ** An ephemeral string value (signified by the STK_Ephem flag) contains
** a pointer to a dynamically allocated string where some other entity ** a pointer to a dynamically allocated string where some other entity
@ -1740,7 +1761,7 @@ case OP_Callback: {
if( aStack[j].flags & STK_Null ){ if( aStack[j].flags & STK_Null ){
zStack[j] = 0; zStack[j] = 0;
}else{ }else{
if( Stringify(p, j) ) goto no_mem; Stringify(p, j);
} }
} }
zStack[p->tos+1] = 0; zStack[p->tos+1] = 0;
@ -1817,7 +1838,7 @@ case OP_Concat: {
nByte = -1; nByte = -1;
break; break;
}else{ }else{
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
nByte += aStack[i].n - 1 + nSep; nByte += aStack[i].n - 1 + nSep;
} }
} }
@ -1987,7 +2008,7 @@ case OP_Function: {
if( aStack[i].flags & STK_Null ){ if( aStack[i].flags & STK_Null ){
zStack[i] = 0; zStack[i] = 0;
}else{ }else{
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
} }
} }
ctx.pFunc = (FuncDef*)pOp->p3; ctx.pFunc = (FuncDef*)pOp->p3;
@ -2283,7 +2304,8 @@ case OP_Ge: {
aStack[tos].flags = STK_Int; aStack[tos].flags = STK_Int;
c = aStack[nos].i - aStack[tos].i; c = aStack[nos].i - aStack[tos].i;
}else{ }else{
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; Stringify(p, tos);
Stringify(p, nos);
c = sqliteCompare(zStack[nos], zStack[tos]); c = sqliteCompare(zStack[nos], zStack[tos]);
} }
switch( pOp->opcode ){ switch( pOp->opcode ){
@ -2433,7 +2455,8 @@ case OP_StrGe: {
} }
break; break;
}else{ }else{
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; Stringify(p, tos);
Stringify(p, nos);
c = strcmp(zStack[nos], zStack[tos]); c = strcmp(zStack[nos], zStack[tos]);
} }
/* The asserts on each case of the following switch are there to verify /* The asserts on each case of the following switch are there to verify
@ -2694,6 +2717,7 @@ case OP_MakeRecord: {
u32 addr; u32 addr;
int addUnique = 0; /* True to cause bytes to be added to make the int addUnique = 0; /* True to cause bytes to be added to make the
** generated record distinct */ ** generated record distinct */
char zTemp[NBFS]; /* Temp space for small records */
/* Assuming the record contains N fields, the record format looks /* Assuming the record contains N fields, the record format looks
** like this: ** like this:
@ -2720,7 +2744,7 @@ case OP_MakeRecord: {
if( (aStack[i].flags & STK_Null) ){ if( (aStack[i].flags & STK_Null) ){
addUnique = pOp->p2; addUnique = pOp->p2;
}else{ }else{
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
nByte += aStack[i].n; nByte += aStack[i].n;
} }
} }
@ -2737,8 +2761,12 @@ case OP_MakeRecord: {
rc = SQLITE_TOOBIG; rc = SQLITE_TOOBIG;
goto abort_due_to_error; goto abort_due_to_error;
} }
if( nByte<=NBFS ){
zNewRecord = zTemp;
}else{
zNewRecord = sqliteMallocRaw( nByte ); zNewRecord = sqliteMallocRaw( nByte );
if( zNewRecord==0 ) goto no_mem; if( zNewRecord==0 ) goto no_mem;
}
j = 0; j = 0;
addr = idxWidth*(nField+1) + addUnique*sizeof(uniqueCnt); addr = idxWidth*(nField+1) + addUnique*sizeof(uniqueCnt);
for(i=p->tos-nField+1; i<=p->tos; i++){ for(i=p->tos-nField+1; i<=p->tos; i++){
@ -2774,8 +2802,16 @@ case OP_MakeRecord: {
PopStack(p, nField); PopStack(p, nField);
p->tos++; p->tos++;
aStack[p->tos].n = nByte; aStack[p->tos].n = nByte;
if( nByte<=NBFS ){
assert( zNewRecord==zTemp );
memcpy(aStack[p->tos].z, zTemp, nByte);
zStack[p->tos] = aStack[p->tos].z;
aStack[p->tos].flags = STK_Str;
}else{
assert( zNewRecord!=zTemp );
aStack[p->tos].flags = STK_Str | STK_Dyn; aStack[p->tos].flags = STK_Str | STK_Dyn;
zStack[p->tos] = zNewRecord; zStack[p->tos] = zNewRecord;
}
break; break;
} }
@ -2851,6 +2887,7 @@ case OP_MakeKey: {
int addRowid; int addRowid;
int i, j; int i, j;
int containsNull = 0; int containsNull = 0;
char zTemp[NBFS];
addRowid = pOp->opcode==OP_MakeIdxKey; addRowid = pOp->opcode==OP_MakeIdxKey;
nField = pOp->p1; nField = pOp->p1;
@ -2890,8 +2927,12 @@ case OP_MakeKey: {
goto abort_due_to_error; goto abort_due_to_error;
} }
if( addRowid ) nByte += sizeof(u32); if( addRowid ) nByte += sizeof(u32);
if( nByte<=NBFS ){
zNewKey = zTemp;
}else{
zNewKey = sqliteMallocRaw( nByte ); zNewKey = sqliteMallocRaw( nByte );
if( zNewKey==0 ) goto no_mem; if( zNewKey==0 ) goto no_mem;
}
j = 0; j = 0;
for(i=p->tos-nField+1; i<=p->tos; i++){ for(i=p->tos-nField+1; i<=p->tos; i++){
if( aStack[i].flags & STK_Null ){ if( aStack[i].flags & STK_Null ){
@ -2919,8 +2960,15 @@ case OP_MakeKey: {
} }
p->tos++; p->tos++;
aStack[p->tos].n = nByte; aStack[p->tos].n = nByte;
if( nByte<=NBFS ){
assert( zNewKey==zTemp );
zStack[p->tos] = aStack[p->tos].z;
memcpy(zStack[p->tos], zTemp, nByte);
aStack[p->tos].flags = STK_Str;
}else{
aStack[p->tos].flags = STK_Str|STK_Dyn; aStack[p->tos].flags = STK_Str|STK_Dyn;
zStack[p->tos] = zNewKey; zStack[p->tos] = zNewKey;
}
break; break;
} }
@ -2936,7 +2984,7 @@ case OP_IncrKey: {
int tos = p->tos; int tos = p->tos;
VERIFY( if( tos<0 ) goto bad_instruction ); VERIFY( if( tos<0 ) goto bad_instruction );
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
if( aStack[tos].flags & (STK_Static|STK_Ephem) ){ if( aStack[tos].flags & (STK_Static|STK_Ephem) ){
/* CANT HAPPEN. The IncrKey opcode is only applied to keys /* CANT HAPPEN. The IncrKey opcode is only applied to keys
** generated by MakeKey or MakeIdxKey and the results of those ** generated by MakeKey or MakeIdxKey and the results of those
@ -3364,7 +3412,7 @@ case OP_MoveTo: {
pC->lastRecno = aStack[tos].i; pC->lastRecno = aStack[tos].i;
pC->recnoIsValid = res==0; pC->recnoIsValid = res==0;
}else{ }else{
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
pC->recnoIsValid = 0; pC->recnoIsValid = 0;
} }
@ -3440,7 +3488,7 @@ case OP_Found: {
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
int res, rx; int res, rx;
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
alreadyExists = rx==SQLITE_OK && res==0; alreadyExists = rx==SQLITE_OK && res==0;
} }
@ -3496,7 +3544,7 @@ case OP_IsUnique: {
/* Make sure K is a string and make zKey point to K /* Make sure K is a string and make zKey point to K
*/ */
if( Stringify(p, nos) ) goto no_mem; Stringify(p, nos);
zKey = zStack[nos]; zKey = zStack[nos];
nKey = aStack[nos].n; nKey = aStack[nos].n;
assert( nKey >= 4 ); assert( nKey >= 4 );
@ -3709,7 +3757,7 @@ case OP_PutStrKey: {
char *zKey; char *zKey;
int nKey, iKey; int nKey, iKey;
if( pOp->opcode==OP_PutStrKey ){ if( pOp->opcode==OP_PutStrKey ){
if( Stringify(p, nos) ) goto no_mem; Stringify(p, nos);
nKey = aStack[nos].n; nKey = aStack[nos].n;
zKey = zStack[nos]; zKey = zStack[nos];
}else{ }else{
@ -4199,7 +4247,7 @@ case OP_IdxGE: {
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
int res, rc; int res, rc;
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res); rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
break; break;
@ -4462,7 +4510,7 @@ case OP_SortPut: {
int nos = tos - 1; int nos = tos - 1;
Sorter *pSorter; Sorter *pSorter;
VERIFY( if( tos<1 ) goto not_enough_stack; ) VERIFY( if( tos<1 ) goto not_enough_stack; )
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; if( Dynamicify(p, tos) || Dynamicify(p, nos) ) goto no_mem;
pSorter = sqliteMallocRaw( sizeof(Sorter) ); pSorter = sqliteMallocRaw( sizeof(Sorter) );
if( pSorter==0 ) goto no_mem; if( pSorter==0 ) goto no_mem;
pSorter->pNext = p->pSort; pSorter->pNext = p->pSort;
@ -4502,7 +4550,7 @@ case OP_SortMakeRec: {
nByte = 0; nByte = 0;
for(i=p->tos-nField+1; i<=p->tos; i++){ for(i=p->tos-nField+1; i<=p->tos; i++){
if( (aStack[i].flags & STK_Null)==0 ){ if( (aStack[i].flags & STK_Null)==0 ){
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
nByte += aStack[i].n; nByte += aStack[i].n;
} }
} }
@ -4555,7 +4603,7 @@ case OP_SortMakeKey: {
if( (aStack[i].flags & STK_Null)!=0 ){ if( (aStack[i].flags & STK_Null)!=0 ){
nByte += 2; nByte += 2;
}else{ }else{
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
nByte += aStack[i].n+2; nByte += aStack[i].n+2;
} }
} }
@ -4999,7 +5047,7 @@ case OP_AggFunc: {
if( aStack[i].flags & STK_Null ){ if( aStack[i].flags & STK_Null ){
zStack[i] = 0; zStack[i] = 0;
}else{ }else{
if( Stringify(p, i) ) goto no_mem; Stringify(p, i);
} }
} }
i = aStack[p->tos].i; i = aStack[p->tos].i;
@ -5042,7 +5090,7 @@ case OP_AggFocus: {
int nKey; int nKey;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
zKey = zStack[tos]; zKey = zStack[tos];
nKey = aStack[tos].n; nKey = aStack[tos].n;
pElem = sqliteHashFind(&p->agg.hash, zKey, nKey); pElem = sqliteHashFind(&p->agg.hash, zKey, nKey);
@ -5192,7 +5240,7 @@ case OP_SetInsert: {
}else{ }else{
int tos = p->tos; int tos = p->tos;
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
sqliteHashInsert(&p->aSet[i].hash, zStack[tos], aStack[tos].n, p); sqliteHashInsert(&p->aSet[i].hash, zStack[tos], aStack[tos].n, p);
POPSTACK; POPSTACK;
} }
@ -5210,7 +5258,7 @@ case OP_SetFound: {
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
if( i>=0 && i<p->nSet && if( i>=0 && i<p->nSet &&
sqliteHashFind(&p->aSet[i].hash, zStack[tos], aStack[tos].n)){ sqliteHashFind(&p->aSet[i].hash, zStack[tos], aStack[tos].n)){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
@ -5229,7 +5277,7 @@ case OP_SetNotFound: {
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
if( Stringify(p, tos) ) goto no_mem; Stringify(p, tos);
if( i<0 || i>=p->nSet || if( i<0 || i>=p->nSet ||
sqliteHashFind(&p->aSet[i].hash, zStack[tos], aStack[tos].n)==0 ){ sqliteHashFind(&p->aSet[i].hash, zStack[tos], aStack[tos].n)==0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;