osrm-backend/test/t/util/test_memory_mapping.cpp
Patrick Niklaus 8511256779 Squashed 'third_party/libosmium/' content from commit 2282c84
git-subtree-dir: third_party/libosmium
git-subtree-split: 2282c8450bae55839372a2002db7ca754530d2fc
2016-03-01 17:56:55 +01:00

420 lines
11 KiB
C++

#include "catch.hpp"
#include <sys/types.h>
#include <limits>
#include <osmium/util/file.hpp>
#include <osmium/util/memory_mapping.hpp>
#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32))
#include "win_mkstemp.hpp"
#endif
static const size_t huge = std::numeric_limits<size_t>::max();
TEST_CASE("anonymous mapping") {
SECTION("simple memory mapping should work") {
osmium::util::MemoryMapping mapping(1000, osmium::util::MemoryMapping::mapping_mode::write_private);
REQUIRE(mapping.get_addr() != nullptr);
REQUIRE(mapping.size() >= 1000);
volatile int* addr = mapping.get_addr<int>();
REQUIRE(mapping.writable());
*addr = 42;
REQUIRE(*addr == 42);
REQUIRE(!!mapping);
mapping.unmap();
REQUIRE(!mapping);
mapping.unmap(); // second unmap is okay
}
SECTION("memory mapping of zero length should work") {
osmium::util::MemoryMapping mapping(0, osmium::util::MemoryMapping::mapping_mode::write_private);
REQUIRE(mapping.get_addr() != nullptr);
REQUIRE(mapping.size() == osmium::util::get_pagesize());
REQUIRE(!!mapping);
mapping.unmap();
REQUIRE(!mapping);
}
SECTION("moving a memory mapping should work") {
osmium::util::MemoryMapping mapping1(1000, osmium::util::MemoryMapping::mapping_mode::write_private);
int* addr1 = mapping1.get_addr<int>();
*addr1 = 42;
REQUIRE(!!mapping1);
osmium::util::MemoryMapping mapping2(std::move(mapping1));
REQUIRE(!!mapping2);
REQUIRE(!mapping1);
mapping1.unmap();
int* addr2 = mapping2.get_addr<int>();
REQUIRE(*addr2 == 42);
mapping2.unmap();
REQUIRE(!mapping2);
}
SECTION("move assignment should work") {
osmium::util::MemoryMapping mapping1(1000, osmium::util::MemoryMapping::mapping_mode::write_private);
osmium::util::MemoryMapping mapping2(1000, osmium::util::MemoryMapping::mapping_mode::write_private);
REQUIRE(!!mapping1);
REQUIRE(!!mapping2);
int* addr1 = mapping1.get_addr<int>();
*addr1 = 42;
mapping2 = std::move(mapping1);
REQUIRE(!!mapping2);
REQUIRE(!mapping1);
int* addr2 = mapping2.get_addr<int>();
REQUIRE(*addr2 == 42);
mapping2.unmap();
REQUIRE(!mapping2);
}
#ifdef __linux__
SECTION("remapping to larger size should work") {
osmium::util::MemoryMapping mapping(1000, osmium::util::MemoryMapping::mapping_mode::write_private);
REQUIRE(mapping.size() >= 1000);
size_t size1 = mapping.size();
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(8000);
REQUIRE(mapping.size() > size1);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
}
SECTION("remapping to smaller size should work") {
osmium::util::MemoryMapping mapping(8000, osmium::util::MemoryMapping::mapping_mode::write_private);
REQUIRE(mapping.size() >= 1000);
size_t size1 = mapping.size();
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(500);
REQUIRE(mapping.size() < size1);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
}
#endif
}
TEST_CASE("file-based mapping") {
SECTION("writing to a mapped file should work") {
char filename[] = "test_mmap_write_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
osmium::util::resize_file(fd, 100);
{
osmium::util::MemoryMapping mapping(100, osmium::util::MemoryMapping::mapping_mode::write_shared, fd);
REQUIRE(mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
*mapping.get_addr<int>() = 1234;
mapping.unmap();
}
REQUIRE(osmium::util::file_size(fd) == 100);
{
osmium::util::MemoryMapping mapping(100, osmium::util::MemoryMapping::mapping_mode::readonly, fd);
REQUIRE(!mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
REQUIRE(*mapping.get_addr<int>() == 1234);
mapping.unmap();
}
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
SECTION("writing to a privately mapped file should work") {
char filename[] = "test_mmap_write_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
osmium::util::resize_file(fd, 100);
{
osmium::util::MemoryMapping mapping(100, osmium::util::MemoryMapping::mapping_mode::write_private, fd);
REQUIRE(mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
*mapping.get_addr<int>() = 1234;
mapping.unmap();
}
REQUIRE(osmium::util::file_size(fd) == 100);
{
osmium::util::MemoryMapping mapping(100, osmium::util::MemoryMapping::mapping_mode::readonly, fd);
REQUIRE(!mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
REQUIRE(*mapping.get_addr<int>() == 0); // should not see the value set above
mapping.unmap();
}
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
SECTION("remapping to larger size should work") {
char filename[] = "test_mmap_grow_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
osmium::util::MemoryMapping mapping(100, osmium::util::MemoryMapping::mapping_mode::write_shared, fd);
REQUIRE(mapping.size() >= 100);
size_t size1 = mapping.size();
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(8000);
REQUIRE(mapping.size() >= 8000);
REQUIRE(mapping.size() > size1);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
mapping.unmap();
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
SECTION("remapping to smaller size should work") {
char filename[] = "test_mmap_shrink_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
{
osmium::util::MemoryMapping mapping(8000, osmium::util::MemoryMapping::mapping_mode::write_shared, fd);
REQUIRE(mapping.size() >= 8000);
size_t size1 = mapping.size();
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(50);
REQUIRE(mapping.size() >= 50);
REQUIRE(mapping.size() < size1);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
}
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
}
TEST_CASE("typed anonymous mapping") {
SECTION("simple memory mapping should work") {
osmium::util::TypedMemoryMapping<uint32_t> mapping(1000);
volatile uint32_t* addr = mapping.begin();
REQUIRE(mapping.writable());
*addr = 42;
REQUIRE(*addr == 42);
REQUIRE(!!mapping);
mapping.unmap();
REQUIRE(!mapping);
mapping.unmap(); // second unmap is okay
}
SECTION("moving a memory mapping should work") {
osmium::util::TypedMemoryMapping<uint32_t> mapping1(1000);
uint32_t* addr1 = mapping1.begin();
*addr1 = 42;
REQUIRE(!!mapping1);
osmium::util::TypedMemoryMapping<uint32_t> mapping2(std::move(mapping1));
REQUIRE(!!mapping2);
REQUIRE(!mapping1);
mapping1.unmap();
auto addr2 = mapping2.begin();
REQUIRE(*addr2 == 42);
mapping2.unmap();
REQUIRE(!mapping2);
}
SECTION("move assignment should work") {
osmium::util::TypedMemoryMapping<uint32_t> mapping1(1000);
osmium::util::TypedMemoryMapping<uint32_t> mapping2(1000);
REQUIRE(!!mapping1);
REQUIRE(!!mapping2);
auto addr1 = mapping1.begin();
*addr1 = 42;
mapping2 = std::move(mapping1);
REQUIRE(!!mapping2);
REQUIRE(!mapping1);
auto addr2 = mapping2.begin();
REQUIRE(*addr2 == 42);
mapping2.unmap();
REQUIRE(!mapping2);
}
#ifdef __linux__
SECTION("remapping to larger size should work") {
osmium::util::TypedMemoryMapping<uint32_t> mapping(1000);
REQUIRE(mapping.size() >= 1000);
auto addr1 = mapping.begin();
*addr1 = 42;
mapping.resize(8000);
auto addr2 = mapping.begin();
REQUIRE(*addr2 == 42);
}
SECTION("remapping to smaller size should work") {
osmium::util::TypedMemoryMapping<uint32_t> mapping(8000);
REQUIRE(mapping.size() >= 8000);
auto addr1 = mapping.begin();
*addr1 = 42;
mapping.resize(500);
auto addr2 = mapping.begin();
REQUIRE(*addr2 == 42);
}
#endif
}
TEST_CASE("typed file-based mapping") {
SECTION("writing to a mapped file should work") {
char filename[] = "test_mmap_file_size_XXXXXX";
const int fd = mkstemp(filename);
REQUIRE(fd > 0);
osmium::util::resize_file(fd, 100);
{
osmium::util::TypedMemoryMapping<uint32_t> mapping(100, osmium::util::MemoryMapping::mapping_mode::write_shared, fd);
REQUIRE(mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
*mapping.begin() = 1234;
mapping.unmap();
}
{
osmium::util::TypedMemoryMapping<uint32_t> mapping(100, osmium::util::MemoryMapping::mapping_mode::readonly, fd);
REQUIRE(!mapping.writable());
REQUIRE(!!mapping);
REQUIRE(mapping.size() >= 100);
REQUIRE(*mapping.begin() == 1234);
mapping.unmap();
}
REQUIRE(0 == close(fd));
REQUIRE(0 == unlink(filename));
}
}
TEST_CASE("anonymous memory mapping class") {
SECTION("simple memory mapping should work") {
osmium::util::AnonymousMemoryMapping mapping(1000);
REQUIRE(mapping.get_addr() != nullptr);
volatile int* addr = mapping.get_addr<int>();
REQUIRE(mapping.writable());
*addr = 42;
REQUIRE(*addr == 42);
REQUIRE(!!mapping);
mapping.unmap();
REQUIRE(!mapping);
mapping.unmap(); // second unmap is okay
}
#ifdef __linux__
SECTION("remapping to larger size should work") {
osmium::util::AnonymousMemoryMapping mapping(1000);
REQUIRE(mapping.size() >= 1000);
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(2000);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
}
SECTION("remapping to smaller size should work") {
osmium::util::AnonymousMemoryMapping mapping(2000);
REQUIRE(mapping.size() >= 2000);
int* addr1 = mapping.get_addr<int>();
*addr1 = 42;
mapping.resize(500);
int* addr2 = mapping.get_addr<int>();
REQUIRE(*addr2 == 42);
}
#endif
}