diff --git a/include/lo2s/perf/event_reader.hpp b/include/lo2s/perf/event_reader.hpp index dd335edc..1a1a1bc1 100644 --- a/include/lo2s/perf/event_reader.hpp +++ b/include/lo2s/perf/event_reader.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -149,6 +150,22 @@ class EventReader // struct sample_id sample_id; }; + EventReader() = default; + + EventReader(EventReader&) = delete; + EventReader& operator=(EventReader&) = delete; + + EventReader(EventReader&& other) + { + std::swap(this->shmem_, other.shmem_); + } + + EventReader& operator=(EventReader&& other) + { + std::swap(this->shmem_, other.shmem_); + return *this; + } + ~EventReader() { if (lost_samples > 0) @@ -165,16 +182,17 @@ class EventReader mmap_pages_ = config().mmap_pages; - base = mmap(NULL, (mmap_pages_ + 1) * get_page_size(), PROT_READ | PROT_WRITE, MAP_SHARED, - fd, 0); - // Should not be necessary to check for nullptr, but we've seen it! - if (base == MAP_FAILED || base == nullptr) + try + { + shmem_ = SharedMemory(fd, (mmap_pages_ + 1) * get_page_size()); + } + catch (const std::system_error& e) { Log::error() << "mapping memory for recording events failed. You can try " "to decrease the buffer size with the -m flag, or try to increase " "the amount of mappable memory by increasing /proc/sys/kernel/" "perf_event_mlock_kb"; - throw_errno(); + throw; } } @@ -305,12 +323,12 @@ class EventReader private: const struct perf_event_mmap_page* header() const { - return (const struct perf_event_mmap_page*)base; + return shmem_.as(); } struct perf_event_mmap_page* header() { - return (struct perf_event_mmap_page*)base; + return shmem_.as(); } uint64_t data_head() const @@ -341,7 +359,7 @@ class EventReader { // workaround for old kernels // assert(header()->data_offset == get_page_size()); - return reinterpret_cast(base) + get_page_size(); + return shmem_.as() + get_page_size(); } public: @@ -373,7 +391,7 @@ class EventReader private: int fd_; - void* base; + SharedMemory shmem_; std::byte event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); }; diff --git a/include/lo2s/shared_memory.hpp b/include/lo2s/shared_memory.hpp new file mode 100644 index 00000000..ee307439 --- /dev/null +++ b/include/lo2s/shared_memory.hpp @@ -0,0 +1,119 @@ +/* + * This file is part of the lo2s software. + * Linux OTF2 sampling + * + * Copyright (c) 2016, + * Technische Universitaet Dresden, Germany + * + * lo2s is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * lo2s is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with lo2s. If not, see . + */ + +#pragma once + +#include + +#include + +extern "C" +{ +#include +#include +} + +namespace lo2s +{ +class SharedMemory +{ +public: + SharedMemory() : addr_(nullptr), size_(0) + { + } + + SharedMemory(SharedMemory&) = delete; + SharedMemory& operator=(SharedMemory&) = delete; + + SharedMemory(SharedMemory&& other) + { + addr_ = std::move(other.addr_); + size_ = std::move(other.size_); + + other.addr_ = nullptr; + } + + SharedMemory& operator=(SharedMemory&& other) + { + unmap(); + addr_ = std::move(other.addr_); + size_ = std::move(other.size_); + + other.addr_ = nullptr; + + return *this; + } + + SharedMemory(int fd, size_t size, size_t offset = 0, void* location = nullptr) : size_(size) + { + assert(offset % get_page_size() == 0); + + if (location == nullptr) + { + addr_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); + } + else + { + addr_ = + mmap(location, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset); + } + + if (addr_ == MAP_FAILED) + { + throw_errno(); + } + } + + template + T* as() + { + return reinterpret_cast(addr_); + } + + template + const T* as() const + { + return reinterpret_cast(addr_); + } + + ~SharedMemory() + { + unmap(); + } + + size_t size() + { + return size_; + } + +private: + void unmap() + { + if (addr_ != nullptr) + { + munmap(addr_, size_); + } + } + + void* addr_ = nullptr; + size_t size_ = 0; +}; +} // namespace lo2s