Емельянов Эдуард Владимирович (eddy_em) wrote,
Емельянов Эдуард Владимирович
eddy_em

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

Занялся полным рефакторингом кода системы управления оптоволоконным спектрографом. А глаз уже "замыленный": ну вот не могу сходу обнаружить, где я забываю 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 потоков должно хватить, но кто знает?).
Буду искать, где ж собака порылась-то!
Reposted from dreamwidth: https://eddy-em.dreamwidth.org/301941.html.
Tags: c, рукожопие
Subscribe

promo eddy_em september 3, 12:13 8
Buy for 10 tokens
Уже больше полугода занимаюсь разработкой, вот, наконец-то в мастерских взялись за меня и начали выдавать первые детали. Сегодня сделал тестовую сборку (как обычно, местами пришлось "доработать напильником"): Пока прибор без названия (да и как-то не лезет в голову ничего, у меня нет…
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic
  • 12 comments