131 lines
4.9 KiB
Markdown
131 lines
4.9 KiB
Markdown
# Karta pracy: FreeRTOS `heap_4`
|
||
|
||
Trzy programy wspierające kartę po K&R 5.4 oraz `structures`:
|
||
|
||
1. nagłówek, wyrównanie i geometria splitu na arenie 256 B;
|
||
2. lista adresowa + scalanie `A | B | C`;
|
||
3. niezmodyfikowany FreeRTOS-Kernel V11.3.0 `heap_4.c`.
|
||
|
||
W lekcji 30-minutowej programy 1–2 są demonstracjami z predykcją. Uczeń
|
||
debugguje wyłącznie program 3.
|
||
|
||
Task 3 linkuje upstream `portable/MemMang/heap_4.c` z commita
|
||
`9b777ae5c5b8e9e456065a00294d1e5f5f9facf5`.
|
||
|
||
- AMD64: rzeczywisty algorytm + jednowątkowy adapter sekcji krytycznej.
|
||
- Hazard3: `tasks.c`, `list.c`, `heap_4.c` i oficjalny port RISC-V.
|
||
- RP2350: zgodny core+port z forka Raspberry Pi (`4f7299d6ea74`) oraz
|
||
podstawiony stabilny allocator V11.3.0.
|
||
|
||
## Bezpośrednia kontynuacja K&R 5.4
|
||
|
||
Lekcja zaczyna się od gotowego projektu z poprzedniej karty:
|
||
`allocbuf[64]`, `allocp`, `alloc(5)`, `alloc(7)` oraz offsety
|
||
`0 -> 5 -> 12`. Ten alokator:
|
||
|
||
- nie potrafi zwolnić pierwszego bloku i zachować drugiego;
|
||
- nie przechowuje rozmiaru ani stanu zwróconego obszaru;
|
||
- nie zapamiętuje i nie wykorzystuje dziur;
|
||
- odzyskuje pamięć wyłącznie przez reset całej areny.
|
||
|
||
FC01 odpowiada na jedno pytanie projektowe: **co trzeba dodać, aby zwalniać
|
||
dowolny blok i ponownie wykorzystywać powstałe miejsce?** Odpowiedzią jest
|
||
mechanika `heap_4`: nagłówek bloku, lista wolnych bloków uporządkowana po
|
||
adresie, first-fit, split oraz scalanie fizycznych sąsiadów.
|
||
|
||
FreeRTOS udostępnia kilka wymiennych implementacji tego samego API i projekt
|
||
linkuje dokładnie jedną. `heap_1`, `heap_2`, `heap_3` i `heap_5` są w tej
|
||
karcie tylko jednominutową mapą kontekstu. Cała obserwowana implementacja to
|
||
niezmodyfikowany [`heap_4.c` z FreeRTOS-Kernel V11.3.0](https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/V11.3.0/portable/MemMang/heap_4.c).
|
||
|
||
Lekcja trwa 30 minut. Task 1 i Task 2 są krótkimi demonstracjami z predykcją;
|
||
Task 3 jest jedynym centralnym przebiegiem ucznia w debuggerze. Obraz dla
|
||
Pico 2 W musi być zbudowany i wgrany przed zajęciami. `heap_4` jest wyborem
|
||
linkera projektu, nie sprzętowym mechanizmem RP2350.
|
||
|
||
## Jedno wejście: `stemctl`
|
||
|
||
Centralny przebieg lekcji, przygotowany przed wejściem uczniów:
|
||
|
||
```bash
|
||
stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
|
||
```
|
||
|
||
Pełna weryfikacja repozytorium wykonywana poza 30-minutową lekcją:
|
||
|
||
```bash
|
||
stemctl series cards fetch freertos heap4
|
||
stemctl test native-amd64 freertos heap4 1
|
||
stemctl test hazard3-sim freertos heap4 2
|
||
stemctl debug hazard3-sim freertos heap4 3
|
||
stemctl test rp2350 freertos heap4 3
|
||
stemctl deploy rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
|
||
stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD
|
||
```
|
||
|
||
- `debug rp2350`: roboczy ELF `no_flash` ładowany do SRAM.
|
||
- `deploy rp2350`: trwały obraz w SPI flash, odczytany przez breakpointy.
|
||
|
||
## Kontrakt zadań
|
||
|
||
| Task | Sprawdza | Wynik kluczowy |
|
||
|---|---|---|
|
||
| 1 | alignment, header, split | `wanted + remainder == 256` |
|
||
| 2 | lista po adresie, coalescing | `2 bloki -> 1 blok`, `96 -> 144 B` |
|
||
| 3 | prawdziwe API FreeRTOS | free wraca do F0, minimum nie rośnie, OOM = NULL |
|
||
|
||
## Debugowanie Task 3
|
||
|
||
Automatyczny start: `heap4_reset_checkpoint`. Karta prowadzi po ośmiu
|
||
powtarzalnych stanach jednego procesu:
|
||
|
||
| Event | Symbol | Najważniejszy dowód Hazard3 |
|
||
|---|---|---|
|
||
| E01 | `heap4_reset_checkpoint` | `free=largest=4080`, 1 blok |
|
||
| E02 | `heap4_alloc_a_checkpoint` | A(24), `consumed=48`, `free=4032` |
|
||
| E03 | `heap4_alloc_b_checkpoint` | B(40), `consumed=64`, `free=3968` |
|
||
| E04 | `heap4_alloc_c_checkpoint` | C(16), `consumed=32`, `free=3936` |
|
||
| E05 | `heap4_free_a_checkpoint` | `free=3984`, 2 bloki |
|
||
| E06 | `heap4_fragmented_checkpoint` | `free=4016`, 2 bloki, `free>largest` |
|
||
| E07 | `heap4_coalesced_checkpoint` | `free=largest=4080`, 1 blok |
|
||
| E08 | `task03_debug_checkpoint` | OOM `NULL`, hook=1, asserts=0, PASS=1 |
|
||
|
||
`BlockLink_t` ma na RV32 8 B, ale port wymaga wyrównania 16 B, dlatego
|
||
`xHeapStructSize` wynosi 16 B. To rozróżnienie tłumaczy zużycie 48/64/32 B.
|
||
|
||
```gdb
|
||
p g_fragmented_stats
|
||
p g_final_stats
|
||
p g_a_consumed
|
||
p g_b_consumed
|
||
p g_c_consumed
|
||
p xFreeBytesRemaining
|
||
p xMinimumEverFreeBytesRemaining
|
||
p xStart
|
||
p pxEnd
|
||
x/160bx ucHeap
|
||
b prvInsertBlockIntoFreeList
|
||
b pvPortMalloc
|
||
b vPortFree
|
||
```
|
||
|
||
Scalanie sprawdzamy z replay E06: zatrzymujemy się przed `vPortFree(g_b)`,
|
||
ustawiamy tymczasowy breakpoint na `prvInsertBlockIntoFreeList` i krokujemy.
|
||
Upstream V11.3.0 scala najpierw poprzedni/lewy, a potem następny/prawy blok.
|
||
Pełna macierz kroków diagramów jest w
|
||
[`doc/hazard3-iteration-plan.md`](doc/hazard3-iteration-plan.md).
|
||
|
||
W UI: Termdebug po lewej; źródło i listing po prawej; bash pod Neovimem.
|
||
`F5` continue, `F9` breakpoint, `F10` next, `F11` step, `Shift-F11`
|
||
finish, `F8` stepi, `:StudentStack`, `:StudentMemory`, `:StudentLst`.
|
||
|
||
## Test repozytorium
|
||
|
||
```bash
|
||
./tests/test_host.sh
|
||
bash -n tools/card-action.sh
|
||
./scripts/render_pdf.sh
|
||
```
|
||
|
||
Źródło i licencja: [UPSTREAM.md](UPSTREAM.md).
|