在调试中,如何知道对函数的重复调用中参数的统计数据(max-min,average,distribution..)

In debugging, how to know the stats (max-min, average, distribution...) of an argument in a repetitive calls to a function?

本文关键字:参数 统计数据 average distribution 调用 max-min 调试 何知道 函数      更新时间:2023-10-16

假设我有一个函数void Myclass::func(x),其他各种代码对它进行了数千次调用。现在我想知道参数x的一些统计数据,例如平均值、最大值、最小值,甚至分布图。

void Myclass::func(int x) {
while(foo.doFancyStuff(x)) {
// ...
}
}

以下是我想到的一些特殊方法:

  1. x的每个值打印到日志中。然后使用外部工具/脚本对其进行分析。
    • 注意事项:与日志中的其他信息混合。将x的每个值写入文件系统上的外部日志或文件是很慢的
  2. 定义全局变量以存储它们,并在感兴趣的执行结束时进行分析。
    • 注意事项:全局变量不好。它们将来会变得令人困惑
  3. 将它们存储在类别Myclass中。
    • 注意事项:不可重复使用的代码。下次我想分析Otherclass::doOtherStuff(y)时呢?以及糟糕的集成,因为统计代码不应该和Myclass本身耦合

有什么工具/库可以做到这一点吗?我在Windows上使用Visual Studio,所以希望得到一个适用于此平台的答案。跨平台工具也很受欢迎。

下面是一个使用lldb的脚本API的示例(它也适用于Windows)。以这个琐碎的程序为例,

void func(int x) {}
int main(int, char **)
{
for (int i = 0; i < 1000; ++i)
func(i);
}

你可以用这样的脚本来分析

import lldb
import os
fArgs = []
def analyzeFrame(frame, bpLocation, dict):
variables = frame.GetVariables(True, False, False, False)
x = variables.GetValueAtIndex(0).GetValueAsSigned()
fArgs.append(x)
return False
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(False)
target = debugger.CreateTargetWithFileAndArch("pathToYourExecutable", "")
bp = target.BreakpointCreateByName("func", 4, lldb.SBFileSpecList(), lldb.SBFileSpecList())
bp.SetScriptCallbackFunction("analyzeFrame")
process = target.Launch(target.GetDebugger().GetListener(), [], [],
None, None, None, os.getcwd(), 0, False, lldb.SBError())
print("max: {}".format(max(fArgs)))
print("min: {}".format(min(fArgs)))

您需要确保python解释器找到lldb模块。可以通过在命令行上执行lldb -P来查看路径。

不幸的是,没有一个简单的答案。您想要的是一种检测调试的变体,这意味着需要有人在您的类中注入额外的代码来处理这种情况。

对于可移植的方法,唯一的选择是添加以前值的缓存,然后在类析构函数中输出所需的统计信息。缓存数据的方式取决于您自己,您可以设计一个简单的Stats<>类,它是要监视的类的成员,并对其进行调用以存储新值。这将是我首先尝试的,因为它是便携式的,几乎是干净的,可重复使用的。