Browse Source

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.

Vincent Gee 10 years ago
parent
commit
a91e5a2590

+ 61 - 14
Engine/source/console/simDictionary.cpp

@@ -23,19 +23,24 @@
 #include "console/simDictionary.h"
 #include "console/simDictionary.h"
 #include "console/simBase.h"
 #include "console/simBase.h"
 
 
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 extern U32 HashPointer(StringTableEntry e);
 extern U32 HashPointer(StringTableEntry e);
 
 
 SimNameDictionary::SimNameDictionary()
 SimNameDictionary::SimNameDictionary()
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    hashTable = NULL;
    hashTable = NULL;
+#endif
    mutex = Mutex::createMutex();
    mutex = Mutex::createMutex();
 }
 }
 
 
 SimNameDictionary::~SimNameDictionary()
 SimNameDictionary::~SimNameDictionary()
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    delete[] hashTable;
    delete[] hashTable;
+#endif
    Mutex::destroyMutex(mutex);
    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);
       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);
    Mutex::lockMutex(mutex);
-   
+#ifdef USE_CLASSIC_SIMDICTIONARY
    if(!hashTable)
    if(!hashTable)
    {
    {
       hashTable = new SimObject *[DefaultTableSize];
       hashTable = new SimObject *[DefaultTableSize];
@@ -95,12 +100,15 @@ void SimNameDictionary::insert(SimObject* obj)
       hashTable = newHashTable;
       hashTable = newHashTable;
       hashTableSize = newHashTableSize;
       hashTableSize = newHashTableSize;
    }
    }
-   
+#else
+   root[StringTable->insert(obj->objectName)] = obj;
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }
 }
 
 
 SimObject* SimNameDictionary::find(StringTableEntry name)
 SimObject* SimNameDictionary::find(StringTableEntry name)
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    // NULL is a valid lookup - it will always return NULL
    // NULL is a valid lookup - it will always return NULL
    if(!hashTable)
    if(!hashTable)
       return NULL;
       return NULL;
@@ -121,6 +129,12 @@ SimObject* SimNameDictionary::find(StringTableEntry name)
 
 
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
    return NULL;
    return NULL;
+#else
+  Mutex::lockMutex(mutex);
+  SimObject* f = root[StringTable->insert(name)];
+  Mutex::unlockMutex(mutex);
+  return f;
+#endif
 }
 }
 
 
 void SimNameDictionary::remove(SimObject* obj)
 void SimNameDictionary::remove(SimObject* obj)
@@ -129,7 +143,7 @@ void SimNameDictionary::remove(SimObject* obj)
       return;
       return;
 
 
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
-
+#ifdef USE_CLASSIC_SIMDICTIONARY
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
    while(*walk)
    while(*walk)
    {
    {
@@ -144,7 +158,11 @@ void SimNameDictionary::remove(SimObject* obj)
       }
       }
       walk = &((*walk)->nextNameObject);
       walk = &((*walk)->nextNameObject);
    }
    }
-
+#else
+   const char* name = StringTable->insert(obj->objectName);
+   if (root[name])
+	   root.erase(name);
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }	
 }	
 
 
@@ -152,18 +170,21 @@ void SimNameDictionary::remove(SimObject* obj)
 
 
 SimManagerNameDictionary::SimManagerNameDictionary()
 SimManagerNameDictionary::SimManagerNameDictionary()
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    hashTable = new SimObject *[DefaultTableSize];
    hashTable = new SimObject *[DefaultTableSize];
    hashTableSize = DefaultTableSize;
    hashTableSize = DefaultTableSize;
    hashEntryCount = 0;
    hashEntryCount = 0;
    
    
    dMemset( hashTable, 0, sizeof( hashTable[ 0 ] ) * hashTableSize );
    dMemset( hashTable, 0, sizeof( hashTable[ 0 ] ) * hashTableSize );
-
+#endif
    mutex = Mutex::createMutex();
    mutex = Mutex::createMutex();
 }
 }
 
 
 SimManagerNameDictionary::~SimManagerNameDictionary()
 SimManagerNameDictionary::~SimManagerNameDictionary()
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    delete[] hashTable;
    delete[] hashTable;
+#endif
    Mutex::destroyMutex(mutex);
    Mutex::destroyMutex(mutex);
 }
 }
 
 
@@ -173,7 +194,7 @@ void SimManagerNameDictionary::insert(SimObject* obj)
       return;
       return;
 
 
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
-
+#ifdef USE_CLASSIC_SIMDICTIONARY
    S32 idx = HashPointer(obj->objectName) % hashTableSize;
    S32 idx = HashPointer(obj->objectName) % hashTableSize;
    obj->nextManagerNameObject = hashTable[idx];
    obj->nextManagerNameObject = hashTable[idx];
    hashTable[idx] = obj;
    hashTable[idx] = obj;
@@ -209,7 +230,9 @@ void SimManagerNameDictionary::insert(SimObject* obj)
       hashTable = newHashTable;
       hashTable = newHashTable;
       hashTableSize = newHashTableSize;
       hashTableSize = newHashTableSize;
    }
    }
-   
+#else
+   root[StringTable->insert(obj->objectName)] = obj;
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }
 }
 
 
@@ -219,6 +242,7 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name)
 
 
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
 
 
+#ifdef USE_CLASSIC_SIMDICTIONARY
    S32 idx = HashPointer(name) % hashTableSize;
    S32 idx = HashPointer(name) % hashTableSize;
    SimObject *walk = hashTable[idx];
    SimObject *walk = hashTable[idx];
    while(walk)
    while(walk)
@@ -230,9 +254,14 @@ SimObject* SimManagerNameDictionary::find(StringTableEntry name)
       }
       }
       walk = walk->nextManagerNameObject;
       walk = walk->nextManagerNameObject;
    }
    }
-
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
+
    return NULL;
    return NULL;
+#else
+   SimObject* f = root[StringTable->insert(name)];	
+   Mutex::unlockMutex(mutex);
+   return f;
+#endif
 }
 }
 
 
 void SimManagerNameDictionary::remove(SimObject* obj)
 void SimManagerNameDictionary::remove(SimObject* obj)
@@ -240,6 +269,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
    if(!obj->objectName)
    if(!obj->objectName)
       return;
       return;
 
 
+#ifdef USE_CLASSIC_SIMDICTIONARY
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
 
 
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
    SimObject **walk = &hashTable[HashPointer(obj->objectName) % hashTableSize];
@@ -256,7 +286,12 @@ void SimManagerNameDictionary::remove(SimObject* obj)
       }
       }
       walk = &((*walk)->nextManagerNameObject);
       walk = &((*walk)->nextManagerNameObject);
    }
    }
+#else
 
 
+	const char* name = StringTable->insert(obj->objectName);
+	if (root[name])
+		root.erase(name);
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }	
 }	
 
 
@@ -265,7 +300,9 @@ void SimManagerNameDictionary::remove(SimObject* obj)
 
 
 SimIdDictionary::SimIdDictionary()
 SimIdDictionary::SimIdDictionary()
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    dMemset( table, 0, sizeof( table[ 0 ] ) * DefaultTableSize );
    dMemset( table, 0, sizeof( table[ 0 ] ) * DefaultTableSize );
+#endif
    mutex = Mutex::createMutex();
    mutex = Mutex::createMutex();
 }
 }
 
 
@@ -274,22 +311,26 @@ SimIdDictionary::~SimIdDictionary()
    Mutex::destroyMutex(mutex);
    Mutex::destroyMutex(mutex);
 }
 }
 
 
+
+
 void SimIdDictionary::insert(SimObject* obj)
 void SimIdDictionary::insert(SimObject* obj)
 {
 {
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
-
+#ifdef USE_CLASSIC_SIMDICTIONARY
    S32 idx = obj->getId() & TableBitMask;
    S32 idx = obj->getId() & TableBitMask;
    obj->nextIdObject = table[idx];
    obj->nextIdObject = table[idx];
    AssertFatal( obj->nextIdObject != obj, "SimIdDictionary::insert - Creating Infinite Loop linking to self!" );
    AssertFatal( obj->nextIdObject != obj, "SimIdDictionary::insert - Creating Infinite Loop linking to self!" );
    table[idx] = obj;
    table[idx] = obj;
-
+#else
+   root[obj->getId()] = obj;
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }
 }
 
 
 SimObject* SimIdDictionary::find(S32 id)
 SimObject* SimIdDictionary::find(S32 id)
 {
 {
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
-
+#ifdef USE_CLASSIC_SIMDICTIONARY
    S32 idx = id & TableBitMask;
    S32 idx = id & TableBitMask;
    SimObject *walk = table[idx];
    SimObject *walk = table[idx];
    while(walk)
    while(walk)
@@ -301,22 +342,28 @@ SimObject* SimIdDictionary::find(S32 id)
       }
       }
       walk = walk->nextIdObject;
       walk = walk->nextIdObject;
    }
    }
-
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 
 
    return NULL;
    return NULL;
+#else
+   SimObject* f = root[id];
+   Mutex::unlockMutex(mutex);
+   return f;
+#endif
 }
 }
 
 
 void SimIdDictionary::remove(SimObject* obj)
 void SimIdDictionary::remove(SimObject* obj)
 {
 {
    Mutex::lockMutex(mutex);
    Mutex::lockMutex(mutex);
-
+#ifdef USE_CLASSIC_SIMDICTIONARY
    SimObject **walk = &table[obj->getId() & TableBitMask];
    SimObject **walk = &table[obj->getId() & TableBitMask];
    while(*walk && *walk != obj)
    while(*walk && *walk != obj)
       walk = &((*walk)->nextIdObject);
       walk = &((*walk)->nextIdObject);
    if(*walk)
    if(*walk)
       *walk = obj->nextIdObject;
       *walk = obj->nextIdObject;
-
+#else
+   root.erase(obj->getId());
+#endif
    Mutex::unlockMutex(mutex);
    Mutex::unlockMutex(mutex);
 }
 }
 
 

+ 47 - 3
Engine/source/console/simDictionary.h

@@ -33,8 +33,37 @@
 #include "platform/threads/mutex.h"
 #include "platform/threads/mutex.h"
 #endif
 #endif
 
 
+#include <string>
+#include <unordered_map>
+
+#include "TorqueConfig.h"
+
+
 class SimObject;
 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<const char * , SimObject*, my_hash, eqstr>  StringDictDef;	
+typedef std::unordered_map<U32 ,SimObject*> U32DictDef;	
+#endif
+
+
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 /// Map of names to SimObjects
 /// Map of names to SimObjects
 ///
 ///
@@ -42,6 +71,7 @@ class SimObject;
 /// for fast removal of an object given object*
 /// for fast removal of an object given object*
 class SimNameDictionary
 class SimNameDictionary
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    enum
    enum
    {
    {
       DefaultTableSize = 29
       DefaultTableSize = 29
@@ -50,9 +80,13 @@ class SimNameDictionary
    SimObject **hashTable;  // hash the pointers of the names...
    SimObject **hashTable;  // hash the pointers of the names...
    S32 hashTableSize;
    S32 hashTableSize;
    S32 hashEntryCount;
    S32 hashEntryCount;
-
+#else
+   StringDictDef root;
+#endif
    void *mutex;
    void *mutex;
 
 
+
+
 public:
 public:
    void insert(SimObject* obj);
    void insert(SimObject* obj);
    void remove(SimObject* obj);
    void remove(SimObject* obj);
@@ -64,6 +98,7 @@ public:
 
 
 class SimManagerNameDictionary
 class SimManagerNameDictionary
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    enum
    enum
    {
    {
       DefaultTableSize = 29
       DefaultTableSize = 29
@@ -73,8 +108,14 @@ class SimManagerNameDictionary
    S32 hashTableSize;
    S32 hashTableSize;
    S32 hashEntryCount;
    S32 hashEntryCount;
 
 
-   void *mutex;
+   
+#else
+
+   
+   StringDictDef root;
 
 
+#endif
+   void *mutex;
 public:
 public:
    void insert(SimObject* obj);
    void insert(SimObject* obj);
    void remove(SimObject* obj);
    void remove(SimObject* obj);
@@ -91,13 +132,16 @@ public:
 /// for fast removal of an object given object*
 /// for fast removal of an object given object*
 class SimIdDictionary
 class SimIdDictionary
 {
 {
+#ifdef USE_CLASSIC_SIMDICTIONARY
    enum
    enum
    {
    {
       DefaultTableSize = 4096,
       DefaultTableSize = 4096,
       TableBitMask = 4095
       TableBitMask = 4095
    };
    };
    SimObject *table[DefaultTableSize];
    SimObject *table[DefaultTableSize];
-
+#else
+   U32DictDef root;
+#endif
    void *mutex;
    void *mutex;
 
 
 public:
 public:

+ 4 - 0
Templates/Empty/source/torqueConfig.h

@@ -31,6 +31,10 @@
 //general, the information here is global for your entire codebase, applying
 //general, the information here is global for your entire codebase, applying
 //not only to your game proper, but also to all of your tools.
 //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.
 /// What's the name of your application? Used in a variety of places.
 #define TORQUE_APP_NAME            "Empty"
 #define TORQUE_APP_NAME            "Empty"
 
 

+ 4 - 0
Templates/Full/source/torqueConfig.h

@@ -31,6 +31,10 @@
 //general, the information here is global for your entire codebase, applying
 //general, the information here is global for your entire codebase, applying
 //not only to your game proper, but also to all of your tools.
 //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.
 /// What's the name of your application? Used in a variety of places.
 #define TORQUE_APP_NAME            "Full"
 #define TORQUE_APP_NAME            "Full"