如何向 C 函数添加分析调用?

Posted

技术标签:

【中文标题】如何向 C 函数添加分析调用?【英文标题】:How to add profiling calls to C functions? 【发布时间】:2019-06-13 02:37:42 【问题描述】:

我正在尝试创建一个 python 脚本来修改 C 源代码以适应时间并收集有关所选函数执行的其他指标。

目标是从配置文件开始,然后运行修改源代码的脚本以完成以下操作:

想法 A:

foo_profile()
    
    start_profile();
    foo();
    end_profile();
    

想法 B:

foo()
    
    start_profile();
    //dostuff
    end_profile();
    

A的考虑:

策略:通过插入拦截似乎最容易做到这一点 原型/定义到相同的头文件/src 文件中。离开 其他一切都相同(以防某些呼叫者未更改)。和的 当然为 start/end_profile() 添加包含。

需要识别 foo() 的正确调用者 有一些具有相同名称的函数受更高级别的构建系统保护,该系统将事物拆分为 项目/分区(很难自动确定,但 特定的配置可以解决问题) 需要识别具有 foo() 的正确标头 参数需要传递,并且会在堆栈中复制,这不是什么大问题,但可能会有点丢东西

B的考虑:

策略:这个很简单,只需添加配置文件调用。它 会有很多烦人的问题需要处理(以下)。 start_profile() 需要在变量声明后调用(arm) 不确定是否可以使用编译器标志忽略此错误,或者是否有此原因? (编译器特定我知道,但一般) 可以很容易地找到简单的局部变量 (ctags),但有一些宏被调用以进行参数验证,最终结果 声明难以自动找到的变量。 最终可能会得到一个宏黑名单来检查以添加 之后的个人资料电话。 end_profile() 当然需要在所有返回之前调用 如果调用的设置如下所示,则返回中的昂贵函数调用最终不会被分析:end_profile();return lucky_call(); 当然,expensive_call() 可以给定一个返回变量(最初声明),类型自动从包含的 标题。增加一些复杂性和潜在的问题(更多 堆栈,可能是一些奇怪的宏东西来破坏东西) 有什么方法可以告诉编译器将代码添加到序言/尾声? (我知道这是特定于编译器的,但前提是您有一个大致的想法是否可能)

概述/问题:

实施明智的 A 最有吸引力,但对于收集的信息和易于配置的 B 会更好。 B 似乎更难以实施/不太可靠。当然还有其他方法,比如修改链接,但以前的策略对我来说似乎是最好的。

所以我的问题归结为这里有我遗漏的策略吗?鉴于问题,您将如何解决?有什么我在这里没有提到的我应该考虑的吗?对于分散的问题或一般指导的任何帮助将不胜感激。

如果有任何不清楚的地方,我会尽快进行编辑和澄清。第一个问题,如果我搞砸了,请告诉我。

编辑:------------------------------ -------

我的 ARM 编译器有一个标志,可让您提供自己的进入/退出定义来执行此操作 (--gnu_instrument)。如果由于某种原因编译器不允许您这样做,我认为实际上更改真实定义的名称并使用脚本在具有相同签名的同一文件中添加回“真实”函数名称是最简单的(不是确定为什么我没有想到这一点)。这就是为什么所有呼叫都被检测并且您不必担心“拦截”的原因。像这样:

首字母:

foo()
    
    //do stuff
    

仪表化:

foo()
    
    start_profile();
    foo_unique_id();
    end_profile();
    

foo_unique_id()
    
    //do stuff
    

【问题讨论】:

您是在开发新的通用工具,还是在尝试解决特定问题?在后一种情况下,可能会有XY problem。如果您使用的是 GCC,请查看 gcovgprof 【参考方案1】:

看起来您正在尝试执行的操作称为代码检测,有点类似于this post。 GCC 有 -finstrument-functions(如果您使用 GCC),您可以阅读有关 here 和官方文档 here 的信息。 -finstrument-functions 似乎采用了第二种方法,将跟踪调用添加到现有函数中,而不是包装它。

【讨论】:

原来 ARMCC 有一个 --gnu_instrument 标志,可以让您定义进入和退出函数。这几乎正​​是我想做的事

以上是关于如何向 C 函数添加分析调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地分析相互递归函数

C语言不同文件的函数如何相互调用

如何向 v-data-table 添加点击事件?

如何向 Shader 传递一个巨大的数组

C语言在函数调用时,栈是如何变化的?

Fortran 调用 C:如何获得有效的矢量化函数