eddy_em: (Default)
eddy_em ([personal profile] eddy_em) wrote2021-10-13 04:29 pm

Разбираемся с утечками

Занялся полным рефакторингом кода системы управления оптоволоконным спектрографом. А глаз уже "замыленный": ну вот не могу сходу обнаружить, где я забываю free() сделать (тем более, что у меня там аллокаторы многоуровневые: вызываешь одну функцию, она — другую, и лишь в третьей вызывается аллокатор, поди-как обнаружь косяк). Вот и решил накидать макросов для логгирования проблемных мест.

Сделал надстройку над макросами аллокаторов и free, debug.h:
#include <usefull_macros.h>

#ifdef EBUG

extern sl_log *debuglog;
void makedebuglog();
void *my_malloc(size_t N, size_t S);
void my_free(void *ptr);

#undef FNAME
#undef ALLOC
#undef MALLOC
#undef FREE
#define _LOG(...)       do{if(!debuglog) makedebuglog(); sl_putlogt(1, debuglog, LOGLEVEL_ERR, __VA_ARGS__);}while(0)
#define DBGLOG(...)     do{_LOG("%s (%s, line %d)", __func__, __FILE__, __LINE__); \
                           sl_putlogt(0, debuglog, LOGLEVEL_ERR, __VA_ARGS__);}while(0)
#define FNAME()         _LOG("%s (%s, line %d)", __func__, __FILE__, __LINE__)

#define _str(x) #x
#define ALLOC(type, var, size)  DBGLOG("%s *%s = ALLOC(%d)", _str(type), _str(var), size*sizeof(type)); \
                                type * var = ((type *)my_malloc(size, sizeof(type)))
#define MALLOC(type, size)  ((type *)my_malloc(size, sizeof(type))); DBGLOG("ALLOC()")
#define FREE(ptr)           do{if(ptr){DBGLOG("FREE(%s)", _str(ptr)); my_free(ptr); ptr = NULL;}}while(0);

#else

#define DBGLOG(...)

#endif

И вот, что находится в debug.c:
#ifdef EBUG

#include <string.h>
#include <unistd.h>

#include "debug.h"

#define DEBUGLOG        "DEBUG.log"

sl_log *debuglog = NULL;

void makedebuglog(){
    unlink(DEBUGLOG);
    debuglog = sl_createlog(DEBUGLOG, LOGLEVEL_ANY, 0);
}

/**
 * @brief my_malloc - memory allocator for logger
 * @param N - number of elements to allocate
 * @param S - size of single element (typically sizeof)
 * @return pointer to allocated memory area
 */
void *my_malloc(size_t N, size_t S){
    size_t NS = N*S + sizeof(size_t);
    sl_putlogt(0, debuglog, LOGLEVEL_ERR, "ALLOCSZ(%zd)", N*S);
    void *p = malloc(NS);
    if(!p) ERR("malloc");
    memset(p, 0, NS);
    *((size_t*)p) = N*S;
    return (p + sizeof(size_t));
}

void my_free(void *ptr){
    void *orig = ptr - sizeof(size_t);
    sl_putlogt(0, debuglog, LOGLEVEL_ERR, "FREESZ(%zd)", *(size_t*)orig);
    free(orig);
}

#endif

Переопределил еще макрос FNAME, да добавил макросы _LOG и DBGLOG, чтобы можно было еще дополнительно что-нибудь в этот файл писать, да при необходимости помечать функции, в которые заходит в ходе выполнения.
Для анализа выхлопа DEBUG.log написал простой скриптик:
#!/bin/sh

ALLOC=$(grep ALLOCSZ DEBUG.log)
FREE=$(grep FREESZ DEBUG.log)

echo "Total: $(echo "$ALLOC" | wc -l) allocations and $(echo "$FREE" | wc -l) frees"
AL=$(echo "$ALLOC" | sed 's/ALLOCSZ(\([[:digit:]]*\))/\1/' | awk 'BEGIN{x=0;} {x=x+$1;} END{print x;}')
FR=$(echo "$FREE" | sed 's/FREESZ(\([[:digit:]]*\))/\1/' | awk 'BEGIN{x=0;} {x=x+$1;} END{print x;}')
echo "Allocated: $AL bytes, Freed: $FR bytes, difference: $((AL - FR)) bytes"


Запустил немного погонять, и что я вижу:
./DEBUG.log.analyze
Total: 4080 allocations and 3906 frees
Allocated: 5965517012 bytes, Freed: 5935556848 bytes, difference: 29960164 bytes

Рукожопие мое зело велико! На 4080 аллокаторов всего лишь 3906 освобождений памяти! И за несколько минут натекло аж 28.5МБ памяти! То-то оно и дохло через несколько часов работы… Интересно, что "потеряшек" всего с полпроцента от общей выделяемой памяти, т.е. теряется где-то в мелочевке (скажем, выделил память под объект, выделил память под его содержимое; содержимое освободил, а объект - нет). Ну и нужно проверить, успевают ли логгироваться все выделения/освобождения памяти в потоках openmp (дело в том, что у меня для записи лога файл открывается и блокируется, однако, если другой процесс/поток захочет туда же записать, он ждет не более 0.1с; теоретически, этого времени на 8 потоков должно хватить, но кто знает?).
Буду искать, где ж собака порылась-то!

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org