Changes between Version 48 and Version 49 of AS6-TME-B6


Ignore:
Timestamp:
Mar 29, 2022, 8:32:34 PM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B6

    v48 v49  
    5454  - Cette demande de place a pour effet de créer un bloc vide.
    5555  - L'API de cet allocateur est `void * malloc(size_t)` et `void free(void *)`
    56   - `void * malloc(size)` (politique de remplissage first fit)
     56  - `void * malloc(size)` (politique de remplissage first-fit)
    5757    - La fonction parcourt l'ensemble des blocs en commençant par le tout premier à la recherche d'un bloc vide assez grand pour contenir `size`.
    5858    - Si la place restante est plus petite qu'une ligne de cache, alors l'ensemble du bloc est marqué comme `plein`.
     
    169169'''
    170170}}}
    171 1. L'allocateur d'objets (nommés blocs dans le rappel de cours au-dessus) pour l'application utilise une politique ''first fit''. Qu'est-ce que cela signifie ? Quels sont les autres ? Existe-t-il une politique meilleure que les autres et pour quel critère ?
    172 {{{#!protected ------------------------------------------------------------------
    173 '''
    174  * L'allocation ''first fit'' signifie que l'allocateur utilise le premier bloc libre assez grand pour l'objet alloué. Ce bloc libre est coupé en deux s'il est trop grand pour produire un nouveau bloc libre, mais plus petit parce qu’amputé de la partie allouée à l'objet.
    175  * On a aussi l'allocation ''next fit'' qui consiste à ne pas partir du début dans la recherche d'un bloc libre, mais de l'endroit de la dernière affectation, et la l'allocation ''best fit'' qui consiste à trouver un bloc libre de la bonne taille en premier.
     1711. L'allocateur d'objets (nommés blocs dans le rappel de cours au-dessus) pour l'application utilise une politique ''first-fit''. Qu'est-ce que cela signifie ? Quels sont les autres ? Existe-t-il une politique meilleure que les autres et pour quel critère ?
     172{{{#!protected ------------------------------------------------------------------
     173'''
     174 * L'allocation ''first-fit'' signifie que l'allocateur utilise le premier bloc libre assez grand pour l'objet alloué. Ce bloc libre est coupé en deux s'il est trop grand pour produire un nouveau bloc libre, mais plus petit parce qu’amputé de la partie allouée à l'objet.
     175 * On a aussi l'allocation ''next-fit'' qui consiste à ne pas partir du début dans la recherche d'un bloc libre, mais de l'endroit de la dernière affectation, et la l'allocation ''best-fit'' qui consiste à trouver un bloc libre de la bonne taille en premier.
    176176 * Il en existe d'autres, leur but est d'augmenter les performances et de réduire la fragmentation.
    177177 * Il n'y a pas de meilleures solutions, mais si on connaît la nature des besoins en termes d'allocation, on peut imaginer des mécanismes plus efficaces.
     
    299299    ├── libc.c
    300300    ├── libc.h
    301     ├── memory.c             // code de l'allocateur first fit
     301    ├── memory.c             // code de l'allocateur first-fit
    302302    ├── memory.h             // prototype de l'allocateur
    303303    ├── thread.c
     
    307307
    308308
    309 == B.1. Transformer l'allocateur first fit et allocateur next fit
    310 
    311 L'allocateur first fit parcourt la liste des blocs depuis le tout premier jusqu'à la fin à la recherche du premier bloc non plein assez grand pour l'objet à allouer.
    312 
    313 
    314 == B.2. Transformer l'allocateur first/next fit et allocateur best fit
     309== B.1. Transformer l'allocateur first-fit et allocateur next-fit
     310
     311L'allocateur first-fit parcourt la liste des blocs depuis le tout premier jusqu'à la fin à la recherche du premier bloc non plein assez grand pour l'objet à allouer. Pour transformer ce comportement en next-fit, il suffit de se souvenir du dernier bloc alloué.
     312
     313Dans le code ci-après, on peut voir la fonction `try_malloc()` appelée par la fonction `malloc()`.
     314On voit que les blocs sont parcouru depuis `Heap.beg` le premier bloc jusqu'au dernier `Heap.end` (qui n'est pas vraiment un bloc mais une frontière). Lisez le code et trouvez comment recommencer le prochain `try_malloc()` à partir de dernier bloc alloué. Ce n'est pas difficile, mais il faut comprendre...
     315
     316{{{#!c
     317static size_t CacheLineSize;    // cache line size set by malloc_init()
     318
     319typedef struct block_info_s {   // small structure always put at the beginning of each blocks
     320    unsigned full:1;            // 1 full, 0 free (means empty)
     321    unsigned magic:7;           // MAGIC_HEAP : magic number to check the corruption
     322    unsigned size:24;           // Number of block_info to the next block_info
     323} block_info_t;
     324
     325static struct heap_s {          // user Heap
     326    block_info_t *beg;          // Heap beginning
     327    block_info_t *end;          // Heap end
     328} Heap;
     329
     330#define LINE_FLOOR(p)   (block_info_t *)FLOOR((size_t)(p),CacheLineSize)
     331#define LINE_CEIL(p)    (block_info_t *)CEIL((size_t)(p),CacheLineSize)
     332#define BINFO_SZ        sizeof(block_info_t)
     333
     334static void* try_malloc (size_t size)
     335{
     336    size = CEIL (size+BINFO_SZ, CacheLineSize);             // true required size in bytes
     337    size = size / sizeof (block_info_t);                    // in the heap size is in block_info_t
     338    block_info_t *oldnext, *newnext, *new;
     339
     340    for (new = Heap.beg;                                    // from the beginning of the Heap
     341        (new < Heap.end) && (new->full||(new->size<size));  // while end not reached and no space
     342        new += new->size);                                  // go to next block
     343
     344    if (new > Heap.end) return NULL;                        // end reached without finding space
     345
     346    new->full = 1;                                          // space found, we put the block
     347    oldnext = new + new->size;                              // next block address before the cut
     348    newnext = LINE_CEIL(new+size);                          // find the new next block
     349
     350    if (newnext != oldnext) {                               // if we need to cut the find block
     351        new->size = newnext - new;                          // new size of current block
     352        new->magic = MAGIC_HEAP;                            // to try detect Heap corruption
     353        newnext->size = oldnext - newnext;                  // new size of remainning space
     354        newnext->full = 0;                                  // that is free space
     355        newnext->magic = MAGIC_HEAP;                        // to try detect Heap corruption
     356    }
     357    return (void *)(new + 1);                               // the allocated block after block_info
     358}
     359
     360void * malloc (size_t size)
     361{
     362    block_info_t *ptr = try_malloc (size);                  // Search for a block
     363    if (ptr == NULL) {                                      // if no free space
     364        merge (Heap.beg);                                   // merge all free blocks from beginning
     365        ptr = try_malloc (size);                            // try again to find a block
     366    }
     367    return ptr;                                             // return what you have found
     368}
     369}}}
     370
     371
     372== B.2. Transformer l'allocateur first-fit en allocateur best-fit
     373
     374Plus difficile, passer l'allocateur en best-fit. Je ne vous demande pas d'écrire le code, sauf si vous avez du temps et de la motivation. En revanche, vous pouvez réfléchir à la manière de procéder. Pour vous aidez, l'idée, c'est de ne pas toucher aux chaînages des blocs utilisés par first-fit. Il faut créer un chaînage ordonné par taille des blocs libres en utilisant l'API `list`.
    315375
    316376== B.3. Tester que les piles n'ont pas débordées
     377
     378
    317379
    318380== B.4. Faire en sorte que les listes d'objets libres du noyau ne retombent à 0