Memory: Non-Functional: Rationalize and improve encapsulation of TLS usage.

This will make the next (functional) commit easier to see.
This commit is contained in:
John Kessenich 2017-11-12 15:28:58 -07:00
parent a36997cb4a
commit be20905582
7 changed files with 70 additions and 58 deletions

View File

@ -45,6 +45,10 @@ namespace glslang {
OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
// Per-process initialization.
// Needs to be called at least once before parsing, etc. is done.
// Will also do thread initialization for the calling thread; other
// threads will need to do that explicitly.
bool InitProcess() bool InitProcess()
{ {
glslang::GetGlobalLock(); glslang::GetGlobalLock();
@ -85,7 +89,9 @@ bool InitProcess()
return true; return true;
} }
// Per-thread scoped initialization.
// Must be called at least once by each new thread sharing the
// symbol tables, etc., needed to parse.
bool InitThread() bool InitThread()
{ {
// //
@ -109,7 +115,9 @@ bool InitThread()
return true; return true;
} }
// Thread-scoped tear down. Needs to be done by all but the last
// thread, which calls DetachProcess() instead.
// NB. TODO: Not currently being executed by each thread.
bool DetachThread() bool DetachThread()
{ {
bool success = true; bool success = true;
@ -126,13 +134,13 @@ bool DetachThread()
success = false; success = false;
} }
FreeGlobalPools(); FreeMemoryPools();
} }
return success; return success;
} }
// Process-scoped tear down. Needs to be done by final thread in process.
bool DetachProcess() bool DetachProcess()
{ {
bool success = true; bool success = true;

View File

@ -40,7 +40,7 @@ namespace glslang {
bool InitProcess(); bool InitProcess();
bool InitThread(); bool InitThread();
bool DetachThread(); bool DetachThread(); // TODO: use this or remove it; ideally make it unneeded
bool DetachProcess(); bool DetachProcess();
} // end namespace glslang } // end namespace glslang

View File

@ -38,7 +38,8 @@
namespace glslang { namespace glslang {
void InitializeMemoryPools(); void InitializeMemoryPools();
void FreeGlobalPools(); void FreeMemoryPools();
bool InitializePoolIndex(); bool InitializePoolIndex();
void FreePoolIndex(); void FreePoolIndex();

View File

@ -250,15 +250,8 @@ private:
// different times. But a simple use is to have a global pop // different times. But a simple use is to have a global pop
// with everyone using the same global allocator. // with everyone using the same global allocator.
// //
typedef TPoolAllocator* PoolAllocatorPointer;
extern TPoolAllocator& GetThreadPoolAllocator(); extern TPoolAllocator& GetThreadPoolAllocator();
void SetThreadPoolAllocator(TPoolAllocator* poolAllocator);
struct TThreadMemoryPools
{
TPoolAllocator* threadPoolAllocator;
};
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
// //
// This STL compatible allocator is intended to be used as the allocator // This STL compatible allocator is intended to be used as the allocator

View File

@ -40,35 +40,40 @@
namespace glslang { namespace glslang {
// Process-wide TLS index
OS_TLSIndex PoolIndex; OS_TLSIndex PoolIndex;
void InitializeMemoryPools() // Per-thread structure holding pool pointers.
struct TThreadMemoryPools
{ {
TThreadMemoryPools* pools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex)); TPoolAllocator* threadPoolAllocator; // the current pool
if (pools) };
return;
TPoolAllocator *threadPoolAllocator = new TPoolAllocator(); // Return the thread-specific pool pointers.
TThreadMemoryPools* GetThreadMemoryPools()
TThreadMemoryPools* threadData = new TThreadMemoryPools(); {
return static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
threadData->threadPoolAllocator = threadPoolAllocator;
OS_SetTLSValue(PoolIndex, threadData);
} }
void FreeGlobalPools() // Set the thread-specific pool pointers.
void SetThreadMemoryPools(TThreadMemoryPools* pools)
{ {
// Release the allocated memory for this thread. OS_SetTLSValue(PoolIndex, pools);
TThreadMemoryPools* globalPools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
if (! globalPools)
return;
GetThreadPoolAllocator().popAll();
delete &GetThreadPoolAllocator();
delete globalPools;
} }
// Return the thread-specific current pool.
TPoolAllocator& GetThreadPoolAllocator()
{
return *GetThreadMemoryPools()->threadPoolAllocator;
}
// Set the thread-specific current pool.
void SetThreadPoolAllocator(TPoolAllocator* poolAllocator)
{
GetThreadMemoryPools()->threadPoolAllocator = poolAllocator;
}
// Process-wide set up of the TLS pool storage.
bool InitializePoolIndex() bool InitializePoolIndex()
{ {
// Allocate a TLS index. // Allocate a TLS index.
@ -78,24 +83,30 @@ bool InitializePoolIndex()
return true; return true;
} }
// Process-wide tear down of the TLS pool storage.
void FreePoolIndex() void FreePoolIndex()
{ {
// Release the TLS index. // Release the TLS index.
OS_FreeTLSIndex(PoolIndex); OS_FreeTLSIndex(PoolIndex);
} }
TPoolAllocator& GetThreadPoolAllocator() // Per-thread set up of the memory pools.
void InitializeMemoryPools()
{ {
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex)); if (GetThreadMemoryPools() == nullptr) {
SetThreadMemoryPools(new TThreadMemoryPools());
return *threadData->threadPoolAllocator; SetThreadPoolAllocator(new TPoolAllocator());
}
} }
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator) // Per-thread tear down of the memory pools.
void FreeMemoryPools()
{ {
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex)); if (GetThreadMemoryPools() != nullptr) {
GetThreadPoolAllocator().popAll();
threadData->threadPoolAllocator = &poolAllocator; delete &GetThreadPoolAllocator();
delete GetThreadMemoryPools();
}
} }
// //

View File

@ -217,7 +217,7 @@ enum EPrecisionClass {
TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {}; TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {}; TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
TPoolAllocator* PerProcessGPA = 0; TPoolAllocator* PerProcessGPA = nullptr;
// //
// Parse and add to the given symbol table the content of the given shader string. // Parse and add to the given symbol table the content of the given shader string.
@ -361,7 +361,7 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
// pool allocator intact, so: // pool allocator intact, so:
// - Switch to a new pool for parsing the built-ins // - Switch to a new pool for parsing the built-ins
// - Do the parsing, which builds the symbol table, using the new pool // - Do the parsing, which builds the symbol table, using the new pool
// - Switch to the process-global pool to save a copy the resulting symbol table // - Switch to the process-global pool to save a copy of the resulting symbol table
// - Free up the new pool used to parse the built-ins // - Free up the new pool used to parse the built-ins
// - Switch back to the original thread's pool // - Switch back to the original thread's pool
// //
@ -388,8 +388,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
// Switch to a new pool // Switch to a new pool
TPoolAllocator& previousAllocator = GetThreadPoolAllocator(); TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator(); TPoolAllocator* builtInPoolAllocator = new TPoolAllocator;
SetThreadPoolAllocator(*builtInPoolAllocator); SetThreadPoolAllocator(builtInPoolAllocator);
// Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped. // Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
TSymbolTable* commonTable[EPcCount]; TSymbolTable* commonTable[EPcCount];
@ -403,7 +403,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source); InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
// Switch to the process-global pool // Switch to the process-global pool
SetThreadPoolAllocator(*PerProcessGPA); SetThreadPoolAllocator(PerProcessGPA);
// Copy the local symbol tables from the new pool to the global tables using the process-global pool // Copy the local symbol tables from the new pool to the global tables using the process-global pool
for (int precClass = 0; precClass < EPcCount; ++precClass) { for (int precClass = 0; precClass < EPcCount; ++precClass) {
@ -430,7 +430,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
delete stageTables[stage]; delete stageTables[stage];
delete builtInPoolAllocator; delete builtInPoolAllocator;
SetThreadPoolAllocator(previousAllocator); SetThreadPoolAllocator(&previousAllocator);
glslang::ReleaseGlobalLock(); glslang::ReleaseGlobalLock();
} }
@ -1196,7 +1196,7 @@ int ShInitialize()
if (! InitProcess()) if (! InitProcess())
return 0; return 0;
if (! PerProcessGPA) if (PerProcessGPA == nullptr)
PerProcessGPA = new TPoolAllocator(); PerProcessGPA = new TPoolAllocator();
glslang::TScanContext::fillInKeywordMap(); glslang::TScanContext::fillInKeywordMap();
@ -1288,10 +1288,10 @@ int __fastcall ShFinalize()
} }
} }
if (PerProcessGPA) { if (PerProcessGPA != nullptr) {
PerProcessGPA->popAll(); PerProcessGPA->popAll();
delete PerProcessGPA; delete PerProcessGPA;
PerProcessGPA = 0; PerProcessGPA = nullptr;
} }
glslang::TScanContext::deleteKeywordMap(); glslang::TScanContext::deleteKeywordMap();
@ -1708,7 +1708,7 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
return false; return false;
pool = new TPoolAllocator(); pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool); SetThreadPoolAllocator(pool);
if (! preamble) if (! preamble)
preamble = ""; preamble = "";
@ -1732,7 +1732,7 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources,
return false; return false;
pool = new TPoolAllocator(); pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool); SetThreadPoolAllocator(pool);
if (! preamble) if (! preamble)
preamble = ""; preamble = "";
@ -1789,7 +1789,7 @@ bool TProgram::link(EShMessages messages)
bool error = false; bool error = false;
pool = new TPoolAllocator(); pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool); SetThreadPoolAllocator(pool);
for (int s = 0; s < EShLangCount; ++s) { for (int s = 0; s < EShLangCount; ++s) {
if (! linkStage((EShLanguage)s, messages)) if (! linkStage((EShLanguage)s, messages))

View File

@ -68,15 +68,14 @@
#endif #endif
// //
// Driver must call this first, once, before doing any other // Call before doing any other compiler/linker operations.
// compiler/linker operations.
// //
// (Call once per process, not once per thread.) // (Call once per process, not once per thread.)
// //
SH_IMPORT_EXPORT int ShInitialize(); SH_IMPORT_EXPORT int ShInitialize();
// //
// Driver should call this at process shutdown. // Call this at process shutdown to clean up memory.
// //
SH_IMPORT_EXPORT int __fastcall ShFinalize(); SH_IMPORT_EXPORT int __fastcall ShFinalize();
@ -290,7 +289,7 @@ SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char*
// Deferred-Lowering C++ Interface // Deferred-Lowering C++ Interface
// ----------------------------------- // -----------------------------------
// //
// Below is a new alternate C++ interface that might potentially replace the above // Below is a new alternate C++ interface, which deprecates the above
// opaque handle-based interface. // opaque handle-based interface.
// //
// The below is further designed to handle multiple compilation units per stage, where // The below is further designed to handle multiple compilation units per stage, where