Перейти к содержанию
    

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

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

Использую CW.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И излишества всякие, нехорошие ...

Думал просто 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;

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

freertos_tlsf.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

MEM2.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первый выделенный блок не освобождается.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Heap_mang.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Хочется более точно понять как и откуда выделяется память во 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. Если память выделяется динамически на этапе старта - инита оси, стеков и пр., а в дальнейшем изменения задач, мутексов и динамически выделяемых данных не предвидится, то есть ли смысл париться альтернативным кодом аллокаторов?

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так ли я понимаю, что при использовании 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 да и все. Она не освобождает память, поэтому реализация простая и очень быстрая...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...