From: drh Date: Mon, 6 Jul 2015 18:54:52 +0000 (+0000) Subject: Enhance separate pcache1 to allocate a block of pages from heap on startup, X-Git-Tag: version-3.8.11~49^2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ee70a84ea7d709979dc09fa42bf4aa9afae21667;p=thirdparty%2Fsqlite.git Enhance separate pcache1 to allocate a block of pages from heap on startup, if possible, for a 5.2% performance improvement. FossilOrigin-Name: aa7341c8736732a0a59f6688cc34e78be02a7bfc --- diff --git a/manifest b/manifest index 1954e6998c..c2e77a579b 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 0975b167fb..29a53816d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6d2999afbc25b9c238e4028f637c10eaaf0ec75e \ No newline at end of file +aa7341c8736732a0a59f6688cc34e78be02a7bfc \ No newline at end of file diff --git a/src/global.c b/src/global.c index 61450b3d35..3b1e804bb8 100644 --- a/src/global.c +++ b/src/global.c @@ -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 */ diff --git a/src/pcache1.c b/src/pcache1.c index 797354bd75..30ea7d0d8b 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -50,8 +50,35 @@ ** ** 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 && ppGroup->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; ipage.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=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); }