8 ms·
do you have a write-up how you did it? I'm interested, thanks.
by synergy20 2y ago
do you have a write-up how you did it? I'm interested, thanks.
- naruhodo 2y agoI did a similar thing, in C++, 3 decades ago. I used a macro, FUNC(), that I would put at the start of functions. It took no arguments and declared a local instance, using the __FUNC__ preprocessor builtin to pass the function name to the Trace constructor: Trace trace##__LINE__(__FUNC__); The Trace instance would generate one log on construction and another on destruction. It also kept track of function call nesting (a counter) in a static member that would increment in the constructor and decrement in the destructor. It was inherently single-threaded, because I used a static member, but it could be adapted to multiple threads using thread local storage. I paired it with a LINE("Var x is " << x); macro for arbitrary ostreams-style logging. And building on that, EXPR(x) would do LINE(#x " = " << (x)). The output was along the lines of: ,- A::f() | ,- A::g() | | ,- B::B() | | `- B::~B() | | x = 12 | | About to do a thing... | | ,- A::doAThing() | | `- A::doAThing() | `- A::g() `- A::f() The macros could be disabled (defined to do nothing) by a preprocessor symbol.
- synergy20 2y agogcc's -finstrument-functions can also add the function call traces without changing the code I think