/ Check-in [8a1deae4]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Small simplification to the prepare statement opcode memory reuse logic. Easier to read, and slightly smaller and faster.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8a1deae497edf3fa43fa96152d140405398c5ed6
User & Date: drh 2016-01-25 02:15:02
Context
2016-01-25
13:55
Add the SQLITE_EXTRA_DURABLE compile-time option. check-in: 30671345 user: drh tags: trunk
02:15
Small simplification to the prepare statement opcode memory reuse logic. Easier to read, and slightly smaller and faster. check-in: 8a1deae4 user: drh tags: trunk
01:07
Small simplification and performance improvement in memsys5Free(). check-in: 0a9cff5c user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbeaux.c.

  1717   1717       }
  1718   1718       z[j] = 0;
  1719   1719       sqlite3IoTrace("SQL %s\n", z);
  1720   1720     }
  1721   1721   }
  1722   1722   #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
  1723   1723   
  1724         -/*
  1725         -** Allocate space from a fixed size buffer and return a pointer to
  1726         -** that space.  If insufficient space is available, return NULL.
  1727         -**
  1728         -** The pBuf parameter is the initial value of a pointer which will
  1729         -** receive the new memory.  pBuf is normally NULL.  If pBuf is not
  1730         -** NULL, it means that memory space has already been allocated and that
  1731         -** this routine should not allocate any new memory.  When pBuf is not
  1732         -** NULL simply return pBuf.  Only allocate new memory space when pBuf
  1733         -** is NULL.
  1734         -**
  1735         -** nByte is the number of bytes of space needed.
  1736         -**
  1737         -** pFrom points to *pnFrom bytes of available space.  New space is allocated
  1738         -** from the end of the pFrom buffer and *pnFrom is decremented.
  1739         -**
  1740         -** *pnNeeded is a counter of the number of bytes of space that have failed
  1741         -** to allocate.  If there is insufficient space in pFrom to satisfy the
  1742         -** request, then increment *pnNeeded by the amount of the request.
         1724  +/* An instance of this object describes bulk memory available for use
         1725  +** by subcomponents of a prepared statement.  Space is allocated out
         1726  +** of a ReusableSpace object by the allocSpace() routine below.
         1727  +*/
         1728  +struct ReusableSpace {
         1729  +  u8 *pSpace;          /* Available memory */
         1730  +  int nFree;           /* Bytes of available memory */
         1731  +  int nNeeded;         /* Total bytes that could not be allocated */
         1732  +};
         1733  +
         1734  +/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
         1735  +** from the ReusableSpace object.  Return a pointer to the allocated
         1736  +** memory on success.  If insufficient memory is available in the
         1737  +** ReusableSpace object, increase the ReusableSpace.nNeeded
         1738  +** value by the amount needed and return NULL.
         1739  +**
         1740  +** If pBuf is not initially NULL, that means that the memory has already
         1741  +** been allocated by a prior call to this routine, so just return a copy
         1742  +** of pBuf and leave ReusableSpace unchanged.
         1743  +**
         1744  +** This allocator is employed to repurpose unused slots at the end of the
         1745  +** opcode array of prepared state for other memory needs of the prepared
         1746  +** statement.
  1743   1747   */
  1744   1748   static void *allocSpace(
  1745         -  void *pBuf,          /* Where return pointer will be stored */
  1746         -  int nByte,           /* Number of bytes to allocate */
  1747         -  u8 *pFrom,           /* Memory available for allocation */
  1748         -  int *pnFrom,         /* IN/OUT: Space available at pFrom */
  1749         -  int *pnNeeded        /* If allocation cannot be made, increment *pnByte */
         1749  +  struct ReusableSpace *p,  /* Bulk memory available for allocation */
         1750  +  void *pBuf,               /* Pointer to a prior allocation */
         1751  +  int nByte                 /* Bytes of memory needed */
  1750   1752   ){
  1751         -  assert( EIGHT_BYTE_ALIGNMENT(pFrom) );
         1753  +  assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
  1752   1754     if( pBuf==0 ){
  1753   1755       nByte = ROUND8(nByte);
  1754         -    if( nByte <= *pnFrom ){
  1755         -      *pnFrom -= nByte;
  1756         -      pBuf = &pFrom[*pnFrom];
         1756  +    if( nByte <= p->nFree ){
         1757  +      p->nFree -= nByte;
         1758  +      pBuf = &p->pSpace[p->nFree];
  1757   1759       }else{
  1758         -      *pnNeeded += nByte;
         1760  +      p->nNeeded += nByte;
  1759   1761       }
  1760   1762     }
  1761   1763     assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
  1762   1764     return pBuf;
  1763   1765   }
  1764   1766   
  1765   1767   /*
................................................................................
  1827   1829     sqlite3 *db;                   /* The database connection */
  1828   1830     int nVar;                      /* Number of parameters */
  1829   1831     int nMem;                      /* Number of VM memory registers */
  1830   1832     int nCursor;                   /* Number of cursors required */
  1831   1833     int nArg;                      /* Number of arguments in subprograms */
  1832   1834     int nOnce;                     /* Number of OP_Once instructions */
  1833   1835     int n;                         /* Loop counter */
  1834         -  int nFree;                     /* Available free space */
  1835         -  u8 *zCsr;                      /* Memory available for allocation */
  1836         -  int nByte;                     /* How much extra memory is needed */
         1836  +  struct ReusableSpace x;        /* Reusable bulk memory */
  1837   1837   
  1838   1838     assert( p!=0 );
  1839   1839     assert( p->nOp>0 );
  1840   1840     assert( pParse!=0 );
  1841   1841     assert( p->magic==VDBE_MAGIC_INIT );
  1842   1842     assert( pParse==p->pParse );
  1843   1843     db = p->db;
................................................................................
  1847   1847     nCursor = pParse->nTab;
  1848   1848     nArg = pParse->nMaxArg;
  1849   1849     nOnce = pParse->nOnce;
  1850   1850     if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
  1851   1851     
  1852   1852     /* For each cursor required, also allocate a memory cell. Memory
  1853   1853     ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
  1854         -  ** the vdbe program. Instead they are used to allocate space for
         1854  +  ** the vdbe program. Instead they are used to allocate memory for
  1855   1855     ** VdbeCursor/BtCursor structures. The blob of memory associated with 
  1856   1856     ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
  1857   1857     ** stores the blob of memory associated with cursor 1, etc.
  1858   1858     **
  1859   1859     ** See also: allocateCursor().
  1860   1860     */
  1861   1861     nMem += nCursor;
  1862   1862   
  1863         -  /* zCsr will initially point to nFree bytes of unused space at the
  1864         -  ** end of the opcode array, p->aOp.  The computation of nFree is
  1865         -  ** conservative - it might be smaller than the true number of free
  1866         -  ** bytes, but never larger.  nFree must be a multiple of 8 - it is
  1867         -  ** rounded down if is not.
         1863  +  /* Figure out how much reusable memory is available at the end of the
         1864  +  ** opcode array.  This extra memory will be reallocated for other elements
         1865  +  ** of the prepared statement.
  1868   1866     */
  1869         -  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode space used */
  1870         -  zCsr = &((u8*)p->aOp)[n];                   /* Unused opcode space */
  1871         -  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
  1872         -  nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused space */
  1873         -  assert( nFree>=0 );
  1874         -  if( nFree>0 ){
  1875         -    memset(zCsr, 0, nFree);
  1876         -    assert( EIGHT_BYTE_ALIGNMENT(&zCsr[nFree]) );
         1867  +  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
         1868  +  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
         1869  +  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
         1870  +  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
         1871  +  assert( x.nFree>=0 );
         1872  +  if( x.nFree>0 ){
         1873  +    memset(x.pSpace, 0, x.nFree);
         1874  +    assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
  1877   1875     }
  1878   1876   
  1879   1877     resolveP2Values(p, &nArg);
  1880   1878     p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
  1881   1879     if( pParse->explain && nMem<10 ){
  1882   1880       nMem = 10;
  1883   1881     }
  1884   1882     p->expired = 0;
  1885   1883   
  1886         -  /* Memory for registers, parameters, cursor, etc, is allocated in two
  1887         -  ** passes.  On the first pass, we try to reuse unused space at the 
         1884  +  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
         1885  +  ** passes.  On the first pass, we try to reuse unused memory at the 
  1888   1886     ** end of the opcode array.  If we are unable to satisfy all memory
  1889   1887     ** requirements by reusing the opcode array tail, then the second
  1890         -  ** pass will fill in the rest using a fresh allocation.  
         1888  +  ** pass will fill in the remainder using a fresh memory allocation.  
  1891   1889     **
  1892   1890     ** This two-pass approach that reuses as much memory as possible from
  1893         -  ** the leftover space at the end of the opcode array can significantly
         1891  +  ** the leftover memory at the end of the opcode array.  This can significantly
  1894   1892     ** reduce the amount of memory held by a prepared statement.
  1895   1893     */
  1896   1894     do {
  1897         -    nByte = 0;
  1898         -    p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
  1899         -    p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
  1900         -    p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
  1901         -    p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
  1902         -                          zCsr, &nFree, &nByte);
  1903         -    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
         1895  +    x.nNeeded = 0;
         1896  +    p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
         1897  +    p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
         1898  +    p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
         1899  +    p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
         1900  +    p->aOnceFlag = allocSpace(&x, p->aOnceFlag, nOnce);
  1904   1901   #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
  1905         -    p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
         1902  +    p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
  1906   1903   #endif
  1907         -    if( nByte ){
  1908         -      p->pFree = sqlite3DbMallocZero(db, nByte);
  1909         -    }
  1910         -    zCsr = p->pFree;
  1911         -    nFree = nByte;
  1912         -  }while( nByte && !db->mallocFailed );
         1904  +    if( x.nNeeded==0 ) break;
         1905  +    x.pSpace = p->pFree = sqlite3DbMallocZero(db, x.nNeeded);
         1906  +    x.nFree = x.nNeeded;
         1907  +  }while( !db->mallocFailed );
  1913   1908   
  1914   1909     p->nCursor = nCursor;
  1915   1910     p->nOnceFlag = nOnce;
  1916   1911     if( p->aVar ){
  1917   1912       p->nVar = (ynVar)nVar;
  1918   1913       for(n=0; n<nVar; n++){
  1919   1914         p->aVar[n].flags = MEM_Null;