调用追踪上下文指针

调用追踪上下文指针

当我们想知道在程序执行过程中,函数调用链路的机制,或者想分析程序代码的性能瓶颈,我们往往会通过在程序入口处记录一下,比如 “开始调用了,当前时间戳是 xxx”、 “结束调用了,当前时间戳是 xxx” 来看看程序执行的步骤和当前函数执行的时间。

为了更优雅的实现这个机制,我们可以在每次函数调用时,将当前上下文信息(如函数名、调用时间、调用者等)记录下来,并在函数退出时清除或更新该信息。作用就是一个主要用于调试的手段吧。

这里用了一个简单示例来演示使用栈来完成这样的追踪调用过程

#include <iostream>
#include <stack>
#include <string>
#include <chrono>

// 线程局部调用栈
thread_local std::stack<std::string> call_stack;

class CallContext {
public:
    CallContext(const std::string& name) {
        call_stack.push(name);
        print_stack("Enter");
    }

    ~CallContext() {
        print_stack("Exit");
        call_stack.pop();
    }

private:
    void print_stack(const std::string& phase) {
        // ... 遍历栈, 打印调用链 ...
           // print(func_name, full_stack);
    }
};

void foo() {
    CallContext ctx("foo");
    bar();
}

void bar() {
    CallContext ctx("bar");
}

int main() {
    CallContext ctx("main");
    foo();
    return 0;
}

执行上方代码可以得到结果。由于在每个函数执行时,都往里面记录了当前函数的名称(“Enter”或”Exit”),然后打印栈信息,而栈又包括了链路信息,这样就可以知道执行到当前函数时的“调用链”。

[Enter] main -> ...
[Enter] main -> foo -> ...
[Enter] main -> foo -> bar -> ...
[Exit] main -> foo -> bar -> ...
[Exit] main -> foo -> ...
[Exit] main -> ...