Click here to Skip to main content
15,886,873 members
Articles / General Programming / Debugging
Tip/Trick

A C++ Code Function Tracing Class

Rate me:
Please Sign up or sign in to vote.
5.00/5 (20 votes)
9 Apr 2024CPOL3 min read 18.7K   667   28   26
Trace your function calls to the Output window.
A simple plug in class that can be used to trace the function calls as your code is run.

Introduction

The code presented in this tip is several years old. I first came up with it when I was developing my TileGrid Control. As part of the debugging and streamlining process, I would try to figure out which functions were getting called, in what order, and how often. The built in debugger call stack is way too limited as it only shows the current call stack, it does not show all the functions that were called in between.

At first, I would do it by constantly stepping through the code using the F10 (step over), F11 (step into) and <shift>F11 (step out) buttons on the keyboard. That got very tedious really fast.

My next idea to make it easier was to put TRACE statements at the start of every function. Well, that kind of worked, I did get the function calls listed in the debug output window. But there was no easy way to tell which function was calling which function. There was no call hierarchy visible.

It was then that I came up with the FunctionTraceClass. It does exactly what I needed it to do.

Here are the outputs from the call stack and from the function trace class when I click on the add tile button in the demo app for the above mentioned TileGrid control with a breakpoint set in the CTileGrid::SelectTile() function.

First, the call stack:

TileGridDialog.exe!CTileGrid::SelectTile(CTileBase * pTile, bool bSelect) Line 1185    C++
TileGridDialog.exe!CTileGrid::SetFocusedTile(CTileBase * pTile) Line 1268    C++
TileGridDialog.exe!CTileGridDialogDlg::OnBnClickedButtonaddtile() Line 445    C++
[External Code]
TileGridDialog.exe!CAutoRepeatButton::OnLButtonUp
               (unsigned int nFlags, CPoint point) Line 105    C++
[External Code]
TileGridDialog.exe!CTileGridDialogApp::InitInstance() Line 75    C++
[External Code]
TileGridDialog.exe!wWinMain(HINSTANCE__ * hInstance,
  HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 26    C++
[External Code]

As you can see, it is not very useful as it does not show the complete picture. Now, here is the output from the function trace class. It is long, but very informative.

CTileGrid::AddTile(struct CRuntimeClass *,bool)
+--CTileGrid::AddTile(class CTileBase *,bool,bool)
|  +--CTileGrid::SCN::SCN(class CTileGrid *,bool)
|  +--CTileGrid::GetTileAtIndex(int)
|  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::ClearSelections(class CTileBase *,class CTileBase *)
|  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::CTileGrid_NotifyParent(unsigned int,class CTileBase *,struct tagNMHDR *)
|  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::GetTileAtIndex(int)
|  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::GetTileAtIndex(int)
|  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::CTileGrid_NotifyParent(unsigned int,class CTileBase *,struct tagNMHDR *)
|  |  +--CTileGrid::GetTileCount(void)
|  |  +--CTileGrid::GetSelectionCount(void)
|  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::IsTileFullyVisible(class CTileBase *)
|  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  +--CTileGrid::GetTileCount(void)
|  |  +--CTileGrid::GetTileRect(class CTileBase *)
|  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::IsTileVisible(class CTileBase *)
|  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  +--CTileGrid::GetTileCount(void)
|  |  +--CTileGrid::GetTileRect(class CTileBase *)
|  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::RedrawTile(class CTileBase *)
|  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  +--CTileGrid::GetTileCount(void)
|  |  +--CTileGrid::IsTileVisible(class CTileBase *)
|  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  +--CTileGrid::GetTileCount(void)
|  |  |  +--CTileGrid::GetTileRect(class CTileBase *)
|  |  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  |  +--CTileGrid::GetTileCount(void)
|  |  +--CTileGrid::GetTileRect(class CTileBase *)
|  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  +--CTileGrid::GetTileCount(void)
|  +--CTileGrid::SCN::~SCN(void)
|  |  +--CTileGrid::CTileGrid_NotifyParent(unsigned int,class CTileBase *,struct tagNMHDR *)
|  |  |  +--CTileGrid::GetSelectionCount(void)
|  |  |  |  +--CTileGrid::GetTileAtIndex(int)
|  |  |  |  |  +--CTileGrid::GetTileCount(void)

CTileGrid::SetFocusedTile(class CTileBase *)
+--CTileGrid::GetTileAtIndex(int)
|  +--CTileGrid::GetTileCount(void)
+--CTileGrid::GetTileAtIndex(int)
|  +--CTileGrid::GetTileCount(void)
+--CTileGrid::SCN::SCN(class CTileGrid *,bool)
+--CTileGrid::SelectTile(class CTileBase *,bool)
|  +--CTileGrid::GetTileAtIndex(int)
|  |  +--CTileGrid::GetTileCount(void)

Using the Code

The code is very easy to use. Add the files, FunctionTrace.h and FunctionTrace.cpp to your project. These files are in available via the download link at the top of this tip.

In the first line of any function you want to trace, you place the FUNC_TRACE macro.

If there are any functions you do not want to trace, you would place the NO_FUNC_TRACE macro. The NO_FUNC_TRACE macro disables all FUNC_TRACE macros that are under it in the call hierarchy.

To toggle function tracing on or off for your entire project, you have to go into the FunctionTrace.h file and uncomment or comment out line 5 to determine if the ENABLEFUNCTIONTRACE macro is defined or not defined.

//#define  ENABLEFUNCTIONTRACE  // uncomment this line to enable debug function tracing

Or, if you want to use this in a single source code file you need to simply #define ENABLEFUNCTIONTRACE before you #include "FunctionTrace.h"".

#define ENABLEFUNCTIONTRACE
#include "FunctionTrace.h"

Update

There was a comment made in the discussion board below this article that I initially dismissed, but the more I thought about the more sense it made. As a result I have updated the code so that the tracing output can be sent either to the console or to a text file. The alternate output methods should solve the problem of having other debugging messages interspersed between the function tracing output.

The update is an addition of two new function macros. They are FUNC_TRACE_TO_CONSOLE and FUNC_TRACE_TO_FILE(filename). Just place one of these macros just after your #include "FunctionTrace.h" line.

#define ENABLEFUNCTIONTRACE
#include "FunctionTrace.h"
FUNC_TRACE_TO_CONSOLE;    // Send the output to the console
// FUNC_TRACE_TO_FILE ("MyTestFile.txt");  // Send the output to the file "MyTestFile.txt"

The default output method, which is used if neither of these two macros are used, is still the debugger output window.

You only need to call one of these macros in a single source file in your project, it makes no difference where you call it. If you call these macros multiple times in your code, only the very first one that is executed will have any effect on the output.

The download also includes a demonstration console application file:

#include "FunctionTrace.h"

#define ENABLEFUNCTIONTRACE
#include "FunctionTrace.h"
FUNC_TRACE_TO_CONSOLE
//FUNC_TRACE_TO_FILE ("MyTestFile.txt")

class Test
{
public:
    void FuncA()
    {
        FUNC_TRACE;
        FuncB();
        FuncC();
    }

    void FuncB()
    {
        NO_FUNC_TRACE;
        FuncC();
    }

    void FuncC()
    {
        FUNC_TRACE;
    }

    Test()
    {
        FUNC_TRACE;
    }
};

int main()
{
    FUNC_TRACE;
    Test t;
    t.FuncA();
    t.FuncB();
    t.FuncC();
  }

The output of the demo file is:

main(void)
+--Test::Test(void)
+--Test::FuncA(void)
|  +--Test::FuncC(void)
+--Test::FuncC(void)

History

  • 5th March, 2024 - Posted to CodeProject hoping that maybe someone may find this interesting and/or useful
  • 8th March, 2024 - Updated the file so it can be used in a single source file. Was previously used project wide.
  • 9th April, 2024 - Added the FUNC_TRACE_TO_CONSOLE and FUNC_TRACE_TO_FILE(filename) macros.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President
Canada Canada
Father of two, brother of two, child of two.
Spouse to one, uncle to many, friend to lots.
Farmer, carpenter, mechanic, electrician, but definitely not a plumber.
Likes walks with the wife, board games, card games, travel, and camping in the summer.
High school graduate, college drop-out.
Hobby programmer who knows C++ with MFC and the STL.
Has dabbled with BASIC, Pascal, Fortran, COBOL, C#, SQL, ASM, and HTML.
Realized long ago that programming is fun when there is nobody pressuring you with schedules and timelines.

Comments and Discussions

 
QuestionOutput to debug API ? Pin
ObiWan_MCC10-Apr-24 23:27
ObiWan_MCC10-Apr-24 23:27 
AnswerRe: Output to debug API ? Pin
PJ Arends11-Apr-24 13:31
professionalPJ Arends11-Apr-24 13:31 
AnswerRe: Output to debug API ? Pin
PJ Arends11-Apr-24 15:32
professionalPJ Arends11-Apr-24 15:32 
GeneralRe: Output to debug API ? Pin
ObiWan_MCC11-Apr-24 20:53
ObiWan_MCC11-Apr-24 20:53 
Questiona simple g++ macro to get file, function, and line number. Pin
mike rumore21-Mar-24 7:03
mike rumore21-Mar-24 7:03 
QuestionOverhead in using the Tracing Class Pin
Henrik Vestermark12-Mar-24 21:57
Henrik Vestermark12-Mar-24 21:57 
AnswerRe: Overhead in using the Tracing Class Pin
PJ Arends13-Mar-24 10:00
professionalPJ Arends13-Mar-24 10:00 
GeneralMy vote of 5 Pin
gugy112-Mar-24 0:13
gugy112-Mar-24 0:13 
Question_debug Pin
feanorgem11-Mar-24 5:43
feanorgem11-Mar-24 5:43 
AnswerRe: _debug Pin
PJ Arends11-Mar-24 5:55
professionalPJ Arends11-Mar-24 5:55 
GeneralRe: _debug Pin
feanorgem11-Mar-24 6:27
feanorgem11-Mar-24 6:27 
GeneralMy vote of 2 Pin
schlebe11-Mar-24 2:42
schlebe11-Mar-24 2:42 
GeneralRe: My vote of 2 Pin
PJ Arends11-Mar-24 5:57
professionalPJ Arends11-Mar-24 5:57 
QuestionOutput mixed Pin
Member 39995439-Mar-24 18:56
Member 39995439-Mar-24 18:56 
AnswerRe: Output mixed Pin
PJ Arends10-Mar-24 20:48
professionalPJ Arends10-Mar-24 20:48 
GeneralRe: Output mixed Pin
Member 399954310-Mar-24 21:54
Member 399954310-Mar-24 21:54 
AnswerRe: Output mixed Pin
PJ Arends4-Apr-24 22:41
professionalPJ Arends4-Apr-24 22:41 
QuestionMy vote of 5 Pin
colins27-Mar-24 20:25
colins27-Mar-24 20:25 
GeneralMy vote of 5 Pin
BitRift26-Mar-24 23:11
BitRift26-Mar-24 23:11 
GeneralRe: My vote of 5 Pin
PJ Arends7-Mar-24 6:33
professionalPJ Arends7-Mar-24 6:33 
GeneralRe: My vote of 5 Pin
BitRift27-Mar-24 7:23
BitRift27-Mar-24 7:23 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA6-Mar-24 14:57
professionalȘtefan-Mihai MOGA6-Mar-24 14:57 
GeneralMy vote of 5 Pin
Joxemi6-Mar-24 2:06
Joxemi6-Mar-24 2:06 
PraiseGot my 5 Pin
_Flaviu5-Mar-24 20:12
_Flaviu5-Mar-24 20:12 
GeneralMy vote of 5 Pin
Shao Voon Wong5-Mar-24 15:21
mvaShao Voon Wong5-Mar-24 15:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.