Bug in TSE profiler.cpp/stringTable.cpp
by Stewart Southern · in Torque Game Engine · 09/25/2006 (1:05 pm) · 14 replies
I think I've discovered a bug in TSE, but I suspect it's a bit of a niche bug. Also, I'm not a spectacular C++ programmer and I've only been working properly with the TSE source for a month, so bear with me.
My problem is that the method call void _StringTable::resize(const U32 newSize) in stringTable.cpp(182) get's stuck in the while loop on lines 194-200. While walking the buckets of the hash map containing the strings in StringTable the linked list starts referencing itself and the while loop never exits. Obviously under normal circumstances this shouldn't (and doesn't happen).
However, if you run TSE under debug mode it is possible to develop a string of calls which means that the resize method is called from within the resize method, and I believe it is this which messes up the linked list somehow, but I'm not sure how. Anyway, the problem lies in const char *Profiler::constructProfilePath(ProfilerData *pd) in profiler.cpp(258) calling StringTable::insert(buf) while memory is being allocated for the resizing of StringTables buckets. StringTable hasn't been resized yet and so resize() is called again from within insert() and the whole thing goes wrong. Run the release version and the profiler isn't used and everything works fine, but that doesn't help me debugging. I could just turn the profiler off, but again that's not a solution as such.
I've included the call stack from Visual C++ 2005 below. Ignore that it's all taking place in Adellion_Editor_DEBUG.exe, I work for HonourBound developing Adellion but we haven't edited and of the files involved.
Adellion_Editor_DEBUG.exe!_StringTable::resize(const unsigned int newSize=7339) Line 183 C++
Adellion_Editor_DEBUG.exe!_StringTable::insert(const char * val=0x020dc954, const bool caseSens=false) Line 134 C++
Adellion_Editor_DEBUG.exe!Profiler::constructProfilePath(ProfilerData * pd=0x01829c18) Line 273 + 0x11 bytes C++
Adellion_Editor_DEBUG.exe!Profiler::hashPush(ProfilerRootData * root=0x00fc3ea0) Line 344 + 0xc bytes C++
Adellion_Editor_DEBUG.exe!Mutex::lockMutex(void * mutex=0x020400a4, bool block=true) Line 29 C++
Adellion_Editor_DEBUG.exe!Memory::alloc(unsigned int size=58720, bool array=false, const char * fileName=0x00000000, const unsigned int line=0) Line 1025 + 0xd bytes C++
Adellion_Editor_DEBUG.exe!Memory::realloc(void * mem=0x023f2bb4, unsigned int size=58720) Line 1278 + 0xf bytes C++
Adellion_Editor_DEBUG.exe!dRealloc(void * in_pResize=0x023f2bb4, unsigned int in_size=58712) Line 1407 + 0xd bytes C++
Adellion_Editor_DEBUG.exe!_StringTable::resize(const unsigned int newSize=7339) Line 202 + 0x12 bytes C++
Adellion_Editor_DEBUG.exe!_StringTable::insert(const char * val=0x00136f78, const bool caseSens=false) Line 134 C++
I'm at a complete loss as to how to fix this, I could add a horribly inefficient hack to ensure that the linked list never self references, but that wouldn't be good. If anyone can throw some light on how to fix this that would be great.
Cheers,
Stewart Southern.
My problem is that the method call void _StringTable::resize(const U32 newSize) in stringTable.cpp(182) get's stuck in the while loop on lines 194-200. While walking the buckets of the hash map containing the strings in StringTable the linked list starts referencing itself and the while loop never exits. Obviously under normal circumstances this shouldn't (and doesn't happen).
However, if you run TSE under debug mode it is possible to develop a string of calls which means that the resize method is called from within the resize method, and I believe it is this which messes up the linked list somehow, but I'm not sure how. Anyway, the problem lies in const char *Profiler::constructProfilePath(ProfilerData *pd) in profiler.cpp(258) calling StringTable::insert(buf) while memory is being allocated for the resizing of StringTables buckets. StringTable hasn't been resized yet and so resize() is called again from within insert() and the whole thing goes wrong. Run the release version and the profiler isn't used and everything works fine, but that doesn't help me debugging. I could just turn the profiler off, but again that's not a solution as such.
I've included the call stack from Visual C++ 2005 below. Ignore that it's all taking place in Adellion_Editor_DEBUG.exe, I work for HonourBound developing Adellion but we haven't edited and of the files involved.
Adellion_Editor_DEBUG.exe!_StringTable::resize(const unsigned int newSize=7339) Line 183 C++
Adellion_Editor_DEBUG.exe!_StringTable::insert(const char * val=0x020dc954, const bool caseSens=false) Line 134 C++
Adellion_Editor_DEBUG.exe!Profiler::constructProfilePath(ProfilerData * pd=0x01829c18) Line 273 + 0x11 bytes C++
Adellion_Editor_DEBUG.exe!Profiler::hashPush(ProfilerRootData * root=0x00fc3ea0) Line 344 + 0xc bytes C++
Adellion_Editor_DEBUG.exe!Mutex::lockMutex(void * mutex=0x020400a4, bool block=true) Line 29 C++
Adellion_Editor_DEBUG.exe!Memory::alloc(unsigned int size=58720, bool array=false, const char * fileName=0x00000000, const unsigned int line=0) Line 1025 + 0xd bytes C++
Adellion_Editor_DEBUG.exe!Memory::realloc(void * mem=0x023f2bb4, unsigned int size=58720) Line 1278 + 0xf bytes C++
Adellion_Editor_DEBUG.exe!dRealloc(void * in_pResize=0x023f2bb4, unsigned int in_size=58712) Line 1407 + 0xd bytes C++
Adellion_Editor_DEBUG.exe!_StringTable::resize(const unsigned int newSize=7339) Line 202 + 0x12 bytes C++
Adellion_Editor_DEBUG.exe!_StringTable::insert(const char * val=0x00136f78, const bool caseSens=false) Line 134 C++
I'm at a complete loss as to how to fix this, I could add a horribly inefficient hack to ensure that the linked list never self references, but that wouldn't be good. If anyone can throw some light on how to fix this that would be great.
Cheers,
Stewart Southern.
#2
09/25/2006 (1:56 pm)
Hey, I'm happy I'M not the only one. I've run into this twice now, I just only sat down and tried to fathom the problem the second time around. Both times I was trying to add more persist fields to objects and I was beginning to think I was just doing something crazy stupid. Apparently not. :)
#3
If you don't know how to do this, you need to comment out # define TORQUE_ENABLE_PROFILE_PATH at lines 161 and 76 of torqueConfig.h.
For TSE to compile without errors you also need to edit gfxStructs.h(326) and gfxTextureObject.h(76) to put preprocessor commands around the calls to getProfilePath as follows:
#ifdef TORQUE_ENABLE_PROFILE_PATH // SIS - added for granularity of debugging.
mDebugCreationPath = gProfiler->getProfilePath();
#endif
Not an ideal solution, but it'll get the whole thing running again.
09/26/2006 (2:44 am)
Ok, I've just turned off profiler path generation for the time being. If you don't know how to do this, you need to comment out # define TORQUE_ENABLE_PROFILE_PATH at lines 161 and 76 of torqueConfig.h.
For TSE to compile without errors you also need to edit gfxStructs.h(326) and gfxTextureObject.h(76) to put preprocessor commands around the calls to getProfilePath as follows:
#ifdef TORQUE_ENABLE_PROFILE_PATH // SIS - added for granularity of debugging.
mDebugCreationPath = gProfiler->getProfilePath();
#endif
Not an ideal solution, but it'll get the whole thing running again.
#4
Does not that solve your problem, either?
09/26/2006 (3:36 am)
Oh, okay. It runs just fine here, I just can not keep the profiler enabled via profilerEnable ( true );Does not that solve your problem, either?
#5
09/27/2006 (1:56 am)
Yeah, turning the profiler off would probably also work (if that's what you mean?). That's not really a solution either though.
#6
09/27/2006 (2:46 am)
Sure is not. This is way over my head though and I have no solution. Hopefully someone else has one.
#7
09/28/2006 (7:29 pm)
Have you tried adding a check to make the it not resize the string table when generating profiler paths? Or alternatively, disable the profiler path generator func when in StringTable::resize?
#8
09/29/2006 (5:31 am)
No, I've just turned off the profiler completely and left it at that. I'm hoping you guys will fix it really, it's presumably your bug and I've not been using Torque long enough to want to be messing around with this kind of stuff.
#9
09/29/2006 (6:24 am)
And here I thought this was some bug I had introduced. I turned off the profile define awhile ago, and figured I'd solve the bug another day.
#10
The profiler (and tool that use it) is extremely useful and I'd strongly recommend people, if they do have to turn it off, review regularly to see if it's been fixed for their case. I personally use it very, very regularly in TSE development (with no ill effects... guess something's slightly different about my build), and love it.
So I realize that you may need to turn it off till we get a fix out but don't get into the habit of ignoring it. You will regret it. :)
09/29/2006 (10:28 am)
We surely will, but it takes a little while for stuff to make it out - so we're definitely addressing it on our end but till then it seems like good practice to help the community troubleshoot it as well. :)The profiler (and tool that use it) is extremely useful and I'd strongly recommend people, if they do have to turn it off, review regularly to see if it's been fixed for their case. I personally use it very, very regularly in TSE development (with no ill effects... guess something's slightly different about my build), and love it.
So I realize that you may need to turn it off till we get a fix out but don't get into the habit of ignoring it. You will regret it. :)
#11
09/29/2006 (11:06 am)
I did too disable the profiler, but I only had this issue with Debug builds.
#12
I don't actually know what the profiler does :( So I don't use it, no problem for me to just turn it off.
09/30/2006 (3:29 am)
Profiler is turned off in everything but debug builds, so that's not suprising.I don't actually know what the profiler does :( So I don't use it, no problem for me to just turn it off.
#13
This a good way to find where your game slows down, and to see how your code performs.
Heh. Not sure why you think the profiler only works in debug builds because that is definatly not true :p
09/30/2006 (4:43 am)
The profiler lets you set up profiler markers and measure the time taken between them.PROFILE_START ( Test ); printf ( "hello world" ); PROFILE_END ();
This a good way to find where your game slows down, and to see how your code performs.
Heh. Not sure why you think the profiler only works in debug builds because that is definatly not true :p
#14
10/01/2006 (2:18 pm)
Ah, because I only read so far down in the file, there's a definition in #TORQUE_DEBUG, but there's another one in #TORQUE_SHIPPING's else clause :)
Torque Owner Stefan Lundmark
Happy I'm not the only one!