How can I decommit a file-mapped page? - winapi

I have a memory mapped file, and a page in a view which is currently committed. I would like to decommit it. MapViewOfFile tells me I cannot use VirtualFree on file mapped pages. Is there some other way to do it?

You cannot decommit it, but what you really want is not decommitting it ...
What you really want is to release the page from a memory. This can be done by using VirtualUnlock. See VirtualUnlock Remarks:
Calling VirtualUnlock on a range of memory that is not locked releases the pages from the process's working set.
Note: As documented, the function will return FALSE (the page was not locked) and GetLastError will return ERROR_NOT_LOCKED.
This is described in Guillermo Prandi's question CreateFileMapping, MapViewOfFile, how to avoid holding up the system memory.
Remarks: I think you can view it this way: decommitting a mapped page is nonsense - pages is commited whenever it is backed by a physical storage, be it a memory or a file. File mapped page cannot be decommitted in this sense, as it will be always backed by the file.
However, the code in the question mentioned is measuring the memory footprint, but what it measures is not representative, as the fact the page is removed from the process working set does not necessarily mean it is no longer present in a memory.
I have performed a different experiment, measuring how long it takes to read a byte from a memory mapped page. After unlocking the page or unmapping the view and closing the mapping handle the access was still fast.
For the access to be slow (i.e. to really discard the page from the memory) it was necessary to unmap the view and close BOTH memory mapping handle and file handle (the last was surprising to me, as I expected unmapping the view and closing the mapping handle will be enough).
It is still possible system will take VirtualUnlocked as a hint and it will discard the pages sooner, once it needs to discard something, but this is something I have to think about yet how to prove.

Related

How exactly do minor page faults get identified/resolved?

I feel very clear on what happens with a segmentation fault and a major page fault, but I'm a bit more curious on the subtleties of minor page faults, and maybe an example would be with dynamically linked libraries. Wikipedia says, for instance:
If the page is loaded in memory at the time the fault is generated, but is not marked in the memory management unit as being loaded in memory, then it is called a minor or soft page fault. The page fault handler in the operating system merely needs to make the entry for that page in the memory management unit point to the page in memory and indicate that the page is loaded in memory; it does not need to read the page into memory. This could happen if the memory is shared by different programs and the page is already brought into memory for other programs.
The line, "The page fault handler in the operating system merely needs to make the entry for that page in the memory management unit point to the page in memory" confuses me. Each process has its own page table. So if I try to map in, say, libc, what's the process that the kernel goes through to figure out that it's already been mapped? How does it know that another process is using it or that there's already a frame associated with it? Does this happen with the page cache? I was reading a bit about it here, but I think some clarification would be nice on the steps that occur in the kernel to identify and resolve a minor page fault would be helpful.
Edit: It looks like a radix tree is used to keep track? Although I'm not quite sure I'm understanding this correctly.
At first, the kernel has no idea if the page is in memory or not. Presumably, the process does have a handle open to the file however, so the kernel performs an operation through the kernel-side file descriptor entry. This involves calling into the filesystem which, of course, knows what pages of the file are resident in memory since it's the code that would load the page were one needed.

DiscardVirtualMemory and Memory Mapped files

Windows 8 added the PrefetchVirtualMemory which is a great help with avoiding hard page faults when reading a lot of sequential data with memory mapped files.
Windows 8.1/10 also added DiscardVirtualMemory which would be great as to avoid reading in pages that will be overwritten. However, when invoking DiscardVirtualMemory on a memory address owned by a Memory Mapping the thread hangs and the function call never completes.
Is DiscardVirtualMemory supported with Memory Mapped files. If so, does one need to do something special (i.e. undocumented) to make it work?

What happens to the cache on page fault?

In a processor, what happens to the cache when the operating system replaces a page, if there is not enough space to hold all running processes' pages in memory? Does it need to flush the cache on every page replacement?
Thanks in advance for your replies.
When a page is swapped in, the contents are read off the disk and into memory. Typically this is done using DMA. So the real question is, "How is the cache kept coherent with DMA?". You can either have DMA talk to the cache controller on each access, or make the OS manage the cache manually. See http://en.wikipedia.org/wiki/Direct_memory_access#Cache_coherency.
I am not 100% sure of what happens in details, but caches and virtual memory using paging
are similar: both are divided in "pages".
The same way that only one page needs to be replaced in a page fault, only one line of
the cache needs to be replaced when it occurs a miss on the cache. The cache has
several "pages" (lines), but only the problematic page will be replaced.
There are other things that I do not know if takes part on such replacements: cache size,
cache coherency - write-through/back and so on. I hope someone else can give you a more detailed answer.

Why memory-mapped files are always mapped at page boundaries?

This is my first question here; I'm not sure if it is off-topic.
While self-studying, I have found the following statement regarding Operating Systems:
Operating systems that allow memory-mapped files always require files to be mapped at page boundaries. For example, with 4-KB page, a file can be mapped in starting at virtual address 4096, but not starting at virtual address 5000.
This statement is explained in the following way:
If a file could be mapped into the middle of page, a single virtual page would
need two partial pages on disk to map it. The first page, in particular, would
be mapped onto a scratch page and also onto a file page. Handling a page
fault for it would be a complex and expensive operation, requiring copying of
data. Also, there would be no way to trap references to unused parts of pages.
For these reasons, it is avoided.
I would like to ask for help to understand this answer. Particularly, what does it mean to say that "a single virtual page would need two partial pages on disk to map it"? From what I found about memory-mapped files, virtual pages are mapped to files on disk, and not to a paging file. Is this what is meant by "partial page"?
Also, what is meant by "scratch page" here? I've tried to look up this term on books (Tanenbaum's "Modern Operating Systems" and "Structured Computer Organization") and on the Web, but haven't found it.
First of all, when reading books and documentation always try to look critically at what you see. Sometimes authors tend to use language like "there is no other way" just to promote the solution that they are describing. Other ways are always possible.
Now to the matter. Modern operating systems always have a disk location for every allocated memory page. This makes sense. Once it will be necessary to discard the page in the memory - it is already clear where to put this page if it is 'dirty' or just discard it if it is not modified. This strategy is widely accepted. Although alternative policies are possible also.
The disk location can be either paging file or memory mapped file. The most common use of the memory mapped files - executables and dlls. They are (almost) never modified. If a page with the code is not used for some time - discard it. If control will come there - reread it from the file.
In the abstract that you mentioned, they say would need two partial pages on disk to map it. The first page, in particular, would be mapped onto a scratch page. They tend to present situation like there is only one solution here. In fact, it is possible to allocate page in a paging file for such combined page and handle appropriate data copying. It is also possible not to have anything in the paging file for such page and assemble this page from files using transient page. In 99% of cases disk controller can read/write only from/to the page boundary. This means that you need to read from the first file to memory page, from the second file to the transient page. Copy data from the transient page and immediately discard it.
As you see, it is perfectly possible to combine several files in one page. There is no principle problem here. Although algorithms for handling this solution will be more complex and they will consume more CPU clocks. Reconstructing such page (if it will be discarded) will require reading from several different files. In our days 4kb is rather small quantity. Saving 2kb is not a huge gain. In my opinion, looking at the benefits and the cost I would say that benefits are not significant enough.
Virtual address pages (on every machine I've ever heard of) are aligned on page sized boundaries. This is simply because it makes the math very easy. On x86, the page size is 4096. That is exactly 12 bits. To figure out which virtual page an address is referring to, you simply shift the address to the right by 12. If you were to map a disk block (assume 4096 bytes) to an address of 5000, it would start on page #1 (5000 >> 12 == 1) and end on page #2 (9095 >> 12 == 2).
Memory mapped files work by mapping a chunk of virtual address space to the file, but the data is loaded on demand (indeed, the file could be far larger than physical memory and may not fit). When you first access the virtual address, if the data isn't there (i.e. it's not in physical memory). The processor will fault and the OS has to fetch the data. When you fetch the data, you need to fetch all of the data for the page, or else you wouldn't be able to turn off the fault. If you don't have the addresses aligned, then you'd have to bring in multiple disk blocks to fill the page. You can certainly do this, it's just messy and inefficient.

How can I force a page to fault, even if it is already in the tlb?

I'm trying to write a toy working set estimator, by keeping track of page faults over a period of time. Whenever a page is faulted in, I want to record that it was touched. The scheme breaks down when I try to keep track of accesses to already-present pages. If a page is read from or written to without triggering a fault, I have no way of tracking the access.
So then, I want to be able to cause a "lightweight" fault to occur on a page access. I've heard of some method at some point, but I didn't understand why it worked so it didn't stick in my mind. Dirty bit maybe?
You can use mprotect with PROT_NONE ("Page cannot be accessed"). Then any access to the given page will cause a fault.
The usual way to do this is to simply clear the "present" bit for the page, while leaving the page in memory and the necessary kernel data structures in place so that the kernel knows this.
However, depending on the architecture in question you may have better options - for example, on x86 there is an "Accessed" flag (bit 5 in the PTE) that is set whenever the PTE is used in a linear address translation. You can simply clear this bit whenever you like, and the hardware will set it to record that the page was touched.
Using either of these methods you will need to clear the cached translation for that page out of the TLB - on x86 you can use the INVLPG instruction.

Resources