如何测量 C 中的函数堆栈使用情况?
How to measure a functions stack usage in C?
有什么方法可以测量一个函数使用了多少堆栈内存?
这个问题不是针对递归函数的;但是我很想知道递归调用的函数需要多少堆栈内存。
我有兴趣优化堆栈内存使用的函数;然而,在不知道编译器已经进行了哪些优化的情况下,这是否在进行真正的改进,这只是猜测。
需要说明的是,这不是关于如何优化堆栈使用的问题
那么有没有一些可靠的方法可以找出函数在 C 中使用了多少堆栈内存?
注意:假设它没有使用 alloca
或 可变长度数组 ,
应该可以在编译时找到它。
你可以很容易地找出调用一个只有一个局部变量的函数占用了多少堆栈space,方法如下:
static byte* p1;
static byte* p2;
void f1()
{
byte b;
p1 = &b;
f2();
}
void f2()
{
byte b;
p2 = &b;
}
void calculate()
{
f1();
int stack_space_used = (int)(p2 - p1);
}
(注意:函数声明了一个只有一个字节的局部变量,但编译器一般会在栈上为其分配一个完整的机器字。)
因此,这将告诉您函数调用占用了多少堆栈 space。添加到函数中的局部变量越多,它占用的堆栈 space 就越多。在函数内不同范围内定义的变量通常不会使事情复杂化,因为编译器通常会在堆栈上为每个局部变量分配一个不同的区域,而不会根据其中一些变量可能永远不会共存的事实进行任何优化。
要计算当前函数的堆栈使用情况,您可以这样做:
void MyFunc( void );
void *pFnBottom = (void *)MyFunc;
void *pFnTop;
unsigned int uiStackUsage;
void MyFunc( void )
{
__asm__ ( mov pFnTop, esp );
uiStackUsage = (unsigned int)(pFnTop - pFnBottom);
}
使用警告
这是特定于 GCC 的 (使用 gcc 4.9 测试):
在函数上方添加:
#pragma GCC diagnostic error "-Wframe-larger-than="
报告如下错误:
error: the frame size of 272 bytes is larger than 1 bytes [-Werror=frame-larger-than=]
虽然方法有点奇怪,但您至少可以在编辑文件时快速执行此操作。
使用 CFLAGS
您可以将 -fstack-usage
添加到您的 CFLAGS,然后它会在目标文件旁边写出文本文件。
参见:https://gcc.gnu.org/onlinedocs/gnat_ugn/Static-Stack-Usage-Analysis.html
虽然这非常有效,但根据您的 buildsystem/configuration 可能有点不方便 - 使用不同的 CFLAG 构建单个文件,尽管这当然可以自动化。
– (感谢@nos 的评论)
注意,
似乎 most/all 的编译器自然方法依赖于猜测 - 优化后不能 100% 确定保持准确,所以这至少给出了一个明确的答案使用免费编译器.
有什么方法可以测量一个函数使用了多少堆栈内存?
这个问题不是针对递归函数的;但是我很想知道递归调用的函数需要多少堆栈内存。
我有兴趣优化堆栈内存使用的函数;然而,在不知道编译器已经进行了哪些优化的情况下,这是否在进行真正的改进,这只是猜测。
需要说明的是,这不是关于如何优化堆栈使用的问题
那么有没有一些可靠的方法可以找出函数在 C 中使用了多少堆栈内存?
注意:假设它没有使用 alloca
或 可变长度数组 ,
应该可以在编译时找到它。
你可以很容易地找出调用一个只有一个局部变量的函数占用了多少堆栈space,方法如下:
static byte* p1;
static byte* p2;
void f1()
{
byte b;
p1 = &b;
f2();
}
void f2()
{
byte b;
p2 = &b;
}
void calculate()
{
f1();
int stack_space_used = (int)(p2 - p1);
}
(注意:函数声明了一个只有一个字节的局部变量,但编译器一般会在栈上为其分配一个完整的机器字。)
因此,这将告诉您函数调用占用了多少堆栈 space。添加到函数中的局部变量越多,它占用的堆栈 space 就越多。在函数内不同范围内定义的变量通常不会使事情复杂化,因为编译器通常会在堆栈上为每个局部变量分配一个不同的区域,而不会根据其中一些变量可能永远不会共存的事实进行任何优化。
要计算当前函数的堆栈使用情况,您可以这样做:
void MyFunc( void );
void *pFnBottom = (void *)MyFunc;
void *pFnTop;
unsigned int uiStackUsage;
void MyFunc( void )
{
__asm__ ( mov pFnTop, esp );
uiStackUsage = (unsigned int)(pFnTop - pFnBottom);
}
使用警告
这是特定于 GCC 的 (使用 gcc 4.9 测试):
在函数上方添加:
#pragma GCC diagnostic error "-Wframe-larger-than="
报告如下错误:
error: the frame size of 272 bytes is larger than 1 bytes [-Werror=frame-larger-than=]
虽然方法有点奇怪,但您至少可以在编辑文件时快速执行此操作。
使用 CFLAGS
您可以将 -fstack-usage
添加到您的 CFLAGS,然后它会在目标文件旁边写出文本文件。
参见:https://gcc.gnu.org/onlinedocs/gnat_ugn/Static-Stack-Usage-Analysis.html
虽然这非常有效,但根据您的 buildsystem/configuration 可能有点不方便 - 使用不同的 CFLAG 构建单个文件,尽管这当然可以自动化。
– (感谢@nos 的评论)
注意,
似乎 most/all 的编译器自然方法依赖于猜测 - 优化后不能 100% 确定保持准确,所以这至少给出了一个明确的答案使用免费编译器.