From 133f7a7a93543b38d9d62b16dc76ce0397143ba8 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:34:36 +0200 Subject: [PATCH 01/12] Start on memory utility --- cpp/dolfinx/common/memory.h | 48 +++++++++++++++++++++++++++++++++++++ cpp/test/CMakeLists.txt | 1 + cpp/test/common/memory.cpp | 29 ++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 cpp/dolfinx/common/memory.h create mode 100644 cpp/test/common/memory.cpp diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h new file mode 100644 index 00000000000..5edae2265fa --- /dev/null +++ b/cpp/dolfinx/common/memory.h @@ -0,0 +1,48 @@ +// Copyright (C) 2025 Paul T. Kühner +// +// This file is part of DOLFINx (https://www.fenicsproject.org) +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include + +namespace dolfinx::common +{ + +namespace impl +{ + +template +std::size_t memory(const T& obj) +{ + static_assert(false, "Memory usage not supported for provided type."); +} + +template +std::size_t memory(const std::vector& vec) +{ + using value_type = typename std::vector::value_type; + + std::size_t size_type = sizeof(vec); + std::size_t size_data = vec.capacity() * sizeof(value_type); + return size_type + size_data; +} + +} // namespace impl + +constexpr std::int64_t byte = 1; +constexpr std::int64_t kilobyte = 1024; +constexpr std::int64_t megabyte = 1'048'576; +constexpr std::int64_t gigabyte = 1'073'741'824; +constexpr std::int64_t terabyte = 1'099'511'627'776; + +template +double memory(const T& obj, std::int64_t bytes_per_unit = byte) +{ + std::size_t bytes = impl::memory(obj); + return static_cast(bytes) / bytes_per_unit; +} + +} // namespace dolfinx::common diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt index b3665a11791..f17cef50967 100644 --- a/cpp/test/CMakeLists.txt +++ b/cpp/test/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable( common/CIFailure.cpp common/sub_systems_manager.cpp common/index_map.cpp + common/memory.cpp common/sort.cpp fem/form.cpp fem/functionspace.cpp diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp new file mode 100644 index 00000000000..fae8590a3a5 --- /dev/null +++ b/cpp/test/common/memory.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2025 Paul T. Kühner +// +// This file is part of DOLFINx (https://www.fenicsproject.org) +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include + +#include +#include + +#include "dolfinx/common/memory.h" + +using namespace dolfinx::common; + +TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, + std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, + float, double, std::complex, std::complex) +{ + std::vector v; + v.reserve(10); + + std::size_t bytes = sizeof(std::vector) + 10 * sizeof(TestType); + + for (auto unit : {byte, kilobyte, megabyte, gigabyte, terabyte}) + CHECK(memory(v, unit) == Catch::Approx(static_cast(bytes) / unit)); +} From fea6098190a1993cc21ea00da60559e8177586fe Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:54:11 +0200 Subject: [PATCH 02/12] Ensure unit bytes is returned as int --- cpp/dolfinx/common/memory.h | 23 ++++++++++++++--------- cpp/test/common/memory.cpp | 12 ++++++++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index 5edae2265fa..ad3f203525e 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -6,6 +6,7 @@ #include #include +#include #include namespace dolfinx::common @@ -15,7 +16,7 @@ namespace impl { template -std::size_t memory(const T& obj) +std::size_t memory(const T& /* obj */) { static_assert(false, "Memory usage not supported for provided type."); } @@ -32,17 +33,21 @@ std::size_t memory(const std::vector& vec) } // namespace impl -constexpr std::int64_t byte = 1; -constexpr std::int64_t kilobyte = 1024; -constexpr std::int64_t megabyte = 1'048'576; -constexpr std::int64_t gigabyte = 1'073'741'824; -constexpr std::int64_t terabyte = 1'099'511'627'776; +constexpr std::integral_constant byte; +constexpr std::integral_constant kilobyte; +constexpr std::integral_constant megabyte; +constexpr std::integral_constant gigabyte; +constexpr std::integral_constant terabyte; -template -double memory(const T& obj, std::int64_t bytes_per_unit = byte) +template +std::conditional_t +memory(const T& obj, std::integral_constant bytes_per_unit) { std::size_t bytes = impl::memory(obj); - return static_cast(bytes) / bytes_per_unit; + if constexpr (bytes_per_unit == byte) + return bytes; + else + return static_cast(bytes) / bytes_per_unit.value; } } // namespace dolfinx::common diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index fae8590a3a5..f23d5d8f11d 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -24,6 +24,14 @@ TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, std::size_t bytes = sizeof(std::vector) + 10 * sizeof(TestType); - for (auto unit : {byte, kilobyte, megabyte, gigabyte, terabyte}) - CHECK(memory(v, unit) == Catch::Approx(static_cast(bytes) / unit)); + CHECK(memory(v, byte) == bytes); + + CHECK(memory(v, kilobyte) + == Catch::Approx(static_cast(bytes) / kilobyte)); + CHECK(memory(v, megabyte) + == Catch::Approx(static_cast(bytes) / megabyte)); + CHECK(memory(v, gigabyte) + == Catch::Approx(static_cast(bytes) / gigabyte)); + CHECK(memory(v, terabyte) + == Catch::Approx(static_cast(bytes) / terabyte)); } From a28d2ad0f02b5cc85775babb97bb254ff896edd7 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:59:47 +0200 Subject: [PATCH 03/12] Add header --- cpp/dolfinx/common/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/dolfinx/common/CMakeLists.txt b/cpp/dolfinx/common/CMakeLists.txt index 3a5c77044e0..8629116b4e1 100644 --- a/cpp/dolfinx/common/CMakeLists.txt +++ b/cpp/dolfinx/common/CMakeLists.txt @@ -7,6 +7,7 @@ set(HEADERS_common ${CMAKE_CURRENT_SOURCE_DIR}/sort.h ${CMAKE_CURRENT_SOURCE_DIR}/types.h ${CMAKE_CURRENT_SOURCE_DIR}/math.h + ${CMAKE_CURRENT_SOURCE_DIR}/memory.h ${CMAKE_CURRENT_SOURCE_DIR}/MPI.h ${CMAKE_CURRENT_SOURCE_DIR}/Scatterer.h ${CMAKE_CURRENT_SOURCE_DIR}/Table.h From e9a77a4606b0a4a59e172299a038a4058b69b66e Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 17:23:59 +0200 Subject: [PATCH 04/12] Ensure scalar vectors are never traversed, and add vec> support --- cpp/dolfinx/common/memory.h | 19 ++++++++++++++++--- cpp/test/common/memory.cpp | 30 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index ad3f203525e..fdecac0a866 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -4,8 +4,11 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later +#include +#include #include #include +#include #include #include @@ -19,18 +22,28 @@ template std::size_t memory(const T& /* obj */) { static_assert(false, "Memory usage not supported for provided type."); + return 0; } -template -std::size_t memory(const std::vector& vec) +template + requires std::is_arithmetic_v +std::size_t memory(const std::vector& vec) { - using value_type = typename std::vector::value_type; + using value_type = typename std::vector::value_type; std::size_t size_type = sizeof(vec); std::size_t size_data = vec.capacity() * sizeof(value_type); return size_type + size_data; } +template +std::size_t memory(const std::vector>& vec) +{ + std::size_t size = sizeof(vec); + std::ranges::for_each(vec, [&](const auto& e) { size += memory(e); }); + return size; +} + } // namespace impl constexpr std::integral_constant byte; diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index f23d5d8f11d..4b76b508b91 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -17,7 +17,8 @@ using namespace dolfinx::common; TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, - float, double, std::complex, std::complex) + float, double) +// std::complex, std::complex { std::vector v; v.reserve(10); @@ -35,3 +36,30 @@ TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, CHECK(memory(v, terabyte) == Catch::Approx(static_cast(bytes) / terabyte)); } + +TEMPLATE_TEST_CASE("memory-vector-vector", "[memory]", std::int16_t, + std::int32_t, std::int64_t, std::uint16_t, std::uint32_t, + std::uint64_t, float, double) +// std::complex, std::complex +{ + std::vector> v; + v.reserve(3); + v.template emplace_back>({{0, 1, 2}}); + v.template emplace_back>({{0, 1, 2, 3}}); + v.template emplace_back>({{0, 1, 2, 3, 4}}); + + std::size_t bytes = sizeof(std::vector>) + + 3 * sizeof(std::vector) + + (3 + 4 + 5) * sizeof(TestType); + + CHECK(memory(v, byte) == bytes); + + CHECK(memory(v, kilobyte) + == Catch::Approx(static_cast(bytes) / kilobyte)); + CHECK(memory(v, megabyte) + == Catch::Approx(static_cast(bytes) / megabyte)); + CHECK(memory(v, gigabyte) + == Catch::Approx(static_cast(bytes) / gigabyte)); + CHECK(memory(v, terabyte) + == Catch::Approx(static_cast(bytes) / terabyte)); +} From 1261ef5c566ebb461211fe2973e28393d4db2996 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 18:09:59 +0200 Subject: [PATCH 05/12] Sketch out geometry --- cpp/dolfinx/common/memory.h | 16 ++++++++++++++-- cpp/dolfinx/mesh/Geometry.h | 25 +++++++++++++++++++++++++ cpp/test/common/memory.cpp | 13 ++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index fdecac0a866..e7691379259 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -3,15 +3,22 @@ // This file is part of DOLFINx (https://www.fenicsproject.org) // // SPDX-License-Identifier: LGPL-3.0-or-later +#pragma once #include -#include #include #include -#include #include #include +// --- FWD declares --- + +namespace dolfinx::mesh +{ +template +class Geometry; +} + namespace dolfinx::common { @@ -44,6 +51,11 @@ std::size_t memory(const std::vector>& vec) return size; } +// --- FWD declares --- + +template +std::size_t memory(const dolfinx::mesh::Geometry& geometry); + } // namespace impl constexpr std::integral_constant byte; diff --git a/cpp/dolfinx/mesh/Geometry.h b/cpp/dolfinx/mesh/Geometry.h index fca6a7db46c..08160aae221 100644 --- a/cpp/dolfinx/mesh/Geometry.h +++ b/cpp/dolfinx/mesh/Geometry.h @@ -328,3 +328,28 @@ create_geometry(const Topology& topology, } } // namespace dolfinx::mesh + +namespace dolfinx::common::impl +{ + +template +std::size_t memory(const dolfinx::mesh::Geometry& geometry) +{ + + std::size_t size = 0; + size += sizeof(geometry); + + for (std::size_t i = 0; i < geometry.cmaps().size(); i++) + { + // size += memory(geometry.dofmap(i)); TODO + // size += memory(geometry.index_map(i)) TODO + // size += memory(geometry.cmaps()[i]); TODO + } + + // size += memory(geometry.x()); TODO + + // size += memory(geometry.input_global_indices()); + + return size; +}; +} // namespace dolfinx::common::impl \ No newline at end of file diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index 4b76b508b91..3cc7f35808d 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -8,10 +8,11 @@ #include #include -#include #include #include "dolfinx/common/memory.h" +#include "dolfinx/mesh/Geometry.h" +#include "dolfinx/mesh/generation.h" using namespace dolfinx::common; @@ -63,3 +64,13 @@ TEMPLATE_TEST_CASE("memory-vector-vector", "[memory]", std::int16_t, CHECK(memory(v, terabyte) == Catch::Approx(static_cast(bytes) / terabyte)); } + +TEMPLATE_TEST_CASE("memory-geometry", "[memory]", float, double) +{ + auto mesh = dolfinx::mesh::create_rectangle( + MPI_COMM_SELF, {{{0, 0}, {1, 1}}}, {1, 1}, + dolfinx::mesh::CellType::quadrilateral); + + const auto& geo = mesh.geometry(); + CHECK(memory>(geo, byte) > 0); +} \ No newline at end of file From fcb3529f6ea2115665ff2d288d01852b744a8d3a Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 19:46:27 +0200 Subject: [PATCH 06/12] Externalise forward declares --- cpp/dolfinx/common/CMakeLists.txt | 1 + cpp/dolfinx/common/memory.h | 14 ++------------ cpp/dolfinx/common/memory_fwd.h | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 cpp/dolfinx/common/memory_fwd.h diff --git a/cpp/dolfinx/common/CMakeLists.txt b/cpp/dolfinx/common/CMakeLists.txt index 8629116b4e1..b94329122d4 100644 --- a/cpp/dolfinx/common/CMakeLists.txt +++ b/cpp/dolfinx/common/CMakeLists.txt @@ -8,6 +8,7 @@ set(HEADERS_common ${CMAKE_CURRENT_SOURCE_DIR}/types.h ${CMAKE_CURRENT_SOURCE_DIR}/math.h ${CMAKE_CURRENT_SOURCE_DIR}/memory.h + ${CMAKE_CURRENT_SOURCE_DIR}/memory_fwd.h ${CMAKE_CURRENT_SOURCE_DIR}/MPI.h ${CMAKE_CURRENT_SOURCE_DIR}/Scatterer.h ${CMAKE_CURRENT_SOURCE_DIR}/Table.h diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index e7691379259..c38335c4fc7 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -3,6 +3,7 @@ // This file is part of DOLFINx (https://www.fenicsproject.org) // // SPDX-License-Identifier: LGPL-3.0-or-later + #pragma once #include @@ -11,13 +12,7 @@ #include #include -// --- FWD declares --- - -namespace dolfinx::mesh -{ -template -class Geometry; -} +#include "memory_fwd.h" namespace dolfinx::common { @@ -51,11 +46,6 @@ std::size_t memory(const std::vector>& vec) return size; } -// --- FWD declares --- - -template -std::size_t memory(const dolfinx::mesh::Geometry& geometry); - } // namespace impl constexpr std::integral_constant byte; diff --git a/cpp/dolfinx/common/memory_fwd.h b/cpp/dolfinx/common/memory_fwd.h new file mode 100644 index 00000000000..2b19fa46bb5 --- /dev/null +++ b/cpp/dolfinx/common/memory_fwd.h @@ -0,0 +1,21 @@ +// Copyright (C) 2025 Paul T. Kühner +// +// This file is part of DOLFINx (https://www.fenicsproject.org) +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +namespace dolfinx::mesh +{ +template +class Geometry; +} + +namespace dolfinx::common::impl +{ +template +std::size_t memory(const dolfinx::mesh::Geometry& geometry); +} \ No newline at end of file From 86c922e1d50c9faf73c349f45c416aa5384b9d32 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 19:52:23 +0200 Subject: [PATCH 07/12] Add array --- cpp/dolfinx/common/memory.h | 7 +++++++ cpp/test/common/memory.cpp | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index c38335c4fc7..86ffe79c7af 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -27,6 +27,13 @@ std::size_t memory(const T& /* obj */) return 0; } +template + requires std::is_arithmetic_v +std::size_t memory(const std::array& array) +{ + return sizeof(array); +} + template requires std::is_arithmetic_v std::size_t memory(const std::vector& vec) diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index 3cc7f35808d..d4f475c36f7 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -16,6 +16,27 @@ using namespace dolfinx::common; +TEMPLATE_TEST_CASE("memory-array", "[memory]", std::int16_t, std::int32_t, + std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, + float, double) +// std::complex, std::complex +{ + std::array v; + + std::size_t bytes = 10 * sizeof(TestType); + + CHECK(memory(v, byte) == bytes); + + CHECK(memory(v, kilobyte) + == Catch::Approx(static_cast(bytes) / kilobyte)); + CHECK(memory(v, megabyte) + == Catch::Approx(static_cast(bytes) / megabyte)); + CHECK(memory(v, gigabyte) + == Catch::Approx(static_cast(bytes) / gigabyte)); + CHECK(memory(v, terabyte) + == Catch::Approx(static_cast(bytes) / terabyte)); +} + TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, float, double) From 6eccbf96196776f6d26b2cb88d8da51cf8bf183e Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:06:17 +0200 Subject: [PATCH 08/12] Start on IndexMap --- cpp/dolfinx/common/IndexMap.cpp | 17 ++++++++++++++++- cpp/dolfinx/common/IndexMap.h | 7 ++++++- cpp/dolfinx/common/memory_fwd.h | 18 +++++++++++++++--- cpp/test/common/memory.cpp | 7 +++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/cpp/dolfinx/common/IndexMap.cpp b/cpp/dolfinx/common/IndexMap.cpp index ba2eb8a669a..faa4a29937b 100644 --- a/cpp/dolfinx/common/IndexMap.cpp +++ b/cpp/dolfinx/common/IndexMap.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2015-2024 Chris Richardson, Garth N. Wells, Igor Baratta, -// Joseph P. Dean and Jørgen S. Dokken +// Joseph P. Dean, Jørgen S. Dokken and Paul T. Kühner // // This file is part of DOLFINx (https://www.fenicsproject.org) // @@ -1374,3 +1374,18 @@ std::array, 2> IndexMap::rank_type(int split_type) const return {std::move(split_dest), std::move(split_src)}; } //----------------------------------------------------------------------------- + +std::size_t dolfinx::common::impl::memory(const IndexMap& im) +{ + std::size_t size = 0; + + size += sizeof(IndexMap); + size += memory(im.local_range()); + // size += memory(im.ghosts()); + // size += memory(im.owners()); + // size += memory(im.src()); + // size += memory(im.dest()); + + return size; +} +//----------------------------------------------------------------------------- diff --git a/cpp/dolfinx/common/IndexMap.h b/cpp/dolfinx/common/IndexMap.h index 0464a7752fa..a4cc43168e0 100644 --- a/cpp/dolfinx/common/IndexMap.h +++ b/cpp/dolfinx/common/IndexMap.h @@ -8,9 +8,9 @@ #include "IndexMap.h" #include "MPI.h" +#include "memory.h" #include #include -#include #include #include #include @@ -332,4 +332,9 @@ class IndexMap std::vector _dest; }; +namespace impl +{ +std::size_t memory(const IndexMap& im); +} + } // namespace dolfinx::common diff --git a/cpp/dolfinx/common/memory_fwd.h b/cpp/dolfinx/common/memory_fwd.h index 2b19fa46bb5..ac3b1a9e9a5 100644 --- a/cpp/dolfinx/common/memory_fwd.h +++ b/cpp/dolfinx/common/memory_fwd.h @@ -8,14 +8,26 @@ #include -namespace dolfinx::mesh +namespace dolfinx +{ + +namespace common +{ +class IndexMap; +} + +namespace mesh { template class Geometry; } -namespace dolfinx::common::impl +namespace common::impl { +std::size_t memory(const IndexMap& im); + template std::size_t memory(const dolfinx::mesh::Geometry& geometry); -} \ No newline at end of file +} + +} // namespace dolfinx \ No newline at end of file diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index d4f475c36f7..05253c553c1 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "dolfinx/common/memory.h" @@ -86,6 +87,12 @@ TEMPLATE_TEST_CASE("memory-vector-vector", "[memory]", std::int16_t, == Catch::Approx(static_cast(bytes) / terabyte)); } +TEST_CASE("memory-indexmap", "[memory]") +{ + auto im = IndexMap(MPI_COMM_WORLD, 10); + CHECK(memory(im, byte) > 0); +} + TEMPLATE_TEST_CASE("memory-geometry", "[memory]", float, double) { auto mesh = dolfinx::mesh::create_rectangle( From c67892ee5839b6e3b078a3c5a0a326f6e4c82351 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:23:14 +0200 Subject: [PATCH 09/12] Add span, complete IndexMap --- cpp/dolfinx/common/IndexMap.cpp | 8 ++++---- cpp/dolfinx/common/memory.h | 13 +++++++++++++ cpp/dolfinx/common/memory_fwd.h | 2 +- cpp/test/common/memory.cpp | 22 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/cpp/dolfinx/common/IndexMap.cpp b/cpp/dolfinx/common/IndexMap.cpp index faa4a29937b..5af45b44ca2 100644 --- a/cpp/dolfinx/common/IndexMap.cpp +++ b/cpp/dolfinx/common/IndexMap.cpp @@ -1381,10 +1381,10 @@ std::size_t dolfinx::common::impl::memory(const IndexMap& im) size += sizeof(IndexMap); size += memory(im.local_range()); - // size += memory(im.ghosts()); - // size += memory(im.owners()); - // size += memory(im.src()); - // size += memory(im.dest()); + size += memory(im.ghosts()); + size += memory(im.owners()); + size += memory(im.src()); + size += memory(im.dest()); return size; } diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index 86ffe79c7af..392c8efdfcb 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,18 @@ std::size_t memory(const std::vector& vec) return size_type + size_data; } +// TODO: document ownership assumption +template + requires std::is_arithmetic_v +std::size_t memory(const std::span& span) +{ + using value_type = typename std::vector::value_type; + + std::size_t size_type = sizeof(span); + std::size_t size_data = span.size() * sizeof(value_type); + return size_type + size_data; +} + template std::size_t memory(const std::vector>& vec) { diff --git a/cpp/dolfinx/common/memory_fwd.h b/cpp/dolfinx/common/memory_fwd.h index ac3b1a9e9a5..66f2739d83d 100644 --- a/cpp/dolfinx/common/memory_fwd.h +++ b/cpp/dolfinx/common/memory_fwd.h @@ -28,6 +28,6 @@ std::size_t memory(const IndexMap& im); template std::size_t memory(const dolfinx::mesh::Geometry& geometry); -} +} // namespace common::impl } // namespace dolfinx \ No newline at end of file diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index 05253c553c1..66e8be71d00 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -60,6 +60,28 @@ TEMPLATE_TEST_CASE("memory-vector", "[memory]", std::int16_t, std::int32_t, == Catch::Approx(static_cast(bytes) / terabyte)); } +TEMPLATE_TEST_CASE("memory-span", "[memory]", std::int16_t, std::int32_t, + std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, + float, double) +// std::complex, std::complex +{ + std::array v; + std::span span{v}; + + std::size_t bytes = 10 * sizeof(TestType); + + CHECK(memory(v, byte) == bytes); + + CHECK(memory(v, kilobyte) + == Catch::Approx(static_cast(bytes) / kilobyte)); + CHECK(memory(v, megabyte) + == Catch::Approx(static_cast(bytes) / megabyte)); + CHECK(memory(v, gigabyte) + == Catch::Approx(static_cast(bytes) / gigabyte)); + CHECK(memory(v, terabyte) + == Catch::Approx(static_cast(bytes) / terabyte)); +} + TEMPLATE_TEST_CASE("memory-vector-vector", "[memory]", std::int16_t, std::int32_t, std::int64_t, std::uint16_t, std::uint32_t, std::uint64_t, float, double) From 36caf322204e13be61dfc85b5b0a9e32f8eb48e5 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 21:23:51 +0200 Subject: [PATCH 10/12] Add mdspan --- cpp/dolfinx/common/memory.h | 19 +++++++++++++++++++ cpp/dolfinx/mesh/Geometry.h | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/cpp/dolfinx/common/memory.h b/cpp/dolfinx/common/memory.h index 392c8efdfcb..5f9ecedeeb7 100644 --- a/cpp/dolfinx/common/memory.h +++ b/cpp/dolfinx/common/memory.h @@ -9,11 +9,15 @@ #include #include #include +#include #include #include #include +#include + #include "memory_fwd.h" +#include "types.h" namespace dolfinx::common { @@ -66,6 +70,21 @@ std::size_t memory(const std::vector>& vec) return size; } +template > + requires std::is_arithmetic_v +std::size_t +memory(const md::mdspan& mdspan) +{ + using value_type = typename std::mdspan::value_type; + + // TODO: object size? - what happens for compile time sized mdspans? + std::size_t size_data = mdspan.size() * sizeof(value_type); + + return size_data; +} + } // namespace impl constexpr std::integral_constant byte; diff --git a/cpp/dolfinx/mesh/Geometry.h b/cpp/dolfinx/mesh/Geometry.h index 08160aae221..29ce58e2294 100644 --- a/cpp/dolfinx/mesh/Geometry.h +++ b/cpp/dolfinx/mesh/Geometry.h @@ -339,16 +339,16 @@ std::size_t memory(const dolfinx::mesh::Geometry& geometry) std::size_t size = 0; size += sizeof(geometry); + size += memory(*geometry.index_map()); + for (std::size_t i = 0; i < geometry.cmaps().size(); i++) { - // size += memory(geometry.dofmap(i)); TODO - // size += memory(geometry.index_map(i)) TODO + size += memory(geometry.dofmap(i)); // size += memory(geometry.cmaps()[i]); TODO } - // size += memory(geometry.x()); TODO - - // size += memory(geometry.input_global_indices()); + size += memory(geometry.x()); + size += memory(geometry.input_global_indices()); return size; }; From 1cc40e0f9a33094de28e84e40a67b4877bf570d4 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 21:55:50 +0200 Subject: [PATCH 11/12] Demonstrate export --- cpp/dolfinx/mesh/Geometry.h | 5 ++-- cpp/test/common/memory.cpp | 2 +- python/dolfinx/wrappers/common.cpp | 36 ++++++++++++++++++++++- python/test/unit/common/test_index_map.py | 2 ++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/cpp/dolfinx/mesh/Geometry.h b/cpp/dolfinx/mesh/Geometry.h index 29ce58e2294..0a983808a6f 100644 --- a/cpp/dolfinx/mesh/Geometry.h +++ b/cpp/dolfinx/mesh/Geometry.h @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2022 Anders Logg and Garth N. Wells +// Copyright (C) 2006-2022 Anders Logg, Garth N. Wells and Paul T. Kühner // // This file is part of DOLFINx (https://www.fenicsproject.org) // @@ -344,7 +344,8 @@ std::size_t memory(const dolfinx::mesh::Geometry& geometry) for (std::size_t i = 0; i < geometry.cmaps().size(); i++) { size += memory(geometry.dofmap(i)); - // size += memory(geometry.cmaps()[i]); TODO + // TODO: requires heavy work for basix::finite_element + // size += memory(geometry.cmaps()[i]); } size += memory(geometry.x()); diff --git a/cpp/test/common/memory.cpp b/cpp/test/common/memory.cpp index 66e8be71d00..09d3310a8d9 100644 --- a/cpp/test/common/memory.cpp +++ b/cpp/test/common/memory.cpp @@ -123,4 +123,4 @@ TEMPLATE_TEST_CASE("memory-geometry", "[memory]", float, double) const auto& geo = mesh.geometry(); CHECK(memory>(geo, byte) > 0); -} \ No newline at end of file +} diff --git a/python/dolfinx/wrappers/common.cpp b/python/dolfinx/wrappers/common.cpp index 54015f608a6..9ec0742cf0f 100644 --- a/python/dolfinx/wrappers/common.cpp +++ b/python/dolfinx/wrappers/common.cpp @@ -8,6 +8,7 @@ #include "dolfinx_wrappers/array.h" #include "dolfinx_wrappers/caster_mpi.h" #include +#include #include #include #include @@ -143,6 +144,21 @@ void common(nb::module_& m) m.attr("ufcx_signature") = dolfinx::ufcx_signature(); m.attr("version") = dolfinx::version(); + enum MemoryUnit : std::int64_t + { + byte = dolfinx::common::byte.value, + kilobyte = dolfinx::common::kilobyte.value, + megabyte = dolfinx::common::megabyte.value, + gigabyte = dolfinx::common::gigabyte.value, + terabyte = dolfinx::common::terabyte.value, + }; + nb::enum_(m, "MemoryUnit") + .value("byte", MemoryUnit::byte) + .value("kilobyte", MemoryUnit::kilobyte) + .value("megabyte", MemoryUnit::megabyte) + .value("gigabyte", MemoryUnit::gigabyte) + .value("terabyte", MemoryUnit::terabyte); + nb::enum_(m, "Reduction") .value("max", dolfinx::Table::Reduction::max) .value("min", dolfinx::Table::Reduction::min) @@ -246,7 +262,25 @@ void common(nb::module_& m) local); return dolfinx_wrappers::as_nbarray(std::move(local)); }, - nb::arg("global")); + nb::arg("global")) + .def("memory", + [](const dolfinx::common::IndexMap& self, MemoryUnit unit) + { + switch (unit) + { + case MemoryUnit::byte: + return double( + dolfinx::common::memory(self, dolfinx::common::byte)); + case MemoryUnit::kilobyte: + return dolfinx::common::memory(self, dolfinx::common::kilobyte); + case MemoryUnit::megabyte: + return dolfinx::common::memory(self, dolfinx::common::megabyte); + case MemoryUnit::gigabyte: + return dolfinx::common::memory(self, dolfinx::common::gigabyte); + case MemoryUnit::terabyte: + return dolfinx::common::memory(self, dolfinx::common::terabyte); + } + }); // dolfinx::common::Timer nb::class_>( diff --git a/python/test/unit/common/test_index_map.py b/python/test/unit/common/test_index_map.py index 5019a6a9fb9..406d9849d4f 100644 --- a/python/test/unit/common/test_index_map.py +++ b/python/test/unit/common/test_index_map.py @@ -42,6 +42,8 @@ def test_sub_index_map(): comm, map_local_size, [dest_ranks, src_ranks], map_ghosts, src_ranks ) assert map.size_global == map_local_size * comm.size + assert map.memory(dolfinx.cpp.common.MemoryUnit.byte) > 0 + assert map.memory(dolfinx.cpp.common.MemoryUnit.kilobyte) > 0 # Build list for each rank of the first (myrank + myrank % 2) local # indices From 62002bc06b9c5e6cc85342a086f71efbd303a43b Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Sun, 19 Oct 2025 22:04:31 +0200 Subject: [PATCH 12/12] Raise --- python/dolfinx/wrappers/common.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/dolfinx/wrappers/common.cpp b/python/dolfinx/wrappers/common.cpp index 9ec0742cf0f..0241b708713 100644 --- a/python/dolfinx/wrappers/common.cpp +++ b/python/dolfinx/wrappers/common.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,7 @@ void common(nb::module_& m) case MemoryUnit::terabyte: return dolfinx::common::memory(self, dolfinx::common::terabyte); } + throw std::runtime_error("Not a valid memory unit."); }); // dolfinx::common::Timer