SQLite

Check-in [8a1deae497]
Login

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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8a1deae497edf3fa43fa96152d140405398c5ed6
User & Date: drh 2016-01-25 02:15:02.255
Context
2016-01-25
13:55
Add the SQLITE_EXTRA_DURABLE compile-time option. (check-in: 30671345b1 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: 8a1deae497 user: drh tags: trunk)
01:07
Small simplification and performance improvement in memsys5Free(). (check-in: 0a9cff5c48 user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/vdbeaux.c.
1717
1718
1719
1720
1721
1722
1723



1724
1725
1726












1727
1728
1729
1730


1731
1732
1733

1734
1735
1736
1737

1738
1739


1740
1741
1742
1743
1744
1745
1746
1747
1748


1749

1750
1751

1752
1753
1754
1755
1756



1757
1758

1759
1760
1761
1762
1763
1764
1765
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726



1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739



1740
1741



1742
1743



1744


1745
1746



1747
1748




1749
1750

1751
1752

1753
1754
1755



1756
1757
1758
1759

1760
1761
1762
1763
1764
1765
1766
1767







+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
+
+
-
-
-
+

-
-
-
+
-
-
+
+
-
-
-


-
-
-
-
+
+
-
+

-
+


-
-
-
+
+
+

-
+







    }
    z[j] = 0;
    sqlite3IoTrace("SQL %s\n", z);
  }
}
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */

/* An instance of this object describes bulk memory available for use
** by subcomponents of a prepared statement.  Space is allocated out
** of a ReusableSpace object by the allocSpace() routine below.
/*
** Allocate space from a fixed size buffer and return a pointer to
** that space.  If insufficient space is available, return NULL.
*/
struct ReusableSpace {
  u8 *pSpace;          /* Available memory */
  int nFree;           /* Bytes of available memory */
  int nNeeded;         /* Total bytes that could not be allocated */
};

/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
** from the ReusableSpace object.  Return a pointer to the allocated
** memory on success.  If insufficient memory is available in the
** ReusableSpace object, increase the ReusableSpace.nNeeded
** value by the amount needed and return NULL.
**
** The pBuf parameter is the initial value of a pointer which will
** receive the new memory.  pBuf is normally NULL.  If pBuf is not
** NULL, it means that memory space has already been allocated and that
** If pBuf is not initially NULL, that means that the memory has already
** been allocated by a prior call to this routine, so just return a copy
** this routine should not allocate any new memory.  When pBuf is not
** NULL simply return pBuf.  Only allocate new memory space when pBuf
** is NULL.
** of pBuf and leave ReusableSpace unchanged.
**
** nByte is the number of bytes of space needed.
**
** pFrom points to *pnFrom bytes of available space.  New space is allocated
** This allocator is employed to repurpose unused slots at the end of the
** from the end of the pFrom buffer and *pnFrom is decremented.
**
** opcode array of prepared state for other memory needs of the prepared
** statement.
** *pnNeeded is a counter of the number of bytes of space that have failed
** to allocate.  If there is insufficient space in pFrom to satisfy the
** request, then increment *pnNeeded by the amount of the request.
*/
static void *allocSpace(
  void *pBuf,          /* Where return pointer will be stored */
  int nByte,           /* Number of bytes to allocate */
  u8 *pFrom,           /* Memory available for allocation */
  int *pnFrom,         /* IN/OUT: Space available at pFrom */
  struct ReusableSpace *p,  /* Bulk memory available for allocation */
  void *pBuf,               /* Pointer to a prior allocation */
  int *pnNeeded        /* If allocation cannot be made, increment *pnByte */
  int nByte                 /* Bytes of memory needed */
){
  assert( EIGHT_BYTE_ALIGNMENT(pFrom) );
  assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
  if( pBuf==0 ){
    nByte = ROUND8(nByte);
    if( nByte <= *pnFrom ){
      *pnFrom -= nByte;
      pBuf = &pFrom[*pnFrom];
    if( nByte <= p->nFree ){
      p->nFree -= nByte;
      pBuf = &p->pSpace[p->nFree];
    }else{
      *pnNeeded += nByte;
      p->nNeeded += nByte;
    }
  }
  assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
  return pBuf;
}

/*
1827
1828
1829
1830
1831
1832
1833
1834

1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854

1855
1856
1857
1858
1859
1860
1861
1862
1863
1864


1865
1866
1867

1868
1869
1870
1871
1872
1873
1874
1875
1876








1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887


1888
1889
1890

1891
1892
1893

1894
1895
1896
1897
1898
1899
1900
1901





1902
1903

1904
1905

1906
1907
1908


1909
1910
1911
1912


1913
1914
1915
1916
1917
1918
1919
1829
1830
1831
1832
1833
1834
1835

1836


1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853

1854
1855
1856
1857
1858
1859
1860
1861
1862


1863
1864



1865
1866








1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883


1884
1885
1886
1887

1888
1889
1890

1891
1892
1893
1894





1895
1896
1897
1898
1899


1900
1901

1902
1903


1904
1905




1906
1907
1908
1909
1910
1911
1912
1913
1914







-
+
-
-

















-
+








-
-
+
+
-
-
-
+

-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+









-
-
+
+


-
+


-
+



-
-
-
-
-
+
+
+
+
+
-
-
+

-
+

-
-
+
+
-
-
-
-
+
+







  sqlite3 *db;                   /* The database connection */
  int nVar;                      /* Number of parameters */
  int nMem;                      /* Number of VM memory registers */
  int nCursor;                   /* Number of cursors required */
  int nArg;                      /* Number of arguments in subprograms */
  int nOnce;                     /* Number of OP_Once instructions */
  int n;                         /* Loop counter */
  int nFree;                     /* Available free space */
  struct ReusableSpace x;        /* Reusable bulk memory */
  u8 *zCsr;                      /* Memory available for allocation */
  int nByte;                     /* How much extra memory is needed */

  assert( p!=0 );
  assert( p->nOp>0 );
  assert( pParse!=0 );
  assert( p->magic==VDBE_MAGIC_INIT );
  assert( pParse==p->pParse );
  db = p->db;
  assert( db->mallocFailed==0 );
  nVar = pParse->nVar;
  nMem = pParse->nMem;
  nCursor = pParse->nTab;
  nArg = pParse->nMaxArg;
  nOnce = pParse->nOnce;
  if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
  
  /* For each cursor required, also allocate a memory cell. Memory
  ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
  ** the vdbe program. Instead they are used to allocate space for
  ** the vdbe program. Instead they are used to allocate memory for
  ** VdbeCursor/BtCursor structures. The blob of memory associated with 
  ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
  ** stores the blob of memory associated with cursor 1, etc.
  **
  ** See also: allocateCursor().
  */
  nMem += nCursor;

  /* zCsr will initially point to nFree bytes of unused space at the
  ** end of the opcode array, p->aOp.  The computation of nFree is
  /* Figure out how much reusable memory is available at the end of the
  ** opcode array.  This extra memory will be reallocated for other elements
  ** conservative - it might be smaller than the true number of free
  ** bytes, but never larger.  nFree must be a multiple of 8 - it is
  ** rounded down if is not.
  ** of the prepared statement.
  */
  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode space used */
  zCsr = &((u8*)p->aOp)[n];                   /* Unused opcode space */
  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
  nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused space */
  assert( nFree>=0 );
  if( nFree>0 ){
    memset(zCsr, 0, nFree);
    assert( EIGHT_BYTE_ALIGNMENT(&zCsr[nFree]) );
  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
  assert( x.nFree>=0 );
  if( x.nFree>0 ){
    memset(x.pSpace, 0, x.nFree);
    assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
  }

  resolveP2Values(p, &nArg);
  p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
  if( pParse->explain && nMem<10 ){
    nMem = 10;
  }
  p->expired = 0;

  /* Memory for registers, parameters, cursor, etc, is allocated in two
  ** passes.  On the first pass, we try to reuse unused space at the 
  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
  ** passes.  On the first pass, we try to reuse unused memory at the 
  ** end of the opcode array.  If we are unable to satisfy all memory
  ** requirements by reusing the opcode array tail, then the second
  ** pass will fill in the rest using a fresh allocation.  
  ** pass will fill in the remainder using a fresh memory allocation.  
  **
  ** This two-pass approach that reuses as much memory as possible from
  ** the leftover space at the end of the opcode array can significantly
  ** the leftover memory at the end of the opcode array.  This can significantly
  ** reduce the amount of memory held by a prepared statement.
  */
  do {
    nByte = 0;
    p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte);
    p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte);
    p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte);
    p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
    x.nNeeded = 0;
    p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
    p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
    p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
    p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
                          zCsr, &nFree, &nByte);
    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte);
    p->aOnceFlag = allocSpace(&x, p->aOnceFlag, nOnce);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
    p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte);
    p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
#endif
    if( nByte ){
      p->pFree = sqlite3DbMallocZero(db, nByte);
    if( x.nNeeded==0 ) break;
    x.pSpace = p->pFree = sqlite3DbMallocZero(db, x.nNeeded);
    }
    zCsr = p->pFree;
    nFree = nByte;
  }while( nByte && !db->mallocFailed );
    x.nFree = x.nNeeded;
  }while( !db->mallocFailed );

  p->nCursor = nCursor;
  p->nOnceFlag = nOnce;
  if( p->aVar ){
    p->nVar = (ynVar)nVar;
    for(n=0; n<nVar; n++){
      p->aVar[n].flags = MEM_Null;