Files
lab-rv32i-freertos-heap-models/doc/card-plan.md
T

119 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# K05 — C++ heap bridge, heap models and HeapStats
## Position
- Series: FreeRTOS C++
- Lesson: L04, card K05
- Duration: 30 minutes
- Runtime: real FreeRTOS V11.3.0 `heap_4.c` on Hazard3/RV32I
- C++ mode: freestanding C++17, no exceptions, RTTI or hosted `libstdc++`
- New surface: `HeapStats`, `HeapWatermark`, complete `new`/`delete` bridge
K03 proved one-owner RAII, while K05 now exposes the allocator policy and its
metrics. It does not introduce runtime resource selection; K06 will build that
on top of the explicit failure and alignment contract established here.
## Outcome
After 30 minutes the student can choose among `heap_1``heap_5` for a stated
memory topology/lifetime policy, enumerate all C++ allocation bridge forms,
distinguish total free bytes from largest free block, and prove that
minimum-ever free bytes retain history after current free returns to baseline.
## Lesson plan — 30 minutes
| Time | Mode | Evidence |
| --- | --- | --- |
| 05 | choose policy | justify heap scheme for three deployments |
| 59 | bridge | trace `new[] -> pvPortMalloc` and `delete[] -> vPortFree` |
| 914 | predict | draw A/B/C blocks and predicted stats after freeing A/C |
| 1421 | Hazard3 | prove `request < total`, `request > largest`, failure |
| 2126 | coalescence | free B; retry same request; inspect one free block |
| 2630 | history/exit | baseline recovery versus minimum-ever history |
## Policy table
| Scheme | Free? | Coalesce? | Key deployment constraint |
| --- | --- | --- | --- |
| heap_1 | no | n/a | monotonic startup allocation only |
| heap_2 | yes | no | holes remain separate; fragmentation grows |
| heap_3 | libc | libc | linker/compiler must provide a suitable heap |
| heap_4 | yes | yes | one FreeRTOS-owned region |
| heap_5 | yes | yes | regions defined in increasing address order before allocation |
Student choices:
1. All objects allocated once at startup, never deleted: `heap_1` is a valid
simplest policy.
2. One freestanding RAM region, dynamic tasks/queues with deletion: `heap_4`.
3. Two disjoint RAM banks that must both feed the kernel allocator: `heap_5`.
`heap_3` is not treated as a portable freestanding default because it delegates
storage and behavior to the compiler C library and linker heap.
## Canonical experiment
```text
baseline: [ free ........................................ ]
allocate: [ A 2K ][ B 4K ][ C 2K ][ free ............... ]
free A/C: [ free ][ B live ][ free + trailing free ...... ]
total=12256, largest=10192, blocks=2
request 10193 -> FAIL (sum is enough, no individual block is)
free B: [ one coalesced free block ..................... ]
retry 10193 -> SUCCESS
free retry -> current free returns to baseline
minimum-ever remains at the historical low
```
Exact values may change with alignment/header configuration. Assessment uses
relations, except for the fixed requested payload sizes in the source.
## Stable evidence contract
| Evidence | Required relation |
| --- | --- |
| C++ addresses | three distinct, aligned addresses inside `ucHeap` |
| bridge counters | allocations=3, deallocations=3, live=0 |
| deallocation order | A, C, B |
| fragmented stats | free blocks >=2 and total > largest |
| failed request | largest < request < total; successful allocations unchanged |
| coalesced stats | free blocks=1; largest=current=baseline |
| retry | same request succeeds inside `ucHeap` |
| final stats | current=baseline, minimum-ever remains below current |
## Complete bridge contract
```cpp
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;
void operator delete(void*, size_t) noexcept;
void operator delete[](void*, size_t) noexcept;
```
Ordinary `new` is fail-fast in this course profile because exceptions are off.
The recoverable experiment uses raw `pvPortMalloc` and checks `nullptr`.
## Misconceptions
1. Total free bytes do not imply one payload of that size can be allocated.
2. Returning to the current-free baseline does not erase the minimum-ever
watermark.
3. `heap_4` limits external fragmentation by coalescing; it cannot promise
absence of all fragmentation while live blocks separate holes.
4. A C++ bridge selects one heap domain; it does not merge five schemes.
5. `heap_3` inherits the C library/linker heap contract and is therefore not a
self-contained freestanding answer.
## Acceptance
- host test verifies field mapping and current/peak watermark calculations;
- ABI test finds all six allocation functions and no hosted C++ runtime;
- Hazard3 reaches all seven checkpoints and PASS;
- failure request lies strictly between largest block and total free bytes;
- retry succeeds only after B is freed and blocks coalesce;
- student chooses heap_1, heap_4 and heap_5 for the three stated scenarios and
justifies each constraint.