Получить стек вызовов в коде с меньшими затратами?

Я собираюсь реализовать внутренний профилировщик памяти в Linux. Я хочу сохранить стек для каждого malloc/free/realloc. Я пытаюсь использовать «pstack», чтобы каждый раз получать трассировку стека. Но накладные расходы слишком высоки. Есть ли какой-нибудь легкий подход для получения стека вызовов в коде C?

Я знаю, что есть такие инструменты, как "valgrind, google profiler", но не знаю, как они запоминают стеки для каждого действия.

Любой комментарий приветствуется.

Спасибо.


person limi    schedule 05.08.2009    source источник
comment
Как насчет того, чтобы перефразировать ваш «вопрос» в настоящий вопрос?   -  person Bombe    schedule 05.08.2009
comment
Вы всегда можете просто взглянуть на исходный код valgrinds. [valgrind.org/downloads/]   -  person GManNickG    schedule 05.08.2009
comment
отредактировано. Извините за нечеткое описание.   -  person limi    schedule 05.08.2009
comment
да. Я собираюсь получить кое-что из исходного кода valgrind.   -  person limi    schedule 05.08.2009


Ответы (4)


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

static inline void *get_caller(void) {
    unsigned long *ebp;

    /* WARNING: This is working only with frame pointers */
    asm ("movl %%ebp, %0" : "=r" (ebp) : );
    ebp = (unsigned long*)*ebp;
    ebp = (unsigned long*)*(ebp+1);
    return ebp;
}

void *malloc(void) {
    void *caller = get_caller();
    ...    
}

"ebp = (unsigned long*)*ebp;" заставит вас просмотреть стек (если вам нужно больше этой трассировки стека).

person Nicolas Viennot    schedule 05.08.2009

Существует функция GNU backtrace(), которая относительно быстра — она просто возвращает массив адресов.

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

Чтобы backtrace_symbols() действительно разрешать имена, вам нужно использовать -rdynamic параметры компоновщика.

Подробнее см. man backtrace.

person qrdl    schedule 05.08.2009

Остерегайтесь рекурсий с помощью backtrace_symbols(), которая вызывает сам malloc.

Также обратите внимание, что при первом использовании backtrace() и ее друзей динамический компоновщик попытается загрузить libgcc, который снова вызовет malloc.

Гилад

person gby    schedule 09.08.2009

Сейчас встречаю проблему на 64bit.

На 64-битной версии RBP строго не поддерживается. Например, gcc -O3 будет использовать RBP как обычный регистр, сохраненный вызывающей стороной. Так что в этом случае получить стеки вызовов из указателей фреймов не получится. :(

Любые комментарии?

person limi    schedule 14.08.2009
comment
на 64-битной, теперь я использую backtrace() - person limi; 15.08.2009