mem: mmap the backing store with MAP_NORESERVE

This patch ensures we can run simulations with very large simulated
memories (at least 64 TB based on some quick runs on a Linux
workstation). In essence this allows us to efficiently deal with
sparse address maps without having to implement a redirection layer in
the backing store.

This opens up for run-time errors if we eventually exhausts the hosts
memory and swap space, but this should hopefully never happen.
This commit is contained in:
Andreas Hansson 2015-02-16 03:33:47 -05:00
parent 57758ca685
commit e17328a227
4 changed files with 39 additions and 4 deletions

View file

@ -56,12 +56,29 @@
#include "mem/abstract_mem.hh" #include "mem/abstract_mem.hh"
#include "mem/physical.hh" #include "mem/physical.hh"
/**
* On Linux, MAP_NORESERVE allow us to simulate a very large memory
* without committing to actually providing the swap space on the
* host. On OSX the MAP_NORESERVE flag does not exist, so simply make
* it 0.
*/
#if defined(__APPLE__)
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
#endif
#endif
using namespace std; using namespace std;
PhysicalMemory::PhysicalMemory(const string& _name, PhysicalMemory::PhysicalMemory(const string& _name,
const vector<AbstractMemory*>& _memories) : const vector<AbstractMemory*>& _memories,
_name(_name), rangeCache(addrMap.end()), size(0) bool mmap_using_noreserve) :
_name(_name), rangeCache(addrMap.end()), size(0),
mmapUsingNoReserve(mmap_using_noreserve)
{ {
if (mmap_using_noreserve)
warn("Not reserving swap space. May cause SIGSEGV on actual usage\n");
// add the memories from the system to the address map as // add the memories from the system to the address map as
// appropriate // appropriate
for (const auto& m : _memories) { for (const auto& m : _memories) {
@ -148,6 +165,13 @@ PhysicalMemory::createBackingStore(AddrRange range,
DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n", DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n",
range.to_string(), range.size()); range.to_string(), range.size());
int map_flags = MAP_ANON | MAP_PRIVATE; int map_flags = MAP_ANON | MAP_PRIVATE;
// to be able to simulate very large memories, the user can opt to
// pass noreserve to mmap
if (mmapUsingNoReserve) {
map_flags |= MAP_NORESERVE;
}
uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(), uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(),
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
map_flags, -1, 0); map_flags, -1, 0);

View file

@ -85,6 +85,9 @@ class PhysicalMemory : public Serializable
// The total memory size // The total memory size
uint64_t size; uint64_t size;
// Let the user choose if we reserve swap space when calling mmap
const bool mmapUsingNoReserve;
// The physical memory used to provide the memory in the simulated // The physical memory used to provide the memory in the simulated
// system // system
std::vector<std::pair<AddrRange, uint8_t*>> backingStore; std::vector<std::pair<AddrRange, uint8_t*>> backingStore;
@ -112,7 +115,8 @@ class PhysicalMemory : public Serializable
* Create a physical memory object, wrapping a number of memories. * Create a physical memory object, wrapping a number of memories.
*/ */
PhysicalMemory(const std::string& _name, PhysicalMemory(const std::string& _name,
const std::vector<AbstractMemory*>& _memories); const std::vector<AbstractMemory*>& _memories,
bool mmap_using_noreserve);
/** /**
* Unmap all the backing store we have used. * Unmap all the backing store we have used.

View file

@ -59,6 +59,13 @@ class System(MemObject):
"All memories in the system") "All memories in the system")
mem_mode = Param.MemoryMode('atomic', "The mode the memory system is in") mem_mode = Param.MemoryMode('atomic', "The mode the memory system is in")
# When reserving memory on the host, we have the option of
# reserving swap space or not (by passing MAP_NORESERVE to
# mmap). By enabling this flag, we accomodate cases where a large
# (but sparse) memory is simulated.
mmap_using_noreserve = Param.Bool(False, "mmap the backing store " \
"without reserving swap")
# The memory ranges are to be populated when creating the system # The memory ranges are to be populated when creating the system
# such that these can be passed from the I/O subsystem through an # such that these can be passed from the I/O subsystem through an
# I/O bridge or cache # I/O bridge or cache

View file

@ -88,7 +88,7 @@ System::System(Params *p)
loadAddrMask(p->load_addr_mask), loadAddrMask(p->load_addr_mask),
loadAddrOffset(p->load_offset), loadAddrOffset(p->load_offset),
nextPID(0), nextPID(0),
physmem(name() + ".physmem", p->memories), physmem(name() + ".physmem", p->memories, p->mmap_using_noreserve),
memoryMode(p->mem_mode), memoryMode(p->mem_mode),
_cacheLineSize(p->cache_line_size), _cacheLineSize(p->cache_line_size),
workItemsBegin(0), workItemsBegin(0),