Skip to content

Commit

Permalink
CallTrace: Added support for disabling function call trace for a lexi…
Browse files Browse the repository at this point in the history
…cal scope.
  • Loading branch information
levy committed Feb 26, 2024
1 parent d06f96e commit 45cc265
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 27 deletions.
30 changes: 12 additions & 18 deletions src/inet/common/CallTrace.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@ namespace inet {

CallTrace::State CallTrace::state;

CallTrace::CallTrace(const char *name, int maxLevel, const char *filter)
CallTrace::CallTrace(bool enabled, const char *name, int maxLevel, const char *filter)
{
state.enabled = true;
state.level = 1;
oldState = state;
state.enabled = enabled;
state.name = name;
state.maxLevel = maxLevel;
state.filter = std::regex(filter);
printf("TRACE -> %s\n", state.name);
printf("TRACE %s-> %s\n", std::string(state.level * 2, ' ').c_str(), state.name);
state.level++;
}

CallTrace::~CallTrace()
{
printf("TRACE <- %s\n", state.name);
state.enabled = false;
state.level = -1;
state.name = nullptr;
state.maxLevel = -1;
state.filter = std::regex();
state.level--;
printf("TRACE %s<- %s\n", std::string(state.level * 2, ' ').c_str(), state.name);
state = oldState;
}

std::string CallTrace::demangle(const char* mangledName) {
Expand All @@ -60,16 +58,14 @@ void __cyg_profile_func_enter(void* func, void* caller)
auto& state = inet::CallTrace::state;
if (state.enabled) {
state.enabled = false;
if (1 <= state.level && state.level <= state.maxLevel) {
if (state.level < state.maxLevel) {
Dl_info info;
if (dladdr(func, &info)) {
std::string functionName = inet::CallTrace::demangle(info.dli_sname);
if (functionName != "CallTrace::~CallTrace()" &&
std::regex_match(functionName, state.filter))
{
printf("TRACE %s-> %s\n",
std::string(state.level * 2, ' ').c_str(),
info.dli_sname ? functionName.c_str() : "?");
printf("TRACE %s-> %s\n", std::string(state.level * 2, ' ').c_str(), info.dli_sname ? functionName.c_str() : "?");
state.level++;
}
}
Expand All @@ -83,17 +79,15 @@ void __cyg_profile_func_exit(void* func, void* caller)
auto& state = inet::CallTrace::state;
if (state.enabled) {
state.enabled = false;
if (1 <= state.level && state.level <= state.maxLevel) {
if (state.level < state.maxLevel) {
Dl_info info;
if (dladdr(func, &info)) {
std::string functionName = inet::CallTrace::demangle(info.dli_sname);
if (functionName != "CallTrace::~CallTrace()" &&
std::regex_match(functionName, state.filter))
{
state.level--;
printf("TRACE %s<- %s\n",
std::string(state.level * 2, ' ').c_str(),
info.dli_sname ? functionName.c_str() : "?");
printf("TRACE %s<- %s\n", std::string(state.level * 2, ' ').c_str(), info.dli_sname ? functionName.c_str() : "?");
}
}
}
Expand Down
27 changes: 18 additions & 9 deletions src/inet/common/CallTrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@
namespace inet {

/**
* This class supports generating function call traces on the standard output.
* For example, CALL_TRACE(10, "inet::.*") will produce a function call trace
* for a maximum depth limit of 10 levels including only INET functions.
* Here is another example focusing on certain classes and ignoring some functions:
* CALL_TRACE(20, "^inet::(ScenarioManager|LifecycleController|NodeStatus|NetworkInterface|InterfaceTable|Ipv4RoutingTable|Ipv4NetworkConfigurator|Ipv4NodeConfigurator|EthernetMac|EthernetMacBase)::(?!(get|is|has|compute)).*");
* This class is capable of generating a function call traces on the standard output.
* The output contains one line for entering and one line for leaving a function.
*
* Important: compile INET using GCC with '-finstrument-functions' into an executable.
*
* For example, the following produces a function call trace for a maximum depth
* limit of 10 levels including only INET functions:
* CALL_TRACE(true, 10, "inet::.*");
*
* Here is another example focusing on certain classes and ignoring some functions:
* CALL_TRACE(true, 20, "^inet::(ScenarioManager|LifecycleController|NodeStatus|NetworkInterface|InterfaceTable|Ipv4RoutingTable|Ipv4NetworkConfigurator|Ipv4NodeConfigurator|EthernetMac|EthernetMacBase)::(?!(get|is|has|compute)).*");
*
* It's also possible to disable call tracing for the lexical scope:
* CALL_TRACE(false, 0, "");
*/
class INET_API CallTrace
{
Expand All @@ -33,7 +39,7 @@ class INET_API CallTrace
{
public:
bool enabled = false;
int level = -1;
int level = 0;

const char *name = nullptr;
int maxLevel = -1;
Expand All @@ -43,20 +49,23 @@ class INET_API CallTrace
public:
static State state;

private:
State oldState;

public:
CallTrace(const char *name, int maxLevel, const char *filter);
CallTrace(bool enabled, const char *name, int maxLevel, const char *filter);
~CallTrace();

static std::string demangle(const char* mangledName);
};

#define CALL_TRACE(maxLevel, filter) std::string name = CallTrace::demangle(typeid(*this).name()) + "::" + __func__ + "()"; CallTrace callTrace(name.c_str(), maxLevel, filter)
#define CALL_TRACE(enabled, maxLevel, filter) std::string name = CallTrace::demangle(typeid(*this).name()) + "::" + __func__ + "()"; CallTrace callTrace(enabled, name.c_str(), maxLevel, filter)

} // namespace inet

#else

#define CALL_TRACE(maxLevel, filter)
#define CALL_TRACE(enabled, maxLevel, filter)

#endif

Expand Down

0 comments on commit 45cc265

Please sign in to comment.