xv6, line by line
lab 14
Lab 1414 Superpages

Lab 14 · reveal · 18 steps · 9 commits

Superpages: the reference solution

Every user page in this tree is 4096 bytes, mapped by a PTE (page-table entry) in a level-0 page-table page that walk reaches through two higher levels. A process that grows its heap by 4 megabytes gets 1,024 PTEs, two level-0 page-table pages to hold them, and 1,024 translations for the hardware to cache. Yet the Sv39 hardware can map 2 megabytes with a single PTE one level higher up: a superpage (the RISC-V specification calls it a megapage).

In this lab you let sbrk use them. The idea is one sentence; the consequences reach into every corner of the memory system. Where does 2 megabytes of physically contiguous, aligned memory come from, when the allocator hands out single pages in no particular order, and what happens to that supply after the machine has been running for a while? Which page-table functions assume, without saying so, that every leaf sits at level 0, and what does each of them do when it meets one that does not? What does fork do with a superpage when no 2-megabyte chunk is free, and what does sbrk(-n) do when the new end falls in the middle of one?

The reference solution is nine small commits. With it, a 4-megabyte sbrk is mapped by two PTEs, a 64-megabyte heap needs 32 fewer page-table pages, and the allocator keeps all 63 chunks of RAM above the kernel available as superpages even after a full usertests run. You will also measure, honestly, what superpages do not buy on QEMU.

Each step shows one change on the branch ext/14-superpages, the code around it, and the state of the machine when that code runs.

The route
  1. 1A leaf, at any level kernel/riscv.h
  2. 2walklevel stops where the hardware stops kernel/vm.c
  3. 3walkaddr adds the offset inside the superpage kernel/vm.c
  4. 4Sixty-four chunks of RAM kernel/kalloc.c
  5. 5kfree puts a page back on its own chunk's list kernel/kalloc.c
  6. 6kalloc takes a page from the lowest chunk it can kernel/kalloc.c
  7. 7Superpages come from the top kernel/kalloc.c
  8. 8A split chunk can be whole again kernel/kalloc.c
  9. 9mapsuper writes one PTE at level 1 kernel/vm.c
  10. 10uvmunmap frees a superpage whole kernel/vm.c
  11. 11fork gives the child a superpage kernel/vm.c
  12. 12fork without a free superpage kernel/vm.c
  13. 13Splitting a superpage keeps its bytes kernel/vm.c
  14. 14uvmdealloc splits first; sbrk can now fail when shrinking kernel/vm.c
  15. 15The switch, in uvmalloc kernel/vm.c
  16. 16freewalk needed no change kernel/vm.c
  17. 17Asking the kernel what it did kernel/sysproc.c
  18. 18The test that makes fragmentation on purpose user/supertest.c

Keys: ← → step · Home start