Opened 9 years ago

Closed 9 years ago

#9019 closed Bugs (fixed)

Bug: mapped_region shouldn't create a new file mapping but reuse the one provided in file_mapping

Reported by: michal.fronczyk@… Owned by: Ion Gaztañaga
Milestone: To Be Determined Component: interprocess
Version: Boost 1.54.0 Severity: Optimization
Keywords: interprocess mapped_region file_mapping Cc:

Description

In the constructor of the mapped_region class there is the following code:

native_mapping_handle = winapi::create_file_mapping
            ( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle())
            , protection, 0, 0, 0);

followed by the following:

void *base = winapi::map_view_of_file_ex
                                 (native_mapping_handle,
                                 map_access,
                                 offset - page_offset,
                                 static_cast<std::size_t>(page_offset + size),
                                 const_cast<void*>(address));

Each invocation of the mapped_region's class constructor creates a new mapping. I think the code that creates the file mapping should be moved to the file_mapping class, so multiple mapped_regions could reuse the same file mapping. Currently, even if the same file_mapping instance is passed to the mapped_region's constructor, the file mapping isn't reused which makes creating multiple mapped regions of the same file slow.

Change History (6)

comment:1 by Ion Gaztañaga, 9 years ago

Calling CreateFileMapping in the file_mapping class is not a trivial task as the size of the file can change and the file mapping would need to be recreated on the fly. Also, it wouldn't allow the same file using copy on write as the file mapping must be opened with an special flag for that purpose, whereas another view would like to write directly to the file. Do you have any performance numbers about the overhead of not reusing the file mapping? All portable shared memory interfaces I know create new file mappings when mapping the memory so I guess the performance impact is not very high.

comment:2 by Ion Gaztañaga, 9 years ago

Just as additional information, I've found:

http://www.labri.fr/perso/betrema/winnt/manamemo.html

"To use a memory-mapped file, you start by creating a memory-mapped file object. The act of creating an MMF object has very little impact on system resources. It does not affect your process's address space, and no virtual memory is allocated for the object (other than for the internal resources that are necessary in representing the object)."

Maybe it has no big impact in system resources but it could be much slower than reusing the object.

comment:3 by michal.fronczyk@…, 9 years ago

Thanks for such a quick response. I think the problem is not about the time needed to create file mapping, but about the lack of ability to reuse already fetched pages of the file in different mapped regions. The performance problem we observed occurred in a multithreaded program. Using a profiler we discovered that the problem lies in the code where many threads were creating read-only mapped_regions of the same file using a shared instance of the file_mapping class. Different threads mapped different regions of the file, but there was a very high probability that a thread will shortly need the data region mapped previously by one of the other threads. I'm assuming that the destructor of the mapped_region class releases the mapping, so all the pages fetched during using that region are released when the region is destroyed and need to be fetched again from the disk when another region maps the same part of the file. Fetching the same parts of the file many times hurts the performance in our case.

We changed the code to create one shared read-only mapped_region that maps the whole file and we use pointer arithmetic to read different parts of the file in different threads. The performance gain we observed was significant, but I don't have the numbers now. However, this solution isn't ideal because we can't do that in the 32bit version of the app since the file is big (several GBs). We map the whole file in the 64bit version only. BTW, do you see any problems with mapping a 20GB file as a whole to the 64bit address space?

My thinking is that keeping the file_mapping instance and reusing it in multiple mapped_regions, that map small portions of the file, will allow us to reuse the fetched file pages in different mapped_regions as needed and the performance will be more or less the same as in the case of one shared mapped_region that maps the whole file. Please let me know if I'm wrong.

comment:4 by Ion Gaztañaga, 9 years ago

I think all file mappings share the same cached pages as coherency must be maintained:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366763(v=vs.85).aspx

"With one important exception, file views derived from any file mapping object that is backed by the same file are coherent or identical at a specific time. Coherency is guaranteed for views within a process and for views that are mapped by different processes."

(The exception is network files)

I don't think the issue is related to destroying the file mapping (in fact the file mapping is destroyed just after mapping the memory with MapViewOfFile), but because the mapped_region is unmapped (UnmapViewOfFile). The OS knows that no other thread is mapping those pages so it could think it's a good opportunity to release them (although if there is enough file cache, it should be still there). I'm not sure how this can be fixed as it's quite OS dependent.

Mapping the whole file shouldn't be a problem, at least in windows, as physical memory committed when the page is read (although I guess Windows will prefetch some pages).

comment:5 by michal.fronczyk@…, 9 years ago

Thanks for explanation. You're probably right - this can't be fixed in an OS independent way.

comment:6 by Ion Gaztañaga, 9 years ago

Resolution: fixed
Status: newclosed

I'm closing this as it does not seem there is a solution for it. Please reopen it if you have more information to improve the situation. Thanks for the report.

Note: See TracTickets for help on using tickets.