Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v7

- name: Install Doxygen
uses: ssciwr/doxygen-install@v2

- name: Configure cmake
shell: bash
run: cmake -B build -DCMAKE_BUILD_TYPE=Debug -Dndtbl_BUILD_TESTING=ON -Dndtbl_BUILD_DOCS=OFF -Dndtbl_ENABLE_MMAP=${{ matrix.mmap }}
Expand Down Expand Up @@ -95,9 +92,6 @@ jobs:
run: |
sudo apt-get install -y lcov

- name: Install Doxygen
uses: ssciwr/doxygen-install@v2

- name: Configure cmake
shell: bash
run: |
Expand Down
1 change: 1 addition & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ abstract: "Multidimensional table lookup library for C++."
authors:
- family-names: Isensee
given-names: Thomas
affiliation: "Scientific Software Center (SSC), Interdisciplinary Center for Scientific Computing (IWR), Heidelberg University, Germany"
orcid: "https://orcid.org/0000-0002-7242-4529"
keywords:
- "table lookup"
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ target_sources(ndtbl
include/ndtbl/detail/mapped_payload.hpp
)

# Compile flag for enabling mmap support
# Compile flags for enabling mmap support and related features
target_compile_definitions(ndtbl
INTERFACE
NDTBL_ENABLE_MMAP=$<BOOL:${ndtbl_ENABLE_MMAP}>
Expand Down
152 changes: 136 additions & 16 deletions include/ndtbl/detail/mapped_payload.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,29 @@
#include "ndtbl/exceptions.hpp"

#include <cstddef>

#if NDTBL_ENABLE_MMAP
#include <cerrno>
#include <cstdint>
#include <limits>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

#if NDTBL_ENABLE_MMAP || NDTBL_ENABLE_MMAP_DIAGNOSTICS
#include <cerrno>
#include <cstring>

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#endif

#if NDTBL_ENABLE_MMAP_DIAGNOSTICS
#include <cstdio>
#include <fstream>
#include <limits>
#include <sstream>
#include <vector>
#endif

#if NDTBL_ENABLE_MMAP_DIAGNOSTICS
#if !NDTBL_ENABLE_MMAP
#error "NDTBL_ENABLE_MMAP_DIAGNOSTICS requires NDTBL_ENABLE_MMAP"
Expand All @@ -59,10 +65,10 @@ namespace detail {
inline residency_info
unavailable_residency()
{
return residency_info{ false, 0, 0, 0, 0, 0.0 };
return residency_info{};
}

#if NDTBL_ENABLE_MMAP || NDTBL_ENABLE_MMAP_DIAGNOSTICS
#if NDTBL_ENABLE_MMAP

inline std::string
system_error_message(const std::string& prefix)
Expand All @@ -74,11 +80,120 @@ system_error_message(const std::string& prefix)

#if NDTBL_ENABLE_MMAP_DIAGNOSTICS

inline bool
parse_smaps_header(const std::string& line,
std::uintptr_t& start,
std::uintptr_t& end)
{
unsigned long long parsed_start = 0;
unsigned long long parsed_end = 0;
if (std::sscanf(line.c_str(), "%llx-%llx", &parsed_start, &parsed_end) != 2) {
return false;
}

start = static_cast<std::uintptr_t>(parsed_start);
end = static_cast<std::uintptr_t>(parsed_end);
return true;
}

inline std::size_t
parse_smaps_kib(const std::string& line, const char* key)
{
const std::string key_string(key);
if (line.compare(0, key_string.size(), key_string) != 0) {
return 0;
}

std::istringstream is(line.substr(key_string.size()));
std::size_t value_kib = 0;
is >> value_kib;
return value_kib;
}

inline void
query_smaps_mapping(const void* address, residency_info& info)
{
std::ifstream smaps("/proc/self/smaps");
if (!smaps.is_open()) {
return;
}

const std::uintptr_t target = reinterpret_cast<std::uintptr_t>(address);
std::uintptr_t mapping_start = 0;
std::uintptr_t mapping_end = 0;
bool in_target_mapping = false;
std::string line;

while (std::getline(smaps, line)) {
std::uintptr_t header_start = 0;
std::uintptr_t header_end = 0;
if (parse_smaps_header(line, header_start, header_end)) {
if (in_target_mapping) {
return;
}

in_target_mapping = header_start <= target && target < header_end;
if (in_target_mapping) {
mapping_start = header_start;
mapping_end = header_end;
info.smaps_available = true;
info.smaps_mapping_bytes =
static_cast<std::size_t>(mapping_end - mapping_start);
}
continue;
}

if (!in_target_mapping) {
continue;
}

const std::size_t rss_kib = parse_smaps_kib(line, "Rss:");
if (rss_kib != 0) {
info.smaps_rss_bytes = rss_kib * 1024;
continue;
}

const std::size_t pss_kib = parse_smaps_kib(line, "Pss:");
if (pss_kib != 0) {
info.smaps_pss_bytes = pss_kib * 1024;
continue;
}

const std::size_t shared_clean_kib = parse_smaps_kib(line, "Shared_Clean:");
if (shared_clean_kib != 0) {
info.smaps_shared_clean_bytes = shared_clean_kib * 1024;
continue;
}

const std::size_t shared_dirty_kib = parse_smaps_kib(line, "Shared_Dirty:");
if (shared_dirty_kib != 0) {
info.smaps_shared_dirty_bytes = shared_dirty_kib * 1024;
continue;
}

const std::size_t private_clean_kib =
parse_smaps_kib(line, "Private_Clean:");
if (private_clean_kib != 0) {
info.smaps_private_clean_bytes = private_clean_kib * 1024;
continue;
}

const std::size_t private_dirty_kib =
parse_smaps_kib(line, "Private_Dirty:");
if (private_dirty_kib != 0) {
info.smaps_private_dirty_bytes = private_dirty_kib * 1024;
continue;
}
}
}

inline residency_info
query_residency(const void* address, std::size_t length)
{
if (length == 0) {
return residency_info{ true, 0, 0, 0, 0, 0.0 };
residency_info info;
info.available = true;
return info;
}
if (address == nullptr) {
throw std::invalid_argument("cannot query residency for a null payload");
Expand Down Expand Up @@ -117,13 +232,18 @@ query_residency(const void* address, std::size_t length)
}
}

return residency_info{ true,
page_size,
total_pages,
resident_pages,
resident_pages * page_size,
static_cast<double>(resident_pages) /
static_cast<double>(total_pages) };
residency_info info;
info.available = true;
info.page_size = page_size;
info.total_pages = total_pages;
info.resident_pages = resident_pages;
info.resident_bytes = resident_pages * page_size;
info.resident_fraction =
static_cast<double>(resident_pages) / static_cast<double>(total_pages);

query_smaps_mapping(address, info);

return info;
}

#else
Expand Down
21 changes: 15 additions & 6 deletions include/ndtbl/diagnostics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ namespace ndtbl {
*/
struct residency_info
{
bool available;
std::size_t page_size;
std::size_t total_pages;
std::size_t resident_pages;
std::size_t resident_bytes;
double resident_fraction;
bool available = false;
std::size_t page_size = 0;
std::size_t total_pages = 0;
std::size_t resident_pages = 0;
std::size_t resident_bytes = 0;
double resident_fraction = 0.0;

bool smaps_available = false;
std::size_t smaps_mapping_bytes = 0;
std::size_t smaps_rss_bytes = 0;
std::size_t smaps_pss_bytes = 0;
std::size_t smaps_shared_clean_bytes = 0;
std::size_t smaps_shared_dirty_bytes = 0;
std::size_t smaps_private_clean_bytes = 0;
std::size_t smaps_private_dirty_bytes = 0;
};

} // namespace ndtbl