Demo: Which View Each Step Edits¶
Reserve 4 MB, touch the first byte of every page, touch the last byte of every page, unmap.
ps and the fault counter say which of the four steps changed what.
Goal¶
Attach each operation to the structure it edits: mmap() and munmap() change the list of zones, and only the first access to a page changes the page table.
Background¶
reserve_allocate.c maps 1024 pages, waits, writes to byte 0 of every page, waits, writes to byte 4095 of every page, waits, unmaps, waits.
VSZ is the sum of the zones; RSS is the number of valid page table entries times four; min_flt counts the page faults the process has taken.
Build and run¶
Two terminals. In the first:
In the second, at every prompt:
Results and explanations¶
VSZ RSS MINFL
before 2752 1692 64
after mmap(4 MB) 6848 1692 64
after writing byte 0 of every page 6848 5788 1088
after writing byte 4095 of every page 6848 5788 1088
after munmap() 2752 1692 1088
Step by step:
mmap():VSZup by 4,096 KB,RSSand the fault count unchanged. A zone was added to the list; the page table was not touched; the 1024 entries for the new zone are all still invalid.- First write to every page:
VSZunchanged,RSSup by 4,096 KB, 1,024 page faults. The list of zones was not touched; 1024 page-table entries went from invalid to valid, one per fault, each with a freshly zeroed frame behind it. - Second write to every page: nothing changed. Byte 4095 is in the same page as byte 0, the entry is valid, and the hardware translated the address on its own; the kernel never heard about it.
munmap():VSZdown by 4,096 KB,RSSdown by 4,096 KB. The zone is removed from the list, and with it every page-table entry inside it is invalidated and its frame freed. The fault counter keeps its history.
The unit of the second structure is the page: 4,096 bytes, one entry, one fault, however many of those bytes the program uses.
Going further¶
- Change the loop to touch every 8 KB and
RSSgrows by 2 MB, with 512 faults. - Touch the pages in reverse order: the same 1,024 faults; the order of first touches does not matter to the table.
- Replace
mmap()withmalloc()of the same size: the same numbers, because the allocator callsmmap()for a request this large. Replace it withcalloc()and still the same:calloc()knows fresh pages are zero and does not touch them.
References¶
man 2 mmap,man 1 ps,man 5 proc(/proc/[pid]/stat, field 10)