UT2003 Function history (Howd they do that?)

Started by
29 comments, last by Ximmer 21 years, 5 months ago
In UT2003 (Unreal Tournament 2003) when I get a crash I get an error message that states the nature of what killed the game. But underneath this description theres a Function history of Where this crash occured... So seeing this I thought to myself "That''d be a great thing to add to my engine!" And so I did. And I did behold that my framerate proceeded to die... on further inspection by running it through the VC6 Profiler in Release mode the 2 functions I used were taking up a very large portion of the Cpu time. (Usually within the top 5) These are the Methods I tried...
  
void MyClass::MyFunction()
{
	HistoryStart("MyClass::MyFunction");

	// Do Stuff in Here


	HistoryEnd();
}
  
this one was by far the worst as I had to copy the string into a new memory location and then add it to my Linked List of Function Names.
  
void MyClass::MyFunction()
{
	static const char s_History[] = "MyClass::MyFunction";
	HistoryStart(s_History);

	// Do Stuff in Here


	HistoryEnd();
}
  
This one was better as I could avoid a call to new and delete... but it still had a Massive impact on my framerate...
  
__inline HistoryStart(const char *FunctionName)
{
	// Add new Node to Stack

}

__inline HistoryEnd()
{
	// Remove Node from Stack

}

void MyClass::MyFunction()
{
	static const char s_History[] = "MyClass::MyFunction";
	HistoryStart(s_History);

	// Do Stuff in Here


	HistoryEnd();
}
  
This method produces some pretty good results... It finally got HistoryStart below the #1 Cpu user slot... but now it''s in the #2 slot... Can anyone think of a more efficient way of doing this? -Ximmer
Advertisement
All depends on what you do in HistoryStart( const char* )

Because you''ll always be passing constant strings you don''t need to allocate new memory with new, neither do you have to declare a static local variable, you simply pass the const char to the function and store it in a stack.

Dunno how you implemented the stack but the easiest way and probably the fastest will be a simple array of pointers: Adding will simply requring assigning the pointer address and incrementing the stack pointer, that should be pretty fast. Removing is a simple decrement of the stack pointer.
The downside of using the array of pointers is obviously that there''ll have to be a limit to the number of allowed entries you can add.

Calling this in tight inner loops is probably not a good idea.


Hope this can help.

You got me interested in doing this as well now
<$1,000,000 signature goes here>
Hmmm... I wonder how this one would go for performance.

  void MyClass::MyFunction(){  try {    // stuff  }  catch (MyException& e) {    HistoryStart("MyClass::MyFunction"); // might want to rename HistoryStart if you do it this way...    throw e;  }}  
Huh? Wouldn''t this work:

  std::stack<const char*> functionHistory;inline HistoryStart(const char* text) {  functionHistory.push(text);}inline HistoryEnd() {  functionHistory.pop();}//preferably wrap the stuff above inside a class!void MyClass::MyFunction() {  HistoryStart("MyClass::MyFunction");  // Do Stuff in Here  HistoryEnd();}int main() {  try {    //run your program here  } catch (...) {    std::copy(functionHistory.begin(), functionHistory.end(), std::ostream_iterator<const char*>(cout, "\n");  }}  

All that thing does is a single pointer copy + incrementing (Start) and decrementing (End) the stack index (assuming the stack is implemented as a vector and is big enough). Shouldn''t take too much calculation time..
still you don''t want to have that in an inner loop, huh?

I think the looking into the public headers of unreal (that also featured this history thingy) should shed light on this...
For what it''s worth:

http://www.vsl.gifu-u.ac.jp/unreal/UnrealTips/dll/guard.htm

see the guard/unguard macros, i believe they''re what you''re after...
Hmmm some very interesting suggestions... that Exception one looks interesting but I don''t know if it''s what i was looking for... But I''ve settled on this one for now (Don''t want to optimize too much too early)


  struct History{	const char * m_Name;	History *m_Next;};extern History * g_HistoryHead;History * g_HistoryHead = NULL; // In another File__inline void XHistoryAdd(const char *Str){	History *h = new History;	h->m_Name = Str;	h->m_Next = g_HistoryHead;	g_HistoryHead = h;}__inline void XHistoryEnd(){	History *h = g_HistoryHead;	g_HistoryHead = h->m_Next;	delete h;}  


I think about the only way I can improve on that is like what Jaco said and use a Fixed array... but I''m afraid that I may get into Recursive functions that may overload that...

And I actually made HistoryStart into a Macro so I don''t have to make the static const char * myself

#define XHistoryStart(x) static const char s_History[] = x; XHistoryAdd(s_History);
Yep, that''ll work.
Just did a quick test and stepped through the teplate code...
with every push() called new is called in the teplates allocator, which is going to slow you down big time.
With pop(), delete is called.

No doubt that you will get a big performance improvement when implementing your own stack class.


<$1,000,000 signature goes here>
the way they do it is shown in the SDK for their opengl drivers with the original unreal.

they have two macros called guard and unguard. you put the name of the class and function (or whatever you want) in 'guard' and then at the end of the block you put 'unguard'

...i've just downloaded it for you and it's in Core\Inc\UnFile.h line 101 onwards

i just checked and it's also in the unreal tournament developers kit so take your pick

website
unreal
ut

i could just post the code i guess, but if you download the zips you can see how they're used too.

i've modified them and use them in my own work. they make a try catch block and are disabled in debug. basically they stop the program crashing horribly and, as tim sweeney said when i asked him, 'they're for in the field debugging'.

[edited by - petewood on October 18, 2002 3:40:18 AM]
ohh... and the XHistroyAdd function was called about 96 million times for about 8000 frames...

This topic is closed to new replies.

Advertisement