Instrumenting BitStream
by Orion Elenzil · 04/18/2007 (1:55 pm) · 5 comments
This resource provides a framework around instrumenting BitStream.
It can help you answer questions like
"How many bits are going out to each client ?"
"How many of those bits are in Player ?"
"How many are due to the MoveMask ?"
"How many are due to MyCrazyJankyCustomNetmask ?"
etc
all the source code changes are provided below,
but the commentary assumes familiarity with C++ and TGE.
NOTE - this uses a non-stock method, ScriptObject::getDebugString(),
which i now realize i haven't provided as a resource.
Apologies for that. i'll try to resourcify it soon.
In the meantime, i'll provide alternative code which doesn't use it.
bitStream.h
at the top, add this:
inside the class BitStream, add this:
(i added it at the top)
bitStream.cc
at the bottom of BitStream::writeBits(), add this:
at the bottom of BitStream::writeFlag(), add this:
at the bottom of the file, add this:
game.cc
at the bottom of GameInit(), add:
define DEBUG_BITSTREAMCOUNT.
In VisualStudio, do this in Project Settings | C++ | Preprocessor
by just tacking on ";DEBUG_BITSTREAMCOUNT" to "Preprocessor definitions".
For other build environments i'm sure it's similarly straight-forward.
.. that's it for the framework.
here's a couple usage examples.
netConnection.cc
at the top of NetConnection::WritePacket(), add:
player.cc
at the top of Player::packUpdate(), add:
in Player::packUpdate(), find the MoveMask code block and make it look like this:
to activate the instrumentation,
enter the console command "$BitStreamCount = true;".
obviously this is server-side.
It can help you answer questions like
"How many bits are going out to each client ?"
"How many of those bits are in Player ?"
"How many are due to the MoveMask ?"
"How many are due to MyCrazyJankyCustomNetmask ?"
etc
all the source code changes are provided below,
but the commentary assumes familiarity with C++ and TGE.
NOTE - this uses a non-stock method, ScriptObject::getDebugString(),
which i now realize i haven't provided as a resource.
Apologies for that. i'll try to resourcify it soon.
In the meantime, i'll provide alternative code which doesn't use it.
bitStream.h
at the top, add this:
#ifndef _TVECTOR_H_ #include "core/tVector.h" #endif #ifdef DEBUG_BITSTREAMCOUNT // with ScriptObject::GetDebugString(): //#define BITSTREAMCOUNTER( objName, stream, counterName, pNetCon, pSimObject) char s[256]; dSprintf(s, sizeof(s), "%-60s %-60s", pNetCon->getDebugString(), pSimObject->getDebugString()); BitStream::Counter objName(stream, counterName, s); //#define BITSTREAMCOUNTER_NOOBJ(objName, stream, counterName, pNetCon ) char s[256]; dSprintf(s, sizeof(s), "%-60s" , pNetCon->getDebugString() ); BitStream::Counter objName(stream, counterName, s); // without ScriptObject::GetDebugString(): #define BITSTREAMCOUNTER( objName, stream, counterName, pNetCon, pSimObject) char s[256]; dSprintf(s, sizeof(s), "0x%-0.8X %-0.8X", pNetCon, pSimObject); BitStream::Counter objName(stream, counterName, s); #define BITSTREAMCOUNTER_NOOBJ(objName, stream, counterName, pNetCon ) char s[256]; dSprintf(s, sizeof(s), "0x%-0.8X" , pNetCon ); BitStream::Counter objName(stream, counterName, s); #else #define BITSTREAMCOUNTER( objName, stream, counterName, pSimObject, pNetCon) #define BITSTREAMCOUNTER_NOOBJ(objName, stream, counterName, pNetCon) #endif
inside the class BitStream, add this:
(i added it at the top)
//-------------------------------------- Bitstream Counter Stuff Begin
public:
class Counter
{
public:
Counter(BitStream* bs, const char* name, const char* desc);
~Counter();
public:
BitStream* mBitStream;
char mName[64 ];
char mDesc[256];
S32 mBitCount;
S32 mBitCountChildren;
static bool smActive;
};
protected:
Vector<Counter *> mCounterStack;
void counterPush(Counter& counter);
void counterPop (Counter& counter);
//-------------------------------------- Bitstream Counter Stuff DonebitStream.cc
at the bottom of BitStream::writeBits(), add this:
#ifdef DEBUG_BITSTREAMCOUNT
if (mCounterStack.size() > 0)
mCounterStack[0]->mBitCount += bitCount;
#endifat the bottom of BitStream::writeFlag(), add this:
#ifdef DEBUG_BITSTREAMCOUNT
if (mCounterStack.size() > 0)
mCounterStack[0]->mBitCount += 1;
#endifat the bottom of the file, add this:
//-------------------------------------- Bitstream Counter Stuff Begin
// USAGE
// To use the bitstream instrumentation,
// you first gotta compile the application with DEBUG_BITSTREAMCOUNT defined.
// Then, you instrument code at the scope level via either
// BITSTREAMCOUNTER(Literal <Counter Object Name>, BitStream* bitstream, const char* CounterName, NetConnection* netConnection, SimObject* simObject)
// or
// BITSTREAMCOUNTER(Literal <Counter Object Name>, BitStream* bitstream, const char* CounterName, NetConnection* netConnection)
// where:
// * Counter Object Name is the name of the actual instance of the counter object which will be created.
// since it's assumed that the macro is called only once per scope, it's okay to always use the same thing. i recommend "BSCounter".
// * bitStream is a pointer to the bitstream in question.
// * counterName will be printed to the log. Something short like "SkinMask".
// * netConnection is a pointer to the netConnection this bitstream is going out over. used in the debug print.
// todo - probably don't need both bitStream AND netConnection, huh.
// * simObject is a pointer to an object [being ghosted]. used in the debug print.
//
// By "scope" is meant that an object will be created in the given scope,
// and thus automatically destroyed when it leaves scope, which will yield a debug print.
//
// Once all this is compiled,
// active the logging in script by issuing "$bitStreamCount = true;".
//
// the resulting debug prints will look something like this:
//
// bitCount 119/119 | Player::packUpdate 4680-AIPlayer-annie-s-annie 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 119/119 | Player::packUpdate 4676-AIPlayer-alberta-s-alberta 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 198/198 | Player::packUpdate 4690-AIPlayer-Bixxy-s-Bixxy 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 119/119 | Player::packUpdate 4682-AIPlayer-frank-s-frank 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 119/119 | Player::packUpdate 4668-AIPlayer-bob-s-bob 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 111/111 | Player::packUpdate 4678-AIPlayer-djLarsBerg-s-djLarsBerg 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 111/111 | Player::packUpdate 4686-AIPlayer-menace-s-menace 4757-GameConnection-LocalClientConnection-doris lessing
// bitCount 39/935 |netconnection::writePacket 4757-GameConnection-LocalClientConnection-doris lessing
//
// what to look for:
// first, note that lines are printed in sort of reverse order. earlier lines are actually deeper scopes.
// so in the above, all the playe::packUpdates() are subsets of netConnnection::writePacket.
// next, the indenting. see how Player.. is indented compared to netConnection.. ?
// that reflects the scope depth.
// next, the bitcounts are: <Bits contributed by this scope>/<Bits from child scopes>.
// so in the above, netconnection::writePacket itself contributes 39 bits to a total size of 935 bits.
// the fact that everything above adds up to the final 935 value is just lucky.
// - had say some non-player object been ghosted out, things wouldn't have added up. that's okay.
// if the bitcount contributed by a scope is zero, it doesn't print a line.
//
bool BitStream::Counter::smActive = false;
BitStream::Counter::Counter(BitStream* bs, const char* name, const char* desc)
{
#ifndef DEBUG_BITSTREAMCOUNT
AssertFatal(false, "BitStream::Counter::Counter() - shouldn't be in here.");
#endif
AssertFatal(bs != NULL, "null bitstream in counter creation");
dStrncpy(mName, name, sizeof(mName));
dStrncpy(mDesc, desc, sizeof(mDesc));
mBitCount = 0;
mBitCountChildren = 0;
mBitStream = bs;
mBitStream->counterPush(*this);
}
BitStream::Counter::~Counter()
{
mBitStream->counterPop(*this);
}
void BitStream::counterPush(Counter& counter)
{
#ifndef DEBUG_BITSTREAMCOUNT
AssertFatal(false, "BitStream::counterPush() - shouldn't be in here.");
#endif
mCounterStack.push_front(&counter);
}
void BitStream::counterPop (Counter& counter)
{
#ifndef DEBUG_BITSTREAMCOUNT
AssertFatal(false, "BitStream::counterPop() - shouldn't be in here.");
#endif
if (&counter != mCounterStack[0])
{
Con::errorf(ConsoleLogEntry::Communication, "BitStream::counterPop() - wrong counter! %s", counter.mName);
return;
}
S32 bitCountTotal = counter.mBitCount + counter.mBitCountChildren;
if (Counter::smActive && counter.mBitCount > 0)
{
// must.. line.. stuff.. up..
char s[512];
dSprintf(s, sizeof(s), "%-*s%s", mCounterStack.size() - 1, "", counter.mName);
Con::debugf(ConsoleLogEntry::Communication, "bitCount %4d/%-4d |%-35s %s", counter.mBitCount, bitCountTotal, s, counter.mDesc);
}
mCounterStack.pop_front();
if (mCounterStack.size() > 0)
mCounterStack[0]->mBitCountChildren += bitCountTotal;
}
//-------------------------------------- Bitstream Counter Stuff Donegame.cc
at the bottom of GameInit(), add:
Con::addVariable("bitStreamCount" , TypeBool, &BitStream::Counter::smActive);define DEBUG_BITSTREAMCOUNT.
In VisualStudio, do this in Project Settings | C++ | Preprocessor
by just tacking on ";DEBUG_BITSTREAMCOUNT" to "Preprocessor definitions".
For other build environments i'm sure it's similarly straight-forward.
.. that's it for the framework.
here's a couple usage examples.
netConnection.cc
at the top of NetConnection::WritePacket(), add:
BITSTREAMCOUNTER_NOOBJ(BSCounter, bstream, "netconnection::writePacket", this)
player.cc
at the top of Player::packUpdate(), add:
BITSTREAMCOUNTER(BSCounter, stream, "Player::packUpdate", con, this)
in Player::packUpdate(), find the MoveMask code block and make it look like this:
if (stream->writeFlag(mask & MoveMask))
{
[b]BITSTREAMCOUNTER(BSCounter, stream, "MoveMask", con, this)[/b]to activate the instrumentation,
enter the console command "$BitStreamCount = true;".
obviously this is server-side.
About the author

Torque Owner Stefan Lundmark