Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfd85e9f

Browse files
committed
Avoid statically allocating formatting.c's format string caches.
This eliminates circa 120KB of static data from Postgres' memoryfootprint. In some usage patterns that space will get allocatedanyway, but in many processes it never will be allocated.We can improve matters further by allocating only as many cacheentries as we actually use, rather than allocating the whole arrayon first use. However, to avoid wasting lots of space due topalloc's habit of rounding requests up to power-of-2 sizes, tweakthe maximum cacheable format string length to make the struct sizesbe powers of 2 or just less. The sizes I chose make the maximumsa little bit less than they were before, but I doubt it matters much.While at it, rearrange struct FormatNode to avoid wasting quite somuch padding space. This change actually halves the size of thatstruct on 64-bit machines.Discussion:https://postgr.es/m/20181015200754.7y7zfuzsoux2c4ya@alap3.anarazel.de
1 parent02a30a0 commitfd85e9f

File tree

1 file changed

+56
-38
lines changed

1 file changed

+56
-38
lines changed

‎src/backend/utils/adt/formatting.c

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
#include"utils/float.h"
9494
#include"utils/formatting.h"
9595
#include"utils/int8.h"
96+
#include"utils/memutils.h"
9697
#include"utils/numeric.h"
9798
#include"utils/pg_locale.h"
9899

@@ -124,10 +125,10 @@
124125
*/
125126
typedefstruct
126127
{
127-
char*name;/* suffix string*/
128+
constchar*name;/* suffix string*/
128129
intlen,/* suffix length*/
129130
id,/* used in node->suffix */
130-
type;/* prefix / postfix*/
131+
type;/* prefix / postfix*/
131132
}KeySuffix;
132133

133134
/* ----------
@@ -155,10 +156,10 @@ typedef struct
155156

156157
typedefstruct
157158
{
158-
inttype;/* NODE_TYPE_XXX, see below */
159-
constKeyWord*key;/* if type is ACTION */
159+
uint8type;/* NODE_TYPE_XXX, see below */
160160
charcharacter[MAX_MULTIBYTE_CHAR_LEN+1];/* if type is CHAR */
161-
intsuffix;/* keyword prefix/suffix code, if any */
161+
uint8suffix;/* keyword prefix/suffix code, if any */
162+
constKeyWord*key;/* if type is ACTION */
162163
}FormatNode;
163164

164165
#defineNODE_TYPE_END1
@@ -358,14 +359,27 @@ typedef struct
358359
* For simplicity, the cache entries are fixed-size, so they allow for the
359360
* worst case of a FormatNode for each byte in the picture string.
360361
*
361-
* The max number of entries in the caches is DCH_CACHE_ENTRIES
362+
* The CACHE_SIZE constants are computed to make sizeof(DCHCacheEntry) and
363+
* sizeof(NUMCacheEntry) be powers of 2, or just less than that, so that
364+
* we don't waste too much space by palloc'ing them individually. Be sure
365+
* to adjust those macros if you add fields to those structs.
366+
*
367+
* The max number of entries in each cache is DCH_CACHE_ENTRIES
362368
* resp. NUM_CACHE_ENTRIES.
363369
* ----------
364370
*/
365-
#defineNUM_CACHE_SIZE64
366-
#defineNUM_CACHE_ENTRIES20
367-
#defineDCH_CACHE_SIZE128
371+
#defineDCH_CACHE_OVERHEAD \
372+
MAXALIGN(sizeof(bool) + sizeof(int))
373+
#defineNUM_CACHE_OVERHEAD \
374+
MAXALIGN(sizeof(bool) + sizeof(int) + sizeof(NUMDesc))
375+
376+
#defineDCH_CACHE_SIZE \
377+
((2048 - DCH_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
378+
#defineNUM_CACHE_SIZE \
379+
((1024 - NUM_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
380+
368381
#defineDCH_CACHE_ENTRIES20
382+
#defineNUM_CACHE_ENTRIES20
369383

370384
typedefstruct
371385
{
@@ -385,12 +399,12 @@ typedef struct
385399
}NUMCacheEntry;
386400

387401
/* global cache for date/time format pictures */
388-
staticDCHCacheEntryDCHCache[DCH_CACHE_ENTRIES];
402+
staticDCHCacheEntry*DCHCache[DCH_CACHE_ENTRIES];
389403
staticintn_DCHCache=0;/* current number of entries */
390404
staticintDCHCounter=0;/* aging-event counter */
391405

392406
/* global cache for number format pictures */
393-
staticNUMCacheEntryNUMCache[NUM_CACHE_ENTRIES];
407+
staticNUMCacheEntry*NUMCache[NUM_CACHE_ENTRIES];
394408
staticintn_NUMCache=0;/* current number of entries */
395409
staticintNUMCounter=0;/* aging-event counter */
396410

@@ -496,7 +510,7 @@ do { \
496510
*****************************************************************************/
497511

498512
/* ----------
499-
* Suffixes:
513+
* Suffixes (FormatNode.suffix is an OR of these codes)
500514
* ----------
501515
*/
502516
#defineDCH_S_FM0x01
@@ -3368,29 +3382,30 @@ DCH_cache_getnew(const char *str)
33683382
{
33693383
DCHCacheEntry*ent;
33703384

3371-
/* counter overflowcheck - paranoia? */
3385+
/*handlecounter overflowby resetting all ages */
33723386
if (DCHCounter >= (INT_MAX-DCH_CACHE_ENTRIES))
33733387
{
33743388
DCHCounter=0;
33753389

3376-
for (ent=DCHCache;ent<(DCHCache+DCH_CACHE_ENTRIES);ent++)
3377-
ent->age= (++DCHCounter);
3390+
for (inti=0;i<n_DCHCache;i++)
3391+
DCHCache[i]->age= (++DCHCounter);
33783392
}
33793393

33803394
/*
33813395
* If cache is full, remove oldest entry (or recycle first not-valid one)
33823396
*/
33833397
if (n_DCHCache >=DCH_CACHE_ENTRIES)
33843398
{
3385-
DCHCacheEntry*old=DCHCache+0;
3399+
DCHCacheEntry*old=DCHCache[0];
33863400

33873401
#ifdefDEBUG_TO_FROM_CHAR
33883402
elog(DEBUG_elog_output,"cache is full (%d)",n_DCHCache);
33893403
#endif
33903404
if (old->valid)
33913405
{
3392-
for (ent=DCHCache+1;ent<(DCHCache+DCH_CACHE_ENTRIES);ent++)
3406+
for (inti=1;i<DCH_CACHE_ENTRIES;i++)
33933407
{
3408+
ent=DCHCache[i];
33943409
if (!ent->valid)
33953410
{
33963411
old=ent;
@@ -3414,7 +3429,9 @@ DCH_cache_getnew(const char *str)
34143429
#ifdefDEBUG_TO_FROM_CHAR
34153430
elog(DEBUG_elog_output,"NEW (%d)",n_DCHCache);
34163431
#endif
3417-
ent=DCHCache+n_DCHCache;
3432+
Assert(DCHCache[n_DCHCache]==NULL);
3433+
DCHCache[n_DCHCache]=ent= (DCHCacheEntry*)
3434+
MemoryContextAllocZero(TopMemoryContext,sizeof(DCHCacheEntry));
34183435
ent->valid= false;
34193436
StrNCpy(ent->str,str,DCH_CACHE_SIZE+1);
34203437
ent->age= (++DCHCounter);
@@ -3428,20 +3445,19 @@ DCH_cache_getnew(const char *str)
34283445
staticDCHCacheEntry*
34293446
DCH_cache_search(constchar*str)
34303447
{
3431-
inti;
3432-
DCHCacheEntry*ent;
3433-
3434-
/* counter overflow check - paranoia? */
3448+
/* handle counter overflow by resetting all ages */
34353449
if (DCHCounter >= (INT_MAX-DCH_CACHE_ENTRIES))
34363450
{
34373451
DCHCounter=0;
34383452

3439-
for (ent=DCHCache;ent<(DCHCache+DCH_CACHE_ENTRIES);ent++)
3440-
ent->age= (++DCHCounter);
3453+
for (inti=0;i<n_DCHCache;i++)
3454+
DCHCache[i]->age= (++DCHCounter);
34413455
}
34423456

3443-
for (i=0,ent=DCHCache;i<n_DCHCache;i++,ent++)
3457+
for (inti=0;i<n_DCHCache;i++)
34443458
{
3459+
DCHCacheEntry*ent=DCHCache[i];
3460+
34453461
if (ent->valid&&strcmp(ent->str,str)==0)
34463462
{
34473463
ent->age= (++DCHCounter);
@@ -4047,29 +4063,30 @@ NUM_cache_getnew(const char *str)
40474063
{
40484064
NUMCacheEntry*ent;
40494065

4050-
/* counter overflowcheck - paranoia? */
4066+
/*handlecounter overflowby resetting all ages */
40514067
if (NUMCounter >= (INT_MAX-NUM_CACHE_ENTRIES))
40524068
{
40534069
NUMCounter=0;
40544070

4055-
for (ent=NUMCache;ent<(NUMCache+NUM_CACHE_ENTRIES);ent++)
4056-
ent->age= (++NUMCounter);
4071+
for (inti=0;i<n_NUMCache;i++)
4072+
NUMCache[i]->age= (++NUMCounter);
40574073
}
40584074

40594075
/*
40604076
* If cache is full, remove oldest entry (or recycle first not-valid one)
40614077
*/
40624078
if (n_NUMCache >=NUM_CACHE_ENTRIES)
40634079
{
4064-
NUMCacheEntry*old=NUMCache+0;
4080+
NUMCacheEntry*old=NUMCache[0];
40654081

40664082
#ifdefDEBUG_TO_FROM_CHAR
40674083
elog(DEBUG_elog_output,"Cache is full (%d)",n_NUMCache);
40684084
#endif
40694085
if (old->valid)
40704086
{
4071-
for (ent=NUMCache+1;ent<(NUMCache+NUM_CACHE_ENTRIES);ent++)
4087+
for (inti=1;i<NUM_CACHE_ENTRIES;i++)
40724088
{
4089+
ent=NUMCache[i];
40734090
if (!ent->valid)
40744091
{
40754092
old=ent;
@@ -4093,7 +4110,9 @@ NUM_cache_getnew(const char *str)
40934110
#ifdefDEBUG_TO_FROM_CHAR
40944111
elog(DEBUG_elog_output,"NEW (%d)",n_NUMCache);
40954112
#endif
4096-
ent=NUMCache+n_NUMCache;
4113+
Assert(NUMCache[n_NUMCache]==NULL);
4114+
NUMCache[n_NUMCache]=ent= (NUMCacheEntry*)
4115+
MemoryContextAllocZero(TopMemoryContext,sizeof(NUMCacheEntry));
40974116
ent->valid= false;
40984117
StrNCpy(ent->str,str,NUM_CACHE_SIZE+1);
40994118
ent->age= (++NUMCounter);
@@ -4107,20 +4126,19 @@ NUM_cache_getnew(const char *str)
41074126
staticNUMCacheEntry*
41084127
NUM_cache_search(constchar*str)
41094128
{
4110-
inti;
4111-
NUMCacheEntry*ent;
4112-
4113-
/* counter overflow check - paranoia? */
4129+
/* handle counter overflow by resetting all ages */
41144130
if (NUMCounter >= (INT_MAX-NUM_CACHE_ENTRIES))
41154131
{
41164132
NUMCounter=0;
41174133

4118-
for (ent=NUMCache;ent<(NUMCache+NUM_CACHE_ENTRIES);ent++)
4119-
ent->age= (++NUMCounter);
4134+
for (inti=0;i<n_NUMCache;i++)
4135+
NUMCache[i]->age= (++NUMCounter);
41204136
}
41214137

4122-
for (i=0,ent=NUMCache;i<n_NUMCache;i++,ent++)
4138+
for (inti=0;i<n_NUMCache;i++)
41234139
{
4140+
NUMCacheEntry*ent=NUMCache[i];
4141+
41244142
if (ent->valid&&strcmp(ent->str,str)==0)
41254143
{
41264144
ent->age= (++NUMCounter);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp