June 14, 2006
Profiling Windows C++ Applications with Microsoft ExcelFinding out what your application is really up to Oguz Kupusoglu
Profiling an application is necessary when you want to learn more about how it runs and where its bottlenecks are.
Oguz Kupusoglu is a software engineer. He can be contacted at oguz.kupusoglu@gmail.com.
Profiling an application is necessary when you want to learn more about how it runs and where its bottlenecks are. A profiler is an analysis tool, which tracks the application while it is being executed. Although the capabilities of the profilers vary, graphically displaying the call cost and hit count--the average time elapsed in milliseconds for a function call, and the number of times a function is called, respectively-- are the most essential features profiling tools should have.
I use Microsoft Visual C++ 6.0 Professional Edition on Windows 2000 and Windows XP. Although this compiler has a profiler, it is a bit cumbersome. Moreover, analyzing the profiler data is not easy. Microsoft has provided the PROFILER.XLM macro to analyze the profiler data. However, I think it is also difficult to use. Consequently, I decided to develop my own simple profiler. The complete source code (and related files) for the profiler is available online.
My primary design goals are:
I decided to develop a class to collect the profiler data and a tool to analyze them graphically with Microsoft Excel (I tested the tool with Microsoft Excel 2000 and Microsoft Excel 2003.) Obviously, I am not after precise measurements; I simply want to compare some numeric data. The CProfiler class is aimed at function level profiling; it doesn't provide any data on line level.
The tool is tightly coupled to Microsoft Excel. However, I developed the CProfiler class with portably in mind; the SData struct is a wrapper for any specific implementation.
CProfiler Class
Listing One shows this class. Note the static functions and data members.
struct SData;
class CProfiler
{
public:
CProfiler(wchar_t* pId);
CProfiler(void* pAddress, wchar_t* pType, wchar_t* pOp, wchar_t* pId);
~CProfiler();
bool InitInstance();
void StopInstance();
static void InitClass(wchar_t* pDir, bool profiling);
static void StopClass();
static void DeleteTemps();
static void ProcessData();
private:
static bool IsDirOK(wchar_t* pDir);
SData* m_start;
FILE* m_file;
bool m_failed;
wchar_t* m_pId;
static SData* s_frequency;
static wchar_t s_dir[LEN_BUFFER];
static bool s_profiling;
static bool s_failed;
static bool s_stopped;
static std::map
Listing One: CProfiler Class
To simplify the usage, I developed the macros in Listing Two.
#define PROFILER_INITCLASS(dir) CProfiler::InitClass(L##dir, true) #define PROFILER_INITCLASS_CURRDIR CProfiler::InitClass(0, true) #define PROFILER_PROCESSDATA CProfiler::ProcessData() #define PROFILER_START(id) CProfiler profiler(L##id) #define PROFILER_STOP profiler.StopInstance()
Listing Two: Profiler Macros
|
|
||||||||||||||||||||||||||||||
|
|
|
|