Skip to content

Commit bb49c27

Browse files
committed
Fix huge number of zone memory allocations introduced in c8a8d9e
Z_StringPool: Growing pool for immutable C strings in zone memory
1 parent 0af8039 commit bb49c27

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

src/qcommon/common.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,13 @@ int Z_Size(void *pvAddress)
11351135
return pMemory->iSize;
11361136
}
11371137

1138+
memtag_t Z_Tag(void *pvAddress)
1139+
{
1140+
zoneHeader_t *pMemory = ((zoneHeader_t *)pvAddress) - 1;
1141+
1142+
return pMemory->eTag;
1143+
}
1144+
11381145

11391146
// Frees a block of memory...
11401147
//
@@ -1368,6 +1375,65 @@ const char *CopyString( const char *in, memtag_t eTag ) {
13681375
return out;
13691376
}
13701377

1378+
/*
1379+
========================
1380+
StringPool
1381+
1382+
Growing pool for allocating immutable C strings in Zone Memory
1383+
blockSize should be tuned to balance fragmentation and waste
1384+
Strings longer than blockSize can be safely added
1385+
========================
1386+
*/
1387+
1388+
struct stringPool_s {
1389+
unsigned int size;
1390+
unsigned int tail;
1391+
struct stringPool_s *next;
1392+
char buffer[0];
1393+
};
1394+
1395+
stringPool_t *Z_StringPoolNew(unsigned int blockSize, memtag_t eTag) {
1396+
stringPool_t *block = (stringPool_t *)Z_Malloc(offsetof(stringPool_t, buffer) + blockSize, eTag, qfalse);
1397+
1398+
block->size = blockSize;
1399+
block->tail = 0;
1400+
block->next = NULL;
1401+
1402+
return block;
1403+
}
1404+
1405+
void Z_StringPoolFree(stringPool_t * pool) {
1406+
stringPool_t *block = pool;
1407+
1408+
while (block) {
1409+
stringPool_t *nextBlock = block->next;
1410+
Z_Free(block);
1411+
block = nextBlock;
1412+
}
1413+
}
1414+
1415+
const char *Z_StringPoolAdd(stringPool_t * pool, const char * string) {
1416+
stringPool_t *block = pool;
1417+
unsigned int len = strlen(string) + 1;
1418+
unsigned int total = 0;
1419+
1420+
while (block->size < block->tail + len) {
1421+
total += block->size;
1422+
1423+
if (!block->next) {
1424+
unsigned int size = MAX(len, pool->size);
1425+
memtag_t eTag = Z_Tag(block);
1426+
block->next = Z_StringPoolNew(size, eTag);
1427+
}
1428+
1429+
block = block->next;
1430+
}
1431+
1432+
memcpy(block->buffer + block->tail, string, len);
1433+
block->tail += len;
1434+
1435+
return block->buffer + block->tail - len;
1436+
}
13711437

13721438
/*
13731439
==============================================================================

src/qcommon/files.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ typedef struct {
215215
int hashSize; // hash table size (power of 2)
216216
fileInPack_t* *hashTable; // hash table
217217
fileInPack_t* buildBuffer; // buffer with the filenames etc.
218+
stringPool_t* namesPool; // buffer with filenames
218219
int gvc; // game-version compatibility
219220
qboolean isJKA; // jka assets
220221
} pack_t;
@@ -1960,6 +1961,7 @@ of a zip file.
19601961
static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean assetsJKA )
19611962
{
19621963
fileInPack_t *buildBuffer;
1964+
stringPool_t *namesPool;
19631965
pack_t *pack;
19641966
unzFile uf;
19651967
int err;
@@ -1983,6 +1985,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass
19831985
fs_packFiles += gi.number_entry;
19841986

19851987
buildBuffer = (struct fileInPack_s *)Z_Malloc((int)((gi.number_entry * sizeof(fileInPack_t))), TAG_FILESYS, qtrue);
1988+
namesPool = Z_StringPoolNew(gi.number_entry * 8, TAG_FILESYS);
19861989
fs_headerLongs = (int *)Z_Malloc( gi.number_entry * sizeof(int), TAG_FILESYS, qtrue );
19871990

19881991
// get the hash table size from the number of files in the zip
@@ -2034,7 +2037,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass
20342037
}
20352038
Q_strlwr( filename_inzip );
20362039
hash = FS_HashFileName(filename_inzip, pack->hashSize);
2037-
buildBuffer[i].name = CopyString(filename_inzip, TAG_FILESYS);
2040+
buildBuffer[i].name = Z_StringPoolAdd(namesPool, filename_inzip);
20382041
// store the file position in the zip
20392042
buildBuffer[i].pos = unzGetOffset(uf);
20402043
buildBuffer[i].len = file_info.uncompressed_size;
@@ -2051,6 +2054,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass
20512054
Z_Free(fs_headerLongs);
20522055

20532056
pack->buildBuffer = buildBuffer;
2057+
pack->namesPool = namesPool;
20542058

20552059
// which versions does this pk3 support?
20562060

@@ -3132,7 +3136,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass
31323136
if (!found) {
31333137
// server has no interest in the file
31343138
unzClose(pak->handle);
3135-
Z_Free((void *)pak->buildBuffer->name);
3139+
Z_StringPoolFree(pak->namesPool);
31363140
Z_Free(pak->buildBuffer);
31373141
Z_Free(pak);
31383142
continue;
@@ -3390,7 +3394,7 @@ void FS_Shutdown( qboolean closemfp, qboolean keepModuleFiles ) {
33903394

33913395
if ( p->pack ) {
33923396
unzClose(p->pack->handle);
3393-
Z_Free( (void *)p->pack->buildBuffer->name );
3397+
Z_StringPoolFree( p->pack->namesPool );
33943398
Z_Free( p->pack->buildBuffer );
33953399
Z_Free( p->pack );
33963400
}

src/qcommon/qcommon.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,13 @@ MISC
777777

778778
const char *CopyString( const char *in );
779779
const char *CopyString( const char *in, memtag_t eTag );
780+
781+
struct stringPool_s;
782+
typedef struct stringPool_s stringPool_t;
783+
stringPool_t *Z_StringPoolNew(unsigned int blockSize, memtag_t eTag);
784+
void Z_StringPoolFree(stringPool_t * pool);
785+
const char *Z_StringPoolAdd(stringPool_t * pool, const char * string);
786+
780787
void Info_Print( const char *s );
781788

782789
void Com_BeginRedirect (char *buffer, size_t buffersize, void (*flush)(char *), qboolean silent);

0 commit comments

Comments
 (0)