From a91e5a2590f437e1f2630db657e02376546df6bc Mon Sep 17 00:00:00 2001 From: Vincent Gee Date: Tue, 4 Nov 2014 06:30:35 -0500 Subject: [PATCH] Improvements to SimDictionary for when you have a large number of objects in the game. Under light load (i.e. under 5000 objects) this code actually runs slower that the stock simdictionary. When you exceed 5000 objects, the template class actually runs faster and more consistently. --- Engine/source/console/simDictionary.cpp | 75 ++++++++++++++++++++----- Engine/source/console/simDictionary.h | 50 ++++++++++++++++- Templates/Empty/source/torqueConfig.h | 4 ++ Templates/Full/source/torqueConfig.h | 4 ++ 4 files changed, 116 insertions(+), 17 deletions(-) diff --git a/Engine/source/console/simDictionary.cpp b/Engine/source/console/simDictionary.cpp index dac603517..3e25828da 100644 --- a/Engine/source/console/simDictionary.cpp +++ b/Engine/source/console/simDictionary.cpp @@ -23,19 +23,24 @@ #include "console/simDictionary.h" #include "console/simBase.h" + //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- extern U32 HashPointer(StringTableEntry e); SimNameDictionary::SimNameDictionary() { +#ifdef USE_CLASSIC_SIMDICTIONARY hashTable = NULL; +#endif mutex = Mutex::createMutex(); } SimNameDictionary::~SimNameDictionary() { +#ifdef USE_CLASSIC_SIMDICTIONARY delete[] hashTable; +#endif Mutex::destroyMutex(mutex); } @@ -50,7 +55,7 @@ void SimNameDictionary::insert(SimObject* obj) Con::warnf("Warning! You have a duplicate datablock name of %s. This can cause problems. You should rename one of them.", obj->objectName); Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY if(!hashTable) { hashTable = new SimObject *[DefaultTableSize]; @@ -95,12 +100,15 @@ void SimNameDictionary::insert(SimObject* obj) hashTable = newHashTable; hashTableSize = newHashTableSize; } - +#else + root[StringTable->insert(obj->objectName)] = obj; +#endif Mutex::unlockMutex(mutex); } SimObject* SimNameDictionary::find(StringTableEntry name) { +#ifdef USE_CLASSIC_SIMDICTIONARY // NULL is a valid lookup - it will always return NULL if(!hashTable) return NULL; @@ -121,6 +129,12 @@ SimObject* SimNameDictionary::find(StringTableEntry name) Mutex::unlockMutex(mutex); return NULL; +#else + Mutex::lockMutex(mutex); + SimObject* f = root[StringTable->insert(name)]; + Mutex::unlockMutex(mutex); + return f; +#endif } void SimNameDictionary::remove(SimObject* obj) @@ -129,7 +143,7 @@ void SimNameDictionary::remove(SimObject* obj) return; Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize]; while(*walk) { @@ -144,7 +158,11 @@ void SimNameDictionary::remove(SimObject* obj) } walk = &((*walk)->nextNameObject); } - +#else + const char* name = StringTable->insert(obj->objectName); + if (root[name]) + root.erase(name); +#endif Mutex::unlockMutex(mutex); } @@ -152,18 +170,21 @@ void SimNameDictionary::remove(SimObject* obj) SimManagerNameDictionary::SimManagerNameDictionary() { +#ifdef USE_CLASSIC_SIMDICTIONARY hashTable = new SimObject *[DefaultTableSize]; hashTableSize = DefaultTableSize; hashEntryCount = 0; dMemset( hashTable, 0, sizeof( hashTable[ 0 ] ) * hashTableSize ); - +#endif mutex = Mutex::createMutex(); } SimManagerNameDictionary::~SimManagerNameDictionary() { +#ifdef USE_CLASSIC_SIMDICTIONARY delete[] hashTable; +#endif Mutex::destroyMutex(mutex); } @@ -173,7 +194,7 @@ void SimManagerNameDictionary::insert(SimObject* obj) return; Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY S32 idx = HashPointer(obj->objectName) % hashTableSize; obj->nextManagerNameObject = hashTable[idx]; hashTable[idx] = obj; @@ -209,7 +230,9 @@ void SimManagerNameDictionary::insert(SimObject* obj) hashTable = newHashTable; hashTableSize = newHashTableSize; } - +#else + root[StringTable->insert(obj->objectName)] = obj; +#endif Mutex::unlockMutex(mutex); } @@ -219,6 +242,7 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name) Mutex::lockMutex(mutex); +#ifdef USE_CLASSIC_SIMDICTIONARY S32 idx = HashPointer(name) % hashTableSize; SimObject *walk = hashTable[idx]; while(walk) @@ -230,9 +254,14 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name) } walk = walk->nextManagerNameObject; } - Mutex::unlockMutex(mutex); + return NULL; +#else + SimObject* f = root[StringTable->insert(name)]; + Mutex::unlockMutex(mutex); + return f; +#endif } void SimManagerNameDictionary::remove(SimObject* obj) @@ -240,6 +269,7 @@ void SimManagerNameDictionary::remove(SimObject* obj) if(!obj->objectName) return; +#ifdef USE_CLASSIC_SIMDICTIONARY Mutex::lockMutex(mutex); SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize]; @@ -256,7 +286,12 @@ void SimManagerNameDictionary::remove(SimObject* obj) } walk = &((*walk)->nextManagerNameObject); } +#else + const char* name = StringTable->insert(obj->objectName); + if (root[name]) + root.erase(name); +#endif Mutex::unlockMutex(mutex); } @@ -265,7 +300,9 @@ void SimManagerNameDictionary::remove(SimObject* obj) SimIdDictionary::SimIdDictionary() { +#ifdef USE_CLASSIC_SIMDICTIONARY dMemset( table, 0, sizeof( table[ 0 ] ) * DefaultTableSize ); +#endif mutex = Mutex::createMutex(); } @@ -274,22 +311,26 @@ SimIdDictionary::~SimIdDictionary() Mutex::destroyMutex(mutex); } + + void SimIdDictionary::insert(SimObject* obj) { Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY S32 idx = obj->getId() & TableBitMask; obj->nextIdObject = table[idx]; AssertFatal( obj->nextIdObject != obj, "SimIdDictionary::insert - Creating Infinite Loop linking to self!" ); table[idx] = obj; - +#else + root[obj->getId()] = obj; +#endif Mutex::unlockMutex(mutex); } SimObject* SimIdDictionary::find(S32 id) { Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY S32 idx = id & TableBitMask; SimObject *walk = table[idx]; while(walk) @@ -301,22 +342,28 @@ SimObject* SimIdDictionary::find(S32 id) } walk = walk->nextIdObject; } - Mutex::unlockMutex(mutex); return NULL; +#else + SimObject* f = root[id]; + Mutex::unlockMutex(mutex); + return f; +#endif } void SimIdDictionary::remove(SimObject* obj) { Mutex::lockMutex(mutex); - +#ifdef USE_CLASSIC_SIMDICTIONARY SimObject **walk = &table[obj->getId() & TableBitMask]; while(*walk && *walk != obj) walk = &((*walk)->nextIdObject); if(*walk) *walk = obj->nextIdObject; - +#else + root.erase(obj->getId()); +#endif Mutex::unlockMutex(mutex); } diff --git a/Engine/source/console/simDictionary.h b/Engine/source/console/simDictionary.h index 75fc075e2..5dddf4bbe 100644 --- a/Engine/source/console/simDictionary.h +++ b/Engine/source/console/simDictionary.h @@ -33,8 +33,37 @@ #include "platform/threads/mutex.h" #endif +#include +#include + +#include "TorqueConfig.h" + + class SimObject; +#include "core/strings/stringFunctions.h" + +struct my_hash { + inline size_t operator()(const char* val) const + { + return (long)val; + } + }; + + struct eqstr { + inline bool operator()(const char *s1, const char *s2) const { + return dStrcmp(s1, s2) == 0; + } + }; + + +#ifndef USE_CLASSIC_SIMDICTIONARY +typedef std::unordered_map StringDictDef; +typedef std::unordered_map U32DictDef; +#endif + + + //---------------------------------------------------------------------------- /// Map of names to SimObjects /// @@ -42,6 +71,7 @@ class SimObject; /// for fast removal of an object given object* class SimNameDictionary { +#ifdef USE_CLASSIC_SIMDICTIONARY enum { DefaultTableSize = 29 @@ -50,9 +80,13 @@ class SimNameDictionary SimObject **hashTable; // hash the pointers of the names... S32 hashTableSize; S32 hashEntryCount; - +#else + StringDictDef root; +#endif void *mutex; + + public: void insert(SimObject* obj); void remove(SimObject* obj); @@ -64,6 +98,7 @@ public: class SimManagerNameDictionary { +#ifdef USE_CLASSIC_SIMDICTIONARY enum { DefaultTableSize = 29 @@ -73,8 +108,14 @@ class SimManagerNameDictionary S32 hashTableSize; S32 hashEntryCount; - void *mutex; + +#else + + StringDictDef root; + +#endif + void *mutex; public: void insert(SimObject* obj); void remove(SimObject* obj); @@ -91,13 +132,16 @@ public: /// for fast removal of an object given object* class SimIdDictionary { +#ifdef USE_CLASSIC_SIMDICTIONARY enum { DefaultTableSize = 4096, TableBitMask = 4095 }; SimObject *table[DefaultTableSize]; - +#else + U32DictDef root; +#endif void *mutex; public: diff --git a/Templates/Empty/source/torqueConfig.h b/Templates/Empty/source/torqueConfig.h index d9de1b1d1..7e433f67b 100644 --- a/Templates/Empty/source/torqueConfig.h +++ b/Templates/Empty/source/torqueConfig.h @@ -31,6 +31,10 @@ //general, the information here is global for your entire codebase, applying //not only to your game proper, but also to all of your tools. +//If you plan to have less than 5000 objects use the Classic SimDictionary, if you plan to have more than +//5000 objects use the new SimDictionary. + +#define USE_CLASSIC_SIMDICTIONARY /// What's the name of your application? Used in a variety of places. #define TORQUE_APP_NAME "Empty" diff --git a/Templates/Full/source/torqueConfig.h b/Templates/Full/source/torqueConfig.h index 4d8f124f2..777e39a37 100644 --- a/Templates/Full/source/torqueConfig.h +++ b/Templates/Full/source/torqueConfig.h @@ -31,6 +31,10 @@ //general, the information here is global for your entire codebase, applying //not only to your game proper, but also to all of your tools. +//If you plan to have less than 5000 objects use the Classic SimDictionary, if you plan to have more than +//5000 objects use the new SimDictionary. + +#define USE_CLASSIC_SIMDICTIONARY /// What's the name of your application? Used in a variety of places. #define TORQUE_APP_NAME "Full"