Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 3 additions & 4 deletions memInfo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ set(CMAKE_BUILD_TYPE "RelWithDebInfo")
if (NOT ${Kokkos_DIR} STREQUAL "")
add_subdirectory(${Kokkos_DIR})
include_directories(${Kokkos_INCLUDE_DIRS_RET})
else()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/modules")
find_package(Kokkos REQUIRED)
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/modules")

include(CTest)

find_package(Kokkos REQUIRED)

add_subdirectory(src)
add_subdirectory(unit_test)

36 changes: 19 additions & 17 deletions memInfo/src/cexa_MemInfo.hpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
#ifndef KOKKOS_MEMINFO_HPP
#define KOKKOS_MEMINFO_HPP

#include <cstddef>
#include <Kokkos_Core.hpp>
#include <sstream>
#include <fstream>

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/sysinfo.h>
#endif

#include <Kokkos_Core.hpp>

namespace Kokkos {
namespace Experimental {

namespace {
constexpr int OVERCOMMIT_DISABLED = 2;
constexpr char COMMITTED_AS_KEY[] = "Committed_AS:";
constexpr char COMMIT_LIMIT_KEY[] = "CommitLimit:";
constexpr char MEMINFO_PATH[] = "/proc/meminfo";
constexpr char OVERCOMMIT_PATH[] = "/proc/sys/vm/overcommit_memory";
constexpr char MEM_FREE_KEY[] = "MemFree:";
constexpr char MEM_TOTAL_KEY[] = "MemTotal:";
constexpr char COMMITTED_AS_KEY[] = "Committed_AS:";
constexpr char COMMIT_LIMIT_KEY[] = "CommitLimit:";
constexpr char MEMINFO_PATH[] = "/proc/meminfo";
constexpr char OVERCOMMIT_PATH[] = "/proc/sys/vm/overcommit_memory";
}

// On some systems, overcommit is disabled, and the kernel does not allow
// memory allocation beyond the commit limit. This means that allocations
// that touch only a small amount of memory are still counted at their full size.
// man proc_sys_vm
bool is_overcommit_limit_set() {
bool is_overcommit_disabled() {
std::ifstream overcommit_file(OVERCOMMIT_PATH);
int overcommit_value = 0;

Expand Down Expand Up @@ -72,17 +76,13 @@ void MemGetInfo<Kokkos::HostSpace>(size_t* free, size_t* total) {
*total = statex.ullTotalPhys;
}
#else
static bool overcommit_limit = is_overcommit_limit_set();
if (overcommit_limit) {
static bool overcommit_disabled = is_overcommit_disabled();
if (overcommit_disabled) {
*total = get_meminfo_value(COMMIT_LIMIT_KEY);
*free = *total - get_meminfo_value(COMMITTED_AS_KEY);
return;
}
struct sysinfo info;
if (sysinfo(&info) == 0) {
*free = info.freeram * info.mem_unit;
*total = info.totalram * info.mem_unit;
return;
} else {
*total = get_meminfo_value(MEM_TOTAL_KEY);
*free = get_meminfo_value(MEM_FREE_KEY);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A return statement could be added.

#endif
}
Expand Down Expand Up @@ -127,3 +127,5 @@ void MemGetInfo<Kokkos::SYCLDeviceUSMSpace>(size_t* free, size_t* total) {

} // namespace Experimental
} // namespace Kokkos

#endif // KOKKOS_MEMINFO_HPP
7 changes: 4 additions & 3 deletions memInfo/unit_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ include(FetchContent)

FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
DOWNLOAD_EXTRACT_TIMESTAMP true
)
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 6910c9d9165801d8827d628cb72eb7ea9dd538c5
DOWNLOAD_EXTRACT_TIMESTAMP true)

FetchContent_MakeAvailable(googletest)

enable_testing()
Expand Down
88 changes: 34 additions & 54 deletions memInfo/unit_test/TestMemInfo.cpp
Original file line number Diff line number Diff line change
@@ -1,81 +1,61 @@
#include <Kokkos_Core.hpp>
#include <cexa_MemInfo.hpp>
#include <gtest/gtest.h>

#include <cstddef>
#include <type_traits>

#include <Kokkos_Core.hpp>
#include <gtest/gtest.h>

template <typename MemorySpace = void>
template <typename Space = Kokkos::DefaultExecutionSpace>
void testMemInfo() {
size_t step1_total = 0ul;
size_t step2_total = 0ul;
size_t step2_free = 0ul;
size_t step1_free = 0ul;
std::size_t step1_total = 0ul;
std::size_t step2_total = 0ul;
std::size_t step1_free = 0ul;
std::size_t step2_free = 0ul;

if constexpr (std::is_same<MemorySpace, void>::value) {
Kokkos::Experimental::MemGetInfo(&step1_free, &step1_total);
} else {
Kokkos::Experimental::MemGetInfo<MemorySpace>(&step1_free, &step1_total);
}
{
// Allocate 128 MiB of memory
Kokkos::View<double**, MemorySpace> data("data test", 128, 1024*1024);
if constexpr (std::is_same<MemorySpace, void>::value) {
Kokkos::Experimental::MemGetInfo(&step2_free, &step2_total);
} else {
Kokkos::Experimental::MemGetInfo<MemorySpace>(&step2_free, &step2_total);
}
}
Kokkos::Experimental::MemGetInfo<Space>(&step1_free, &step1_total);
// Allocate 64 MiB of memory
Kokkos::View<double**, typename Space::memory_space> data("data test", 1024, 8192);
Kokkos::fence();
Kokkos::Experimental::MemGetInfo<Space>(&step2_free, &step2_total);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add these tests also here:

EXPECT_GT(step2_free, 0);
EXPECT_GT(step2_total, 0);

You had these tests earlier. You have removed these tests, while creating the macro TEST_SPACE.

// Same total memory before and after aloccation
EXPECT_EQ(step1_total, step2_total);
// Check that free memory is less after allocation
EXPECT_LT(step2_free, step1_free);
}

Copy link
Member

@science-enthusiast science-enthusiast Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is repeating logic in the tests. The tests are one of the two types for different execution spaces:

Kokkos::initialize();
testMemInfo<Space_i>(); // One or two spaces
Kokkos::finalize();

size_t free = 0;
size_t total = 0;
Kokkos::Experimental::MemGetInfo<SOME_SPACE>(&free, &total);
EXPECT_GT(free, 0);
EXPECT_GT(total, 0);

But it is ok if you don't refactor.

TEST(MemInfo, HostSpace) {
Kokkos::initialize();
testMemInfo<Kokkos::HostSpace>();
Kokkos::finalize();
}
TEST(MemInfo, HostSpaceUninitialized) {
size_t free = 0;
size_t total = 0;
Kokkos::Experimental::MemGetInfo<Kokkos::HostSpace>(&free, &total);
EXPECT_GT(free, 0);
EXPECT_GT(total, 0);
}
#define TEST_SPACE(Space) \
TEST(MemInfo, Space) { \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are calling the function testMemInfo. When an error happens inside it, it will be difficult to figure out which invocation it is from. Inserting a SCOPED_TRACE could help.

testMemInfo<Kokkos::Space>(); \
}

TEST(MemInfo, DefaultSpace) {
Kokkos::initialize();
testMemInfo<>();
Kokkos::finalize();
}
TEST(MemInfo, DefaultSpaceUninitialized) {
size_t free = 0;
size_t total = 0;
Kokkos::Experimental::MemGetInfo(&free, &total);
EXPECT_GT(free, 0);
EXPECT_GT(total, 0);
}

TEST_SPACE(HostSpace)

#if defined(KOKKOS_ENABLE_CUDA)
TEST(MemInfo, CudaSpace) {
Kokkos::initialize();
testMemInfo<Kokkos::CudaSpace>();
testMemInfo<Kokkos::SharedSpace>();
Kokkos::finalize();
}
TEST_SPACE(CudaSpace)
TEST_SPACE(SharedSpace)
#endif

#if defined(KOKKOS_ENABLE_HIP)
TEST(MemInfo, HIPSpace) {
Kokkos::initialize();
testMemInfo<Kokkos::HIPSpace>();
testMemInfo<Kokkos::SharedSpace>();
Kokkos::finalize();
}
TEST_SPACE(HIPSpace)
TEST_SPACE(SharedSpace)
#endif

#if defined(KOKKOS_ENABLE_SYCL)
TEST_SPACE(SYCLDeviceUSMSpace)
TEST_SPACE(SharedSpace)
#endif

int main(int argc, char *argv[]) {
Kokkos::initialize(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
Kokkos::finalize();
return result;
}

#undef TEST_SPACE