detect slow script functions: setExecDurationWarnThreshhold()
by Orion Elenzil · 04/17/2009 (3:07 pm) · 6 comments
new torqueScript diagnostic tool: setExecDurationWarnThreshhold().
this resource implements a new torqueScript function, setExecDurationWarnThreshhold(),
which will print a warning when any script codeblock takes "a long time" to execute.
i believe there is no performance overhead for this monitoring.
first, here are some examples for motivation:
here's a more real-world example from a particularly slow call from some code,
with the threshhold set to 50ms. (this is a debug build, sort of artificially slow)
you can pretty immediately see that ClosetTabs::tabSelected() might be worth looking at:
and here's the modifications to a TGE 1.3.5 codebase.
all the modification are here, but familiarity with C++ and the Torque source code is assumed.
caveat: i'm seeing that my codebase is actually a bit different than a stock TGE 1.4 codebase,
so i've adapted to what i think should work, but have not actually tested this exact changeset.
consoleInternal.h
in the class ExprEvalState, after bool traceOn;, add:
consoleInternal.cc
in the class ExprEvalState, after traceOn = false;, add:
consoleFunctions.cc
after the console function "trace" ( search for ConsoleFunction(trace ), add this console function:
compiledEval.cc, in the method CodeBlock::exec()
up near the top along with the declaration of curStringTable, add:
just before gEvalState.pushFrame(thisFunctionName, thisNamespace);, insert:
down just below execFinished:, add:
.. and that should do it.
this resource implements a new torqueScript function, setExecDurationWarnThreshhold(),
which will print a warning when any script codeblock takes "a long time" to execute.
i believe there is no performance overhead for this monitoring.
first, here are some examples for motivation:
==>function hardSleep(%ms) { %a = getRealTime(); %b = %a; while (mSubS32(%b, %a) < %ms) { %b = getRealTime(); } }
==>function foo(%ms) { hardSleep(%ms); }
==>setExecDurationWarnThreshhold(1500);
==>foo(1500);
slow codeblock - 1500ms - hardSleep()
slow codeblock - 1500ms - foo()
slow codeblock - 1500ms - ConsoleEntry::eval()here's a more real-world example from a particularly slow call from some code,
with the threshhold set to 50ms. (this is a debug build, sort of artificially slow)
you can pretty immediately see that ClosetTabs::tabSelected() might be worth looking at:
==>setExecDurationWarnThreshhold(50); ==>toggleClosetGui(); slow codeblock - 63ms - Closet::skuListHasCategory() slow codeblock - 343ms - Closet::skuListHasCategory() slow codeblock - 672ms - ClosetItemPopup::update() slow codeblock - 937ms - ClosetThumbnails::setDrawers() slow codeblock - 937ms - ClosetItemsFrame::update() slow codeblock - 984ms - ClosetMyOutfitsFrame::hangerSelected() slow codeblock - 6656ms - ClosetTabs::tabSelected() slow codeblock - 6671ms - TabControl::selectTabAtIndex() slow codeblock - 6671ms - TabControl::selectTabWithName() slow codeblock - 7125ms - (no namespace)::toggleClosetGui()
and here's the modifications to a TGE 1.3.5 codebase.
all the modification are here, but familiarity with C++ and the Torque source code is assumed.
caveat: i'm seeing that my codebase is actually a bit different than a stock TGE 1.4 codebase,
so i've adapted to what i think should work, but have not actually tested this exact changeset.
consoleInternal.h
in the class ExprEvalState, after bool traceOn;, add:
U32 execDurationWarnThreshhold;
consoleInternal.cc
in the class ExprEvalState, after traceOn = false;, add:
execDurationWarnThreshhold = 0;
consoleFunctions.cc
after the console function "trace" ( search for ConsoleFunction(trace ), add this console function:
ConsoleFunction(setExecDurationWarnThreshhold, void, 2, 2, "setExecDurationWarnThreshhold(U32 ms)")
{
gEvalState.execDurationWarnThreshhold = dAtoi(argv[1]);
}
ConsoleFunction(getExecDurationWarnThreshhold, S32, 1, 1, "getExecDurationWarnThreshhold()")
{
return gEvalState.execDurationWarnThreshhold;
}compiledEval.cc, in the method CodeBlock::exec()
up near the top along with the declaration of curStringTable, add:
U32 timeStart = 0;
just before gEvalState.pushFrame(thisFunctionName, thisNamespace);, insert:
if (gEvalState.execDurationWarnThreshhold > 0)
{
timeStart = Platform::getRealMilliseconds();
}down just below execFinished:, add:
if (argv != NULL && timeStart != 0 && gEvalState.execDurationWarnThreshhold > 0)
{
U32 timeFinish = Platform::getRealMilliseconds();
U32 timeDelta = timeFinish - timeStart;
if (timeDelta >= gEvalState.execDurationWarnThreshhold)
{
const char* ns = (thisNamespace != NULL && thisNamespace->mName != NULL) ? thisNamespace->mName : "" ;
const char* sp = (thisNamespace != NULL && thisNamespace->mName != NULL) ? "::" : "" ;
const char* fn = (thisFunctionName != NULL ) ? thisFunctionName : "(no functionName)";
Con::warnf("slow codeblock - %5dms - %-*s%s%s%s()", timeDelta, gEvalState.stack.size() - 1, "", ns, sp, fn);
}
}.. and that should do it.
About the author
#2
04/17/2009 (3:38 pm)
Fantastic resource Orion, this will be something I'm hoping I can get working easily in TGEA to look at where our scripting performance hits are.
#3
i love these things that are so few lines of code but can really save you time tracking down bugs. since i think there's no overhead for this, i'm planning to turn it on for all our production servers at probably 200ms.
04/17/2009 (3:46 pm)
Awesome, i'd love to hear if it integrates moderately seamlessly into TGEA.i love these things that are so few lines of code but can really save you time tracking down bugs. since i think there's no overhead for this, i'm planning to turn it on for all our production servers at probably 200ms.
#4
But apart from that it works perfectly in TGEA 1.8.1 too, I've checked TGE 1.5.2 and there's no getName() function there so might be something you've added to your codebase.
Once again great resource :)
04/17/2009 (5:03 pm)
I had to change thisNamespace->getName() to thisNamespace->mNameBut apart from that it works perfectly in TGEA 1.8.1 too, I've checked TGE 1.5.2 and there's no getName() function there so might be something you've added to your codebase.
Once again great resource :)
#5
yes indeed, thanks for the catch.
updated the resource.
glad to know it works in codebases from teh future, too!
04/17/2009 (5:09 pm)
> might be something you've added to your codebaseyes indeed, thanks for the catch.
updated the resource.
glad to know it works in codebases from teh future, too!
#6
05/05/2009 (4:28 pm)
Very useful, thanks! 
Associate Orion Elenzil
Real Life Plus