]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance separate pcache1 to allocate a block of pages from heap on startup,
authordrh <drh@noemail.net>
Mon, 6 Jul 2015 18:54:52 +0000 (18:54 +0000)
committerdrh <drh@noemail.net>
Mon, 6 Jul 2015 18:54:52 +0000 (18:54 +0000)
if possible, for a 5.2% performance improvement.

FossilOrigin-Name: aa7341c8736732a0a59f6688cc34e78be02a7bfc

manifest
manifest.uuid
src/global.c
src/pcache1.c
test/speedtest1.c

index 1954e6998cd98f8345c8d3fc7229e7a455fa03a5..c2e77a579bd2a6aa1b590e75af5f75200d38a29e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sallow\srecursive\sCTEs\sthat\suse\saggregate\squeries\sin\sthe\srecursive\spart.
-D 2015-07-05T22:15:10.026
+C Enhance\sseparate\spcache1\sto\sallocate\sa\sblock\sof\spages\sfrom\sheap\son\sstartup,\nif\spossible,\sfor\sa\s5.2%\sperformance\simprovement.
+D 2015-07-06T18:54:52.424
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 017bf0511d1b2dd1db5e16488fbf75a17b526cbc
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -283,7 +283,7 @@ F src/expr.c c5c58e4d01c7ceb2266791d8d877f1b23a88e316
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
 F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1
-F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
+F src/global.c 32c0ebfdca59db55c761f1405abf7bdfd24ecae0
 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@@ -319,7 +319,7 @@ F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2
 F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
 F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0
 F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9
-F src/pcache1.c b800e90896640bb0d1b0f6baa34fb059ca3b8b2e
+F src/pcache1.c 28f3434788cac24bc95f8c1af4a61cbde179ef18
 F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7
 F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc
 F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
@@ -1005,7 +1005,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
 F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
-F test/speedtest1.c 2e8f367c5fe5e0c3df24a157e17cb2f75c1b88c7
+F test/speedtest1.c 54f211994e2fb5b3f7c5c82137378f46ca89aae8
 F test/spellfix.test 0597065ff57042df1f138e6a2611ae19c2698135
 F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
 F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68
@@ -1364,7 +1364,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 8cf02090ce53ec150492d77d9e5e5f27665bd34f
-R 2ced95f329e3743e78bec1f4f82122ca
+P 6d2999afbc25b9c238e4028f637c10eaaf0ec75e
+R 773f110b2d424984f83126d1917fdcbb
+T *branch * pcache-bulk-local
+T *sym-pcache-bulk-local *
+T -sym-trunk *
 U drh
-Z 74748fde014fce363e747a5eecd57396
+Z a5a615d5b6a74570375077a92838726e
index 0975b167fb874dac10ed8931eef98ec7ff755bc1..29a53816d976c0044a92d701c55070e391d0098d 100644 (file)
@@ -1 +1 @@
-6d2999afbc25b9c238e4028f637c10eaaf0ec75e
\ No newline at end of file
+aa7341c8736732a0a59f6688cc34e78be02a7bfc
\ No newline at end of file
index 61450b3d3570f27ae4dddfe51921797542831d42..3b1e804bb828dcb94b30e2c9b7c4d36d6c18d09c 100644 (file)
@@ -186,7 +186,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    0,                         /* nScratch */
    (void*)0,                  /* pPage */
    0,                         /* szPage */
-   0,                         /* nPage */
+   100,                       /* nPage */
    0,                         /* mxParserStack */
    0,                         /* sharedCacheEnabled */
    SQLITE_SORTER_PMASZ,       /* szPma */
index 797354bd75c07166231d3dd7bd8a2e919d394645..30ea7d0d8b4f39aa32b3688206326ee556b77811 100644 (file)
 **
 ** The pcache.c and pager.c modules deal pointers to PgHdr objects.
 ** The btree.c module deals with pointers to MemPage objects.
+**
+** SOURCE OF PAGE CACHE MEMORY:
+**
+** Memory for a page might come from any of three sources:
+**
+**    (1)  The general-purpose memory allocator - sqlite3Malloc()
+**    (2)  Global page-cache memory provided using sqlite3_config() with
+**         SQLITE_CONFIG_PAGECACHE.
+**    (3)  PCache-local bulk allocation.
+**
+** The third case is a chunk of heap memory (defaulting to 100 pages worth)
+** that is allocated when the page cache is created.  The size of the local
+** bulk allocation can be adjusted using 
+**
+**     sqlite3_config(SQLITE_CONFIG_PCACHE, 0, 0, N).
+**
+** If N is positive, then N pages worth of memory are allocated using a single
+** sqlite3Malloc() call and that memory is used for the first N pages allocated.
+** Or if N is negative, then -1024*N bytes of memory are allocated and used
+** for as many pages as can be accomodated.
+**
+** Only one of (2) or (3) can be used.  Once the memory available to (2) or
+** (3) is exhausted, subsequent allocations fail over to the general-purpose
+** memory allocator (1).
+**
+** Earlier versions of SQLite used only methods (1) and (2).  But experiments
+** show that method (3) with N==100 provides about a 5% performance boost for
+** common workloads.
 */
-
 #include "sqliteInt.h"
 
 typedef struct PCache1 PCache1;
@@ -105,8 +132,9 @@ struct PCache1 {
   ** The PGroup mutex must be held when accessing nMax.
   */
   PGroup *pGroup;                     /* PGroup this cache belongs to */
-  int szPage;                         /* Size of allocated pages in bytes */
-  int szExtra;                        /* Size of extra space in bytes */
+  int szPage;                         /* Size of database content section */
+  int szExtra;                        /* sizeof(MemPage)+sizeof(PgHdr) */
+  int szAlloc;                        /* Total size of one pcache line */
   int bPurgeable;                     /* True if cache is purgeable */
   unsigned int nMin;                  /* Minimum number of pages reserved */
   unsigned int nMax;                  /* Configured "cache_size" value */
@@ -120,6 +148,8 @@ struct PCache1 {
   unsigned int nPage;                 /* Total number of pages in apHash */
   unsigned int nHash;                 /* Number of slots in apHash[] */
   PgHdr1 **apHash;                    /* Hash table for fast lookup by key */
+  PgHdr1 *pFree;                      /* List of unused pcache-local pages */
+  void *pBulk;                        /* Bulk memory used by pcache-local */
 };
 
 /*
@@ -132,6 +162,7 @@ struct PgHdr1 {
   sqlite3_pcache_page page;
   unsigned int iKey;             /* Key value (page number) */
   u8 isPinned;                   /* Page in use, not on the LRU list */
+  u8 isBulkLocal;                /* This page from bulk local storage */
   PgHdr1 *pNext;                 /* Next in hash table chain */
   PCache1 *pCache;               /* Cache that currently owns this page */
   PgHdr1 *pLruNext;              /* Next in LRU list of unpinned pages */
@@ -139,8 +170,8 @@ struct PgHdr1 {
 };
 
 /*
-** Free slots in the allocator used to divide up the buffer provided using
-** the SQLITE_CONFIG_PAGECACHE mechanism.
+** Free slots in the allocator used to divide up the global page cache
+** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
 */
 struct PgFreeslot {
   PgFreeslot *pNext;  /* Next free slot */
@@ -161,7 +192,7 @@ static SQLITE_WSD struct PCacheGlobal {
   int szSlot;                    /* Size of each free slot */
   int nSlot;                     /* The number of pcache slots */
   int nReserve;                  /* Try to keep nFreeSlot above this */
-  void *pStart, *pEnd;           /* Bounds of pagecache malloc range */
+  void *pStart, *pEnd;           /* Bounds of global page cache memory */
   /* Above requires no mutex.  Use mutex below for variable that follow. */
   sqlite3_mutex *mutex;          /* Mutex for accessing the following: */
   PgFreeslot *pFree;             /* Free page blocks */
@@ -208,6 +239,7 @@ static SQLITE_WSD struct PCacheGlobal {
 void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
   if( pcache1.isInit ){
     PgFreeslot *p;
+    if( pBuf==0 ) sz = n = 0;
     sz = ROUNDDOWN8(sz);
     pcache1.szSlot = sz;
     pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -272,9 +304,9 @@ static void *pcache1Alloc(int nByte){
 /*
 ** Free an allocated buffer obtained from pcache1Alloc().
 */
-static int pcache1Free(void *p){
+static void pcache1Free(void *p){
   int nFreed = 0;
-  if( p==0 ) return 0;
+  if( p==0 ) return;
   if( p>=pcache1.pStart && p<pcache1.pEnd ){
     PgFreeslot *pSlot;
     sqlite3_mutex_enter(pcache1.mutex);
@@ -289,15 +321,14 @@ static int pcache1Free(void *p){
   }else{
     assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
-    nFreed = sqlite3MallocSize(p);
 #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+    nFreed = sqlite3MallocSize(p);
     sqlite3_mutex_enter(pcache1.mutex);
     sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
     sqlite3_mutex_leave(pcache1.mutex);
 #endif
     sqlite3_free(p);
   }
-  return nFreed;
 }
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -325,34 +356,38 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
   PgHdr1 *p = 0;
   void *pPg;
 
-  /* The group mutex must be released before pcache1Alloc() is called. This
-  ** is because it may call sqlite3_release_memory(), which assumes that 
-  ** this mutex is not held. */
   assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
-  pcache1LeaveMutex(pCache->pGroup);
+  if( pCache->pFree ){
+    p = pCache->pFree;
+    pCache->pFree = p->pNext;
+    p->pNext = 0;
+  }else{
+    /* The group mutex must be released before pcache1Alloc() is called. This
+    ** is because it may call sqlite3_release_memory(), which assumes that 
+    ** this mutex is not held. */
+    pcache1LeaveMutex(pCache->pGroup);
 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
-  pPg = pcache1Alloc(pCache->szPage);
-  p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
-  if( !pPg || !p ){
-    pcache1Free(pPg);
-    sqlite3_free(p);
-    pPg = 0;
-  }
+    pPg = pcache1Alloc(pCache->szPage);
+    p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
+    if( !pPg || !p ){
+      pcache1Free(pPg);
+      sqlite3_free(p);
+      pPg = 0;
+    }
 #else
-  pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
-  p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+    pPg = pcache1Alloc(pCache->szAlloc);
+    p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
 #endif
-  pcache1EnterMutex(pCache->pGroup);
-
-  if( pPg ){
+    pcache1EnterMutex(pCache->pGroup);
+    if( pPg==0 ) return 0;
     p->page.pBuf = pPg;
     p->page.pExtra = &p[1];
-    if( pCache->bPurgeable ){
-      pCache->pGroup->nCurrentPage++;
-    }
-    return p;
+    p->isBulkLocal = 0;
   }
-  return 0;
+  if( pCache->bPurgeable ){
+    pCache->pGroup->nCurrentPage++;
+  }
+  return p;
 }
 
 /*
@@ -366,10 +401,15 @@ static void pcache1FreePage(PgHdr1 *p){
   if( ALWAYS(p) ){
     PCache1 *pCache = p->pCache;
     assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
-    pcache1Free(p->page.pBuf);
+    if( p->isBulkLocal ){
+      p->pNext = pCache->pFree;
+      pCache->pFree = p;
+    }else{
+      pcache1Free(p->page.pBuf);
 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
-    sqlite3_free(p);
+      sqlite3_free(p);
 #endif
+    }
     if( pCache->bPurgeable ){
       pCache->pGroup->nCurrentPage--;
     }
@@ -640,6 +680,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
     pCache->pGroup = pGroup;
     pCache->szPage = szPage;
     pCache->szExtra = szExtra;
+    pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
     pCache->bPurgeable = (bPurgeable ? 1 : 0);
     pcache1EnterMutex(pGroup);
     pcache1ResizeHash(pCache);
@@ -649,6 +690,34 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
       pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
     }
     pcache1LeaveMutex(pGroup);
+    if( separateCache
+     && sqlite3GlobalConfig.szPage==0
+     && sqlite3GlobalConfig.nPage!=0
+    ){
+      int szBulk;
+      char *zBulk;
+      sqlite3BeginBenignMalloc();
+      if( sqlite3GlobalConfig.nPage>0 ){
+        szBulk = pCache->szAlloc * sqlite3GlobalConfig.nPage;
+      }else{
+        szBulk = -1024*sqlite3GlobalConfig.nPage;
+      }
+      zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
+      sqlite3EndBenignMalloc();
+      if( zBulk ){
+        int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
+        int i;
+        for(i=0; i<nBulk; i++){
+          PgHdr1 *pX = (PgHdr1*)&zBulk[szPage];
+          pX->page.pBuf = zBulk;
+          pX->page.pExtra = &pX[1];
+          pX->isBulkLocal = 1;
+          pX->pNext = pCache->pFree;
+          pCache->pFree = pX;
+          zBulk += pCache->szAlloc;
+        }
+      }
+    }
     if( pCache->nHash==0 ){
       pcache1Destroy((sqlite3_pcache*)pCache);
       pCache = 0;
@@ -753,15 +822,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
     pcache1RemoveFromHash(pPage, 0);
     pcache1PinPage(pPage);
     pOther = pPage->pCache;
-
-    /* We want to verify that szPage and szExtra are the same for pOther
-    ** and pCache.  Assert that we can verify this by comparing sums. */
-    assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
-    assert( pCache->szExtra<512 );
-    assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
-    assert( pOther->szExtra<512 );
-
-    if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
+    if( pOther->szAlloc != pCache->szAlloc ){
       pcache1FreePage(pPage);
       pPage = 0;
     }else{
@@ -1037,6 +1098,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
   pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
   pcache1EnforceMaxPage(pGroup);
   pcache1LeaveMutex(pGroup);
+  sqlite3_free(pCache->pBulk);
   sqlite3_free(pCache->apHash);
   sqlite3_free(pCache);
 }
@@ -1092,7 +1154,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
   int nFree = 0;
   assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
   assert( sqlite3_mutex_notheld(pcache1.mutex) );
-  if( pcache1.pStart==0 ){
+  if( sqlite3GlobalConfig.nPage==0 ){
     PgHdr1 *p;
     pcache1EnterMutex(&pcache1.grp);
     while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
index caa2330bbdf66032645b71961177fb404f1ced11..9ac9fbb9626a6b8ae138602e9593f94cc4801026 100644 (file)
@@ -1177,6 +1177,7 @@ int main(int argc, char **argv){
   int noSync = 0;               /* True for --nosync */
   int pageSize = 0;             /* Desired page size.  0 means default */
   int nPCache = 0, szPCache = 0;/* --pcache configuration */
+  int doPCache = 0;             /* True if --pcache is seen */
   int nScratch = 0, szScratch=0;/* --scratch configuration */
   int showStats = 0;            /* True for --stats */
   int nThread = 0;              /* --threads value */
@@ -1251,6 +1252,7 @@ int main(int argc, char **argv){
         if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
         nPCache = integerValue(argv[i+1]);
         szPCache = integerValue(argv[i+2]);
+        doPCache = 1;
         i += 2;
       }else if( strcmp(z,"primarykey")==0 ){
         g.zPK = "PRIMARY KEY";
@@ -1317,10 +1319,12 @@ int main(int argc, char **argv){
     rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
     if( rc ) fatal_error("heap configuration failed: %d\n", rc);
   }
-  if( nPCache>0 && szPCache>0 ){
-    pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
-    if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
-                                 nPCache*(sqlite3_int64)szPCache);
+  if( doPCache ){
+    if( nPCache>0 && szPCache>0 ){
+      pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
+      if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
+                                   nPCache*(sqlite3_int64)szPCache);
+    }
     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
     if( rc ) fatal_error("pcache configuration failed: %d\n", rc);
   }