1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Enhance separate pcache1 to allocate a block of pages from heap on startup,

if possible, for a 5.2% performance improvement.

FossilOrigin-Name: aa7341c8736732a0a59f6688cc34e78be02a7bfc
This commit is contained in:
drh
2015-07-06 18:54:52 +00:00
parent b63ce02f57
commit ee70a84ea7
5 changed files with 126 additions and 57 deletions

View File

@ -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

View File

@ -1 +1 @@
6d2999afbc25b9c238e4028f637c10eaaf0ec75e
aa7341c8736732a0a59f6688cc34e78be02a7bfc

View 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 */

View File

@ -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 && 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) ){

View 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);
}