Contents
Monitoring Your PC's Memory Usage For Game Development
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest News
spacer View All spacer
 
November 22, 2009
 
Video Game Watchdog National Institute On Media And The Family Shutting Down [11]
 
Modern Warfare 2 Infinity Ward's 'Most Successful PC Version' Yet [12]
 
New Tech, Design Details Of Project Natal To Emerge At Gamefest In February
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 22, 2009
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Network Programmer
 
Sucker Punch Productions
Texture Artist
 
Sony Online Entertainment
Brand Manager
 
Monolith Productions
Sr. Software Engineer, Engine - Monolith Productions - #113767
 
Crystal Dynamics
Sr. Level Designer
 
Gargantuan Studios
Lead World Designer
spacer
Latest Features
spacer View All spacer
 
November 22, 2009
 
arrow Upping The Craft: Susan O'Connor On Games Writing [6]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part II [6]
 
arrow iPhone Piracy: The Inside Story [48]
 
arrow And Yet It Grows: Analyzing the Size and Growth of the European Game Market [5]
 
arrow NPD: Behind the Numbers, October 2009 [13]
 
arrow Reflecting On Uncharted 2: How They Did It [5]
 
arrow Sponsored Feature: Rasterization on Larrabee -- Adaptive Rasterization Helps Boost Efficiency
 
arrow Postmortem: Wadjet Eye's The Blackwell Convergence [2]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 22, 2009
 
Accepting the Inherent Value of Games
 
Planckogenesis, Part II: Song Structure & Gravy Train [1]
 
Designing Games Is About Matching Personalities [1]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  Monitoring Your PC's Memory Usage For Game Development
by Jelle van der Beek
0 comments
Share RSS
 
 
May 31, 2007 Article Start Previous Page 6 of 10 Next
 

Solution 1: Loading symbol information through SymInitialize.

On PC we load symbol information using the DbgHelp library. In our first solution we use the SymInitialize function from the DbgHelp library:

BOOL SymInitialize(

Advertisement

HANDLE hProcess,

PCTSTR UserSearchPath,

BOOL fInvadeProcess

);

The first parameter is a handle to a process. If you pass a valid handle to a process, SymInitialize will enumerate all of the loaded modules for that process and search for the symbol files. It will search for the symbol files in their default locations. Additional searching can be being performed using UserSearchPath, the second parameter.

There are some pros and cons to this approach:

Pros:

  • It is very convenient and powerful: it finds the symbol information itself for all loaded modules.

  • It knows what image base addresses to load the symbol information at.

Cons:

  • The tool can only use this if the game is running locally – i.e. not over the network.

  • The tool can only use this as long as the game is running. If we decide to save our ‘project’ for offline analysis, the process is no longer alive.

If the drawbacks prove not be a problem for you, possibly when your tool serves as a debugger for a running process, I would suggest using this method to load symbol information. Listing 2 displays a sample program that demonstrates how this works.

 

#include "stdafx.h"
#include
#include

_declspec(noinline) unsigned int GetProgramCounter()
{
unsigned int result;
_asm mov eax, dword ptr[ebp + 4]
_asm mov [result], eax
return result;
}

_declspec(noinline) void Foo()
{
unsigned int programCounter = GetProgramCounter();
std::cout << "Function address: 0x" <<
std::hex << programCounter << std::endl;
}

int main(int argc, char* argv[])
{
int processID = GetCurrentProcessId();
std::cout << "process id: 0x" <<
std::hex << processID << std::endl;

Foo();

Sleep(INFINITE);

return 0;
}

Listing 2: The SomeDummyProcess program.

Let’s go over this code. Our application is a very simple win32 console application that outputs the current running process Id and it outputs an address in the range of the function Foo. Because you cannot read the instruction pointer (EIP) directly, I used a trick from Dan Moulding to obtain the instruction pointer by using the return address. You can read his article at 6. Another way to do this is to use the ReturnAddress intrinsic, which is Microsoft specific, but will also work at architectures other than x86.

After printing, the program goes into sleep state to avoid the process from exiting.

The program output shows the current process Id and the function address of Foo:

process id: 0xe9c

Function address: 0x411553

Listing 3 shows the program that is going to use the process Id and the function address.

 

#include "stdafx.h"
#include
#include
#include
#include
#include
#include

using namespace std;

string FindFunction(DWORD64 address, HANDLE process)
{
string result = "Unknown";

ULONG64 buffer[
(sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(char) +
sizeof(ULONG64) - 1) /
sizeof(ULONG64)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
DWORD64 displ = 0;

pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;

if(::SymFromAddr(process, address, &displ, pSymbol))
{
result = pSymbol->Name;
}
else
{
DWORD error = ::GetLastError();
ostringstream str;
str << "SymFromAddr returned error " << error;
throw exception(str.str().c_str());
}

return result;
}

void Init(HANDLE process)
{
::SymSetOptions(
SYMOPT_UNDNAME |
SYMOPT_DEFERRED_LOADS |
SYMOPT_LOAD_LINES);

if(!::SymInitialize(process, NULL, TRUE))
{
throw exception(
"Could not initialize symbol loader!");
}
}

void Exit(HANDLE process)
{
::SymCleanup(process);
}

int main(int argc, char* argv[])
{
HANDLE processHandle = NULL;

try
{
if (argc != 3)
{
throw invalid_argument(
"Usage: FileLineInfo ");
}

DWORD processId;
istringstream iss1(argv[1], ios_base::in);
iss1 >> hex >> processId;

processHandle = ::OpenProcess(
PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
FALSE, processId);
if(processHandle == NULL)
{
throw invalid_argument(
"Process ID does not refer to a running process!");
}
char fileName[MAX_PATH];
::GetModuleFileNameExA(
processHandle,
NULL,
fileName,
sizeof(fileName));
cout << "Process refers to: " << fileName << endl;

Init(processHandle);

DWORD64 address;
istringstream iss2(argv[2], ios_base::in);
iss2 >> hex >> address;

string name = FindFunction(address, processHandle);
cout << "Function name: " << name << endl;
}
catch(exception& ex)
{
cerr << "Error: " << ex.what( ) << endl;
}

if(processHandle != NULL)
{
Exit(processHandle);
::CloseHandle(processHandle);
}

return 0;
}

Listing 3: The FindFunctionInProcess program.

 
Article Start Previous Page 6 of 10 Next
 
Comments

none
 
Comment:
 


Submit Comment