Как измерить использование стека функций в C?

есть ли способ измерить, сколько стековой памяти использует функция?

этот вопрос не относится к рекурсивным функциям; однако мне было интересно узнать, сколько стековой памяти займет функция, называемая рекурсивно.

мне было интересно оптимизировать функцию для использования стековой памяти; однако, не зная, какие оптимизации компилятор уже делает, это просто догадка, если это делает реальные улучшения или нет.

в будьте ясны, это не вопрос о том, как оптимизировать для лучшего использования стека

Итак, есть ли надежный способ узнать, сколько стековой памяти использует функция в C?


Примечание: предполагая, что он не использует alloca или массивы переменной длины, это должно быть возможно найти во время компиляции.

3 ответов


используя предупреждения

это специфический 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)


Примечание

кажется, что большинство / все естественные методы компилятора полагаются на угадывание , которое не 100% обязательно останется точным после оптимизации, так что это, по крайней мере, дает окончательный ответ с помощью бесплатного компилятора.


вы можете очень легко узнать, сколько пространства стека занимает вызов функции, которая имеет только одно слово локальных переменных следующим образом:

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);
}

(Примечание: функция объявляет локальную переменную, которая является только байтом, но компилятор обычно выделяет для нее целое машинное слово в стеке.)

таким образом, это покажет вам, сколько пространства стека занимает вызов функции. Чем больше локальных переменных вы добавляете в функцию, тем больше пространства стека это займет много времени. Переменные, определенные в разных областях внутри функции, обычно не усложняют ситуацию, поскольку компилятор обычно выделяет отдельную область в стеке для каждой локальной переменной без какой-либо попытки оптимизации на основе того факта, что некоторые из этих переменных могут никогда не сосуществовать.


чтобы вычислить использование стека для текущей функции вы можете сделать что-то вроде этого:

void MyFunc( void );

void *pFnBottom = (void *)MyFunc;
void *pFnTop;
unsigned int uiStackUsage;

void MyFunc( void )
{
    __asm__ ( mov pFnTop, esp );
    uiStackUsage = (unsigned int)(pFnTop - pFnBottom);
}