50

I want to implement a function tracer, which would trace how much time a function is taking to execute. I have following class for the same:-

class FuncTracer
{
    public:
        FuncTracer(LPCTSTR strFuncName_in)
        {
            m_strFuncName[0] = _T('\0');
            if( strFuncName_in ||
                _T('\0') != strFuncName_in[0])
            {   
                _tcscpy(m_strFuncName,strFuncName_in);

                TCHAR strLog[MAX_PATH];
                _stprintf(strLog,_T("Entering Func:- <%s>"),m_strFuncName);
                LOG(strLog)

                m_dwEnterTime = GetTickCount();
            }
        }

        ~FuncTracer()
        {
            TCHAR strLog[MAX_PATH];
            _stprintf(strLog,_T("Leaving Func:- <%s>, Time inside the func <%d> ms"),m_strFuncName, GetTickCount()-m_dwEnterTime);
            LOG(strLog)
        }

    private:
        TCHAR m_strFuncName[MAX_PATH];
        DWORD m_dwEnterTime;
};

void TestClass::TestFunction()
{
    // I want to avoid writing the function name maually..
    // Is there any macro (__LINE__)or some other way to 
    // get the function name inside a function ??

    FuncTracer(_T("TestClass::TestFunction"));
    /*
     * Rest of the function code.
     */
}

I want to know if there is any way to get the name of the function from inside of a function? Basically I want the users of my class to simply create an object the same. They may not pass the function name.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
Canopus
  • 7,351
  • 11
  • 46
  • 57

4 Answers4

78

C99 has __func__, but for C++ this will be compiler specific. On the plus side, some of the compiler-specific versions provide additional type information, which is particularly nice when you're tracing inside a templatized function/class.

  • MSVC: __FUNCTION__, __FUNCDNAME__, __FUNCSIG__
  • GCC: __func__, __FUNCTION__, __PRETTY_FUNCTION__

Boost library has defined macro BOOST_CURRENT_FUNCTION for most C++ compilers in header boost/current_function.hpp. If the compiler is too old to support this, the result will be "(unknown)".

Community
  • 1
  • 1
bk1e
  • 23,871
  • 6
  • 54
  • 65
32

VC++ has

__FUNCTION__ for undecorated names

and

__FUNCDNAME__ for decorated names

And you can write a macro that will itself allocate an object and pass the name-yelding macro inside the constructor. Smth like

#define ALLOC_LOGGER FuncTracer ____tracer( __FUNCTION__ );
sharptooth
  • 167,383
  • 100
  • 513
  • 979
29

C++20 std::source_location::function_name

main.cpp

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location = std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int f(int i) {
    log("Hello world!"); // Line 16
    return i + 1;
}

int f(double i) {
    log("Hello world!"); // Line 21
    return i + 1.0;
}

int main() {
    f(1);
    f(1.0);
}

Compile and run:

g++ -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o source_location.out source_location.cpp
./source_location.out

Output:

info:source_location.cpp:16:int f(int) Hello world!
info:source_location.cpp:21:int f(double) Hello world!

so note how the call preserves caller information, so we see the desired main call location instead of log.

I have covered the relevant standards in a bit more detail at: What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Tested on Ubuntu 22.04, GCC 11.3.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 1
    Although if you follow your link to the reference it shows that there is a `function_name` field, I don't think the copy of the code and possible output provides much value given it doesn't make mention of it. It's just a copy of what's at the reference and you'll have to click on the reference anyway to get the information relevant to this question. The link to your other SO answer is more helpful since that answer at least makes mention of the `function_name` field. – tdashroy Apr 01 '20 at 06:24
4

I was going to say I didn't know of any such thing but then I saw the other answers...

It might interest you to know that an execution profiler (like gprof) does exactly what you're asking about - it tracks the amount of time spent executing each function. A profiler basically works by recording the instruction pointer (IP), the address of the currently executing instruction, every 10ms or so. After the program is done running, you invoke a postprocessor that examines the list of IPs and the program, and converts those addresses into function names. So I'd suggest just using the instruction pointer, rather than the function name, both because it's easier to code and because it's more efficient to work with a single number than with a string.

David Z
  • 128,184
  • 27
  • 255
  • 279
  • 1
    Note that to do this, you also have to save the image load addresses of the executable/libraries, or else you may not be able to interpret the recorded addresses meaningfully. Also, compiler support for custom profilers (e.g. _penter/_pexit in MSVC) can be an alternative to periodic sampling. – bk1e Apr 09 '09 at 20:50