Jump to content

    

FreeRTOS Heap_x.c

Тестировал 2.4.2. Включил в свой проект и погонял свое устройство день. Все работало, как и с прежним аллокатором BGET (тоже известная вещь), т.е. никаких проблем замечено не было.

Подключил я этот алокатор. Вылетает в dabort_hamdler при входе в макрос EXTRACT_BLOCK_HDR(b, tlsf, fl, sl);

Использую CW.

Может уже разбирались с этой проблемой?

Share this post


Link to post
Share on other sites
И излишества всякие, нехорошие ...

Думал просто oткомментировать немного и выложить heap manager для FreeRTOS, но получается, что сначала нужно описывать почему он сделан именно так :(. Попробую:

1. Хотелось иметь возможность получения списков свободных и занятых блоков памяти во время консольной отладки.

2. Хотелось иметь признак для чего блок памяти используется системой (TCB/Stack, Очередь,...)

3. Хотелось иметь возможность знать какая задача породила тот или иной блок - самое простое, при запросе блока сохранять адрес TCB.

4. Обязательна возможность использовать с менеджером разрозненные блоки памяти в едином списке. И наоборот - использовать несколько независимо управляемых блоков памяти (например, если эти блоки памяти имеют разное назначение/свойства, или для ручной борьбы с дефрагментацией )

5. Особые навороты с для ускорения поиска свободных блоков типа "испанского варианта" не нужны, поскольку

- основная масса блоков памяти под задачи, очереди и прочее выделяется "навсегда" и естественно выделение начинается с них;

- относительно родной реализации FreeRTOS под задачу и очередь у меня выделяется по одному блоку памяти TCB+Stack и QCB+Queue вместо отдельных.

- в результате в реальности занимаются/освобождаются обычно 2-3-5-ну чуть больше блоков и найти подходящий по размеру проще и быстрее простым перебором из свободных.

6. Борьба с дефрагментацией:

- склеивание соседних свободных блоков в один;

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

 

Как строим:

1. Один общий связанный список, или отдельные для свободных и занятых. Использую один общий. Решающая причина - простой механизм склейки свободных блоков. При этом недостатки такого подхода нивелирутся тем, что ввиду (п.5) дефрагментация только в хвосте списка и длинна списка для поиска свободного эффективно сокращается использованием всего одного дополнительного указателя на первый свободный блок в общем списке.

2. На MCB выделено достаточно много памяти - 16 байт. Для максимально кастрированного варианта типа родных heap_*.с и с ограничением на размеры выделяемого блока можно было и в 4 байта уложиться, но см. "хотелки". Без особого напряга можно было в 12 байт уложиться, но тем неменее исходя из того, что например, для ARM стека выравнивание на 8 байт надо.... Пусть будет на данный момент 16 байт.

typedef union type_size {
    unsigned long size;
    struct {
    unsigned long xlen:24;
    unsigned long type:8;
    };
}type_size;

// Memory Control Block (MCB)
typedef struct heap_mcb
{
    struct heap_mcb *next;       // Указатель на следующий MCB
                                  // mcb.next  последнего MCM всегда указывает на
                                  // первый MCB.
    struct heap_mcb *prev;       // Указатель на предыдущий MCB.
                                // Для первого MCB этот указатель указывает
                                // сам на себя.
    union type_size ts;          // Размер блока памяти и тип блока

    void  *ow;        // ТСВ Владельца блока памяти
                                // Собственно контролируемый блок памяти расположен сразу за MCB
} heap_mcb;


// Структура-описатель HEAP (тип-структура t_heap)
typedef struct heap_t
{     // Указатель на начало heap (первый MCB)
    struct heap_mcb *start;
    // Указатель на первый свободный MCB
    struct heap_mcb *freem;
    // RAW размер HEAP
    unsigned long hsize;
} heap_t;

Осталось откомментировать и выложить исходники. Завтра...

Share this post


Link to post
Share on other sites

Оптимально-простой в соответствии с ранее изложенными принципами менеджер памяти.

Подгибать, немного по месту, естественно, надо.

Инициализация у меня, например, в одном из применений выглядит примерно так:

#pragma segment="HEAP_RTOS"
#pragma segment="XXX_STACK"
void init_system_heap( int add_ram_id )
{
    system_heap.start = (heap_mcb *)(__segment_begin( "HEAP_RTOS"));
    system_heap.freem = (heap_mcb *)(__segment_begin( "HEAP_RTOS"));
    system_heap.hsize = (ulong)(__segment_begin( "XXX_STACK")) - (ulong)(__segment_begin( "HEAP_RTOS")) + 1;

    heapinit( &system_heap );
    if( add_ram_id == 2148 )              // LPC2148  USB Memory as General prupose RAM
              heapadd( &system_heap, (void *)0x7FD00000, 0x2000 );

}

Для стандартной FreeRTOS можно для начала обертки сделать

#define pvPortMalloc( size )    malloc_z( &system_heap, (size), MARK_SYSTEM, NULL )
#define vPortFree( ptr )              free_z( &system_heap, (ptr) )

MEM.rar

Share this post


Link to post
Share on other sites

Прикрутил к FreeRTOS TLSF

~3kB RAM уходит на таблицу.

Не нашёл описания на кучу дефайнов в tlsf.c, походу минимальный выделяемый блок 128 байт.

 

freertos_tlsf.zip

Share this post


Link to post
Share on other sites

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

Архив с исправлениями в приложении.

MEM2.rar

Share this post


Link to post
Share on other sites

Спасибо за исходники. Пошел подтачивать под ansi.

Share this post


Link to post
Share on other sites

Первый выделенный блок не освобождается. Наверное перекрестную проверку нужно изменить с

    xptr = tptr->prev;
    if( ( xptr->next != tptr )||( mem_ptr < heap->start ) )
    {   xTaskResumeScheduler();
         return;
    }

на

    xptr = tptr->prev;
    if ( ((xptr != tptr) && ( xptr->next != tptr )) || ( mem_ptr < (void*)heap->start ) )
    {
        xTaskResumeScheduler();
        return;
    }

Share this post


Link to post
Share on other sites
Первый выделенный блок не освобождается.

Типа да, это тоже были особенности использования в системе, которая имеет как минимум одну idle задачу, которая занимает минимум один блок.

Если это не так, то добавить этот код надо.

Share this post


Link to post
Share on other sites
Типа да, это тоже были особенности использования в системе, которая имеет как минимум одну idle задачу, которая занимает минимум один блок.

Да это понятно. Спасибо за исходники.

Share this post


Link to post
Share on other sites

Исходники аллокатора от zltigo оказались очень полезными. Их, правда, пришлось почти полностью переписать, но идея, положенная в основу самая правильная. В результате получилась heap, которая при размере в 15 килобайт устойчиво держится в системе FreeRTOS, lwip (полный) и FatFS.

Heap_mang.rar

Share this post


Link to post
Share on other sites

Раз уж подняли тему.

Модулей диагностики (хотя б печать занятых/свободных блоков) для штатных heap2/heap4 никто не делал? Вроде б очень нужная вещь для отладки, но найти я не смог.

 

Или все внешние прикручивают? Странно это...

Share this post


Link to post
Share on other sites

Вот это и было одной из причин использовать собственный аллокатор. На моей плате хеапы из дистрибутива FReeRTOS увеличивали размер кучи после просмотра двух-трех страниц lwipa и чтения пары килобайт из конфигурационных файлов. Оказалось что они почти не следят за освободившимися блоками, не умеют их объединять. Системный malloc приводил к таким же результатам - ему требовался большой стек.

Share this post


Link to post
Share on other sites

Добрый день, коллеги!

Хочется более точно понять как и откуда выделяется память во FreeRTOS и особенности функционирования отдельных выделяльщиков.

Проект в IARe, в конфигурации линковщика есть параметр "heap".

Так ли я понимаю, что при использовании heap_1.c, heap_2.c, heap_4.c для оси выделяется динамическая память размером "configTOTAL_HEAP_SIZE".

 

Вопрос 1. Откуда она выделяется? Т.е. "configTOTAL_HEAP_SIZE" это часть "heap" или "configTOTAL_HEAP_SIZE" - это память, забираемая плюсом к "heap"? Т.е. сколько мне остается на переменные проекта :-)

 

Вопрос 2. Для heap_3.c размер кучи - это "heap" линковщика?

 

Вопрос 3. В последних версиях FreeRTOS heap_4.c (heap_5.c) имеет все равно проблемы с фрагментацией?

 

Вопрос 4. Если память выделяется динамически на этапе старта - инита оси, стеков и пр., а в дальнейшем изменения задач, мутексов и динамически выделяемых данных не предвидится, то есть ли смысл париться альтернативным кодом аллокаторов?

 

 

 

Share this post


Link to post
Share on other sites
Так ли я понимаю, что при использовании heap_1.c, heap_2.c, heap_4.c для оси выделяется динамическая память размером "configTOTAL_HEAP_SIZE".

Не понял что значит "для оси выделяется динамическая память"? configTOTAL_HEAP_SIZE задает объем памяти, доступный через pvPortMalloc. Память с его помощью выделяет сама ОС, и он же может использоваться в пользовательском коде...

 

Вопрос 1. Откуда она выделяется? Т.е. "configTOTAL_HEAP_SIZE" это часть "heap" или "configTOTAL_HEAP_SIZE" - это память, забираемая плюсом к "heap"? Т.е. сколько мне остается на переменные проекта :-)

Есть массив размера configTOTAL_HEAP_SIZE, из него память и выделяется.

 

Вопрос 2. Для heap_3.c размер кучи - это "heap" линковщика?

void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn;

    vTaskSuspendAll();
    {
        pvReturn = malloc( xWantedSize );
    }
    xTaskResumeAll();    
    return pvReturn;
}

КО подсказывает, что да :)

 

Вопрос 3. В последних версиях FreeRTOS heap_4.c (heap_5.c) имеет все равно проблемы с фрагментацией?

Я сижу на 7.4.0, на моих применениях полет нормальный. heap_4 выполняет склейку соседних блоков памяти при освобождении.

 

Вопрос 4. Если память выделяется динамически на этапе старта - инита оси, стеков и пр., а в дальнейшем изменения задач, мутексов и динамически выделяемых данных не предвидится, то есть ли смысл париться альтернативным кодом аллокаторов?

Используй heap_1 да и все. Она не освобождает память, поэтому реализация простая и очень быстрая...

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this