Skip to content

Commit 9affcac

Browse files
author
Vakho Tsulaia
committed
single_store: added support for handling multiple contexts on the host
1 parent 9ac3f7e commit 9affcac

File tree

6 files changed

+141
-24
lines changed

6 files changed

+141
-24
lines changed

core/include/detray/core/detail/single_store.hpp

+69-17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <vecmem/memory/memory_resource.hpp>
1919

2020
// System include(s)
21+
#include <iostream>
2122
#include <type_traits>
2223

2324
namespace detray {
@@ -65,7 +66,9 @@ class single_store {
6566
template <typename allocator_t = vecmem::memory_resource>
6667
requires(std::derived_from<allocator_t, std::pmr::memory_resource>)
6768
DETRAY_HOST explicit single_store(allocator_t &resource)
68-
: m_container(&resource) {}
69+
: m_container(&resource) {
70+
m_context_size = m_container.size();
71+
}
6972

7073
/// Copy Construct with a specific memory resource @param resource
7174
/// (host-side only)
@@ -74,12 +77,16 @@ class single_store {
7477
requires(std::is_same_v<C, std::vector<T>>
7578
&&std::derived_from<allocator_t, std::pmr::memory_resource>)
7679
DETRAY_HOST single_store(allocator_t &resource, const T &arg)
77-
: m_container(&resource, arg) {}
80+
: m_container(&resource, arg) {
81+
m_context_size = m_container.size();
82+
}
7883

7984
/// Construct from the container @param view . Mainly used device-side.
8085
template <concepts::device_view container_view_t>
8186
DETRAY_HOST_DEVICE explicit single_store(container_view_t &view)
82-
: m_container(view) {}
87+
: m_container(view) {
88+
m_context_size = m_container.size();
89+
}
8390

8491
/// @returns a pointer to the underlying container - const
8592
DETRAY_HOST_DEVICE
@@ -95,26 +102,29 @@ class single_store {
95102
DETRAY_HOST_DEVICE
96103
constexpr auto size(const context_type & /*ctx*/ = {}) const noexcept
97104
-> dindex {
98-
return static_cast<dindex>(m_container.size());
105+
return static_cast<dindex>(m_context_size);
99106
}
100107

101108
/// @returns true if the underlying container is empty
102109
DETRAY_HOST_DEVICE
103-
constexpr auto empty(const context_type & /*ctx*/ = {}) const noexcept
104-
-> bool {
105-
return m_container.empty();
110+
constexpr auto empty(const context_type &ctx = {}) const noexcept -> bool {
111+
if (ctx.get() == 0u) {
112+
return m_container.empty();
113+
} else {
114+
return ctx.get() > m_n_contexts;
115+
}
106116
}
107117

108118
/// @returns the collections iterator at the start position
109119
DETRAY_HOST_DEVICE
110-
constexpr auto begin(const context_type & /*ctx*/ = {}) const {
111-
return m_container.begin();
120+
constexpr auto begin(const context_type &ctx = {}) const {
121+
return m_container.begin() + ctx.get() * m_context_size;
112122
}
113123

114124
/// @returns the collections iterator sentinel
115125
DETRAY_HOST_DEVICE
116-
constexpr auto end(const context_type & /*ctx*/ = {}) const {
117-
return m_container.end();
126+
constexpr auto end(const context_type &ctx = {}) const {
127+
return m_container.begin() + (ctx.get() + 1) * m_context_size;
118128
}
119129

120130
/// @returns access to the underlying container - const
@@ -135,33 +145,34 @@ class single_store {
135145
constexpr auto at(const dindex i,
136146
const context_type &ctx = {}) const noexcept
137147
-> const T & {
138-
[[maybe_unused]] context_type tmp_ctx{
139-
ctx}; // Temporary measure to avoid warnings
140-
return m_container.at(i);
148+
return m_container.at(ctx.get() * m_context_size + i);
141149
}
142150

143151
/// @returns context based access to an element (also range checked)
144152
DETRAY_HOST_DEVICE
145153
constexpr auto at(const dindex i, const context_type &ctx = {}) noexcept
146154
-> T & {
147-
[[maybe_unused]] context_type tmp_ctx{
148-
ctx}; // Temporary measure to avoid warnings
149-
return m_container.at(i);
155+
return m_container.at(ctx.get() * m_context_size + i);
150156
}
151157

152158
/// Removes and destructs all elements in the container.
153159
DETRAY_HOST void clear(const context_type & /*ctx*/) {
160+
assert(m_n_contexts == 0u);
154161
m_container.clear();
162+
m_context_size = 0;
155163
}
156164

157165
/// Reserve memory of size @param n for a given geometry context
158166
DETRAY_HOST void reserve(std::size_t n, const context_type & /*ctx*/) {
167+
assert(m_n_contexts == 0u);
159168
m_container.reserve(n);
160169
}
161170

162171
/// Resize the underlying container to @param n for a given geometry context
163172
DETRAY_HOST void resize(std::size_t n, const context_type & /*ctx*/) {
173+
assert(m_n_contexts == 0u);
164174
m_container.resize(n);
175+
m_context_size = m_container.size();
165176
}
166177

167178
/// Add a new element to the collection - copy
@@ -175,7 +186,9 @@ class single_store {
175186
DETRAY_HOST constexpr auto push_back(
176187
const U &arg, const context_type & /*ctx*/ = {}) noexcept(false)
177188
-> void {
189+
assert(m_n_contexts == 0u);
178190
m_container.push_back(arg);
191+
m_context_size = m_container.size();
179192
}
180193

181194
/// Add a new element to the collection - move
@@ -188,7 +201,9 @@ class single_store {
188201
template <typename U>
189202
DETRAY_HOST constexpr auto push_back(
190203
U &&arg, const context_type & /*ctx*/ = {}) noexcept(false) -> void {
204+
assert(m_n_contexts == 0u);
191205
m_container.push_back(std::forward<U>(arg));
206+
m_context_size = m_container.size();
192207
}
193208

194209
/// Add a new element to the collection in place
@@ -201,6 +216,8 @@ class single_store {
201216
template <typename... Args>
202217
DETRAY_HOST constexpr decltype(auto) emplace_back(
203218
const context_type & /*ctx*/ = {}, Args &&... args) noexcept(false) {
219+
assert(m_n_contexts == 0u);
220+
m_context_size++;
204221
return m_container.emplace_back(std::forward<Args>(args)...);
205222
}
206223

@@ -215,8 +232,10 @@ class single_store {
215232
DETRAY_HOST auto insert(container_t<U> &new_data,
216233
const context_type & /*ctx*/ = {}) noexcept(false)
217234
-> void {
235+
assert(m_n_contexts == 0u);
218236
m_container.reserve(m_container.size() + new_data.size());
219237
m_container.insert(m_container.end(), new_data.begin(), new_data.end());
238+
m_context_size = m_container.size();
220239
}
221240

222241
/// Insert another collection - move
@@ -230,30 +249,61 @@ class single_store {
230249
DETRAY_HOST auto insert(container_t<U> &&new_data,
231250
const context_type & /*ctx*/ = {}) noexcept(false)
232251
-> void {
252+
assert(m_n_contexts == 0u);
233253
m_container.reserve(m_container.size() + new_data.size());
234254
m_container.insert(m_container.end(),
235255
std::make_move_iterator(new_data.begin()),
236256
std::make_move_iterator(new_data.end()));
257+
m_context_size = m_container.size();
258+
}
259+
260+
template <typename U>
261+
DETRAY_HOST auto add_context(container_t<U> &context_data) noexcept(false)
262+
-> void {
263+
// Cannot add context data to an empty store
264+
if (m_context_size == 0u) {
265+
std::cout << "WARNING: Single Store. Cannot add a context to an "
266+
"empty store ";
267+
return;
268+
}
269+
// Wrong size of the context_data vector
270+
if (context_data.size() % m_context_size != 0u) {
271+
std::cout << "WARNING: Single Store. Wrong size of the inserted "
272+
"vector. Must be multiple of the context size";
273+
return;
274+
}
275+
// Drop previous contexts if any
276+
if (m_container.size() > m_context_size)
277+
m_container.resize(m_context_size);
278+
// Add new contexts
279+
m_n_contexts = context_data.size() / m_context_size;
280+
m_container.reserve(m_container.size() + context_data.size());
281+
m_container.insert(m_container.end(), context_data.begin(),
282+
context_data.end());
237283
}
238284

239285
/// Append another store to the current one
240286
///
241287
/// @param other The other container
242288
///
243289
/// @note in general can throw an exception
290+
/// ? Remove the ctx argument ?
244291
DETRAY_HOST void append(single_store &other,
245292
const context_type &ctx = {}) noexcept(false) {
246293
insert(other.m_container, ctx);
294+
m_context_size = m_container.size();
247295
}
248296

249297
/// Append another store to the current one - move
250298
///
251299
/// @param other The other container
252300
///
253301
/// @note in general can throw an exception
302+
/// ? Remove the ctx argument ?
254303
DETRAY_HOST void append(single_store &&other,
255304
const context_type &ctx = {}) noexcept(false) {
256305
insert(std::move(other.m_container), ctx);
306+
m_context_size = m_container.size();
257307
}
258308

259309
/// @return the view on the underlying container - non-const
@@ -269,6 +319,8 @@ class single_store {
269319
private:
270320
/// The underlying container implementation
271321
base_type m_container;
322+
size_type m_context_size{0u};
323+
size_type m_n_contexts{0u};
272324
};
273325

274326
} // namespace detray

tests/unit_tests/cpu/core/transform_store.cpp

+63-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "detray/core/detail/single_store.hpp"
1010

1111
// Detray test include(s)
12+
#include "detray/test/common/assert.hpp"
1213
#include "detray/test/utils/types.hpp"
1314

1415
// GTest include(s)
@@ -20,7 +21,8 @@ GTEST_TEST(detray_core, static_transform_store) {
2021
using transform3 = test::transform3;
2122
using point3 = test::point3;
2223

23-
using transform_store_t = single_store<transform3>;
24+
using transform_store_t =
25+
single_store<transform3, dvector, geometry_context>;
2426
transform_store_t static_store;
2527
typename transform_store_t::context_type ctx0{};
2628
typename transform_store_t::context_type ctx1{};
@@ -51,3 +53,63 @@ GTEST_TEST(detray_core, static_transform_store) {
5153
static_store.emplace_back(ctx0);
5254
ASSERT_EQ(static_store.size(ctx0), 5u);
5355
}
56+
57+
// This tests the construction of a static transform store
58+
GTEST_TEST(detray_core, multicontext_transform_store) {
59+
using namespace detray;
60+
using transform3 = test::transform3;
61+
using point3 = test::point3;
62+
63+
using transform_store_t =
64+
single_store<transform3, dvector, geometry_context>;
65+
transform_store_t xf_store;
66+
typename transform_store_t::context_type ctx0{0};
67+
typename transform_store_t::context_type ctx1{1};
68+
69+
// Populate the default context (context 0) of the transform store
70+
// Add new elements one at a time
71+
ASSERT_TRUE(xf_store.empty(ctx0));
72+
73+
point3 t0{0.f, 0.f, 0.f};
74+
transform3 tf0{t0};
75+
xf_store.push_back(tf0);
76+
77+
point3 t1{1.f, 10.f, 7.f};
78+
transform3 tf1{t1};
79+
xf_store.push_back(tf1);
80+
81+
point3 t2{2.f, 1.f, 4.f};
82+
transform3 tf2{t2};
83+
xf_store.push_back(tf2, ctx0);
84+
85+
point3 t3{3.f, 8.f, 6.f};
86+
transform3 tf3{t3};
87+
xf_store.push_back(tf3);
88+
89+
ASSERT_EQ(xf_store.size(ctx0), 4u);
90+
91+
// Create a vector of 'aligned' transforms
92+
point3 shift{.11f, .12f, .13f};
93+
typename transform_store_t::base_type aligned_transforms;
94+
aligned_transforms.reserve(xf_store.size(ctx0));
95+
aligned_transforms.push_back(transform3(t0 + shift));
96+
aligned_transforms.push_back(transform3(t1 + shift));
97+
aligned_transforms.push_back(transform3(t2 + shift));
98+
aligned_transforms.push_back(transform3(t3 + shift));
99+
100+
// Add context 1 to the transform store
101+
ASSERT_TRUE(xf_store.empty(ctx1));
102+
xf_store.add_context(aligned_transforms);
103+
ASSERT_EQ(xf_store.size(ctx1), 4u);
104+
105+
// Check that we can access context data as expected
106+
auto tr0_0 = xf_store.at(0, ctx0).translation();
107+
auto tr1_0 = xf_store.at(0, ctx1).translation();
108+
auto tr_diff_0 = tr1_0 - tr0_0;
109+
EXPECT_POINT3_NEAR(tr_diff_0, shift, 1e-6);
110+
111+
auto tr0_3 = xf_store.at(3, ctx0).translation();
112+
auto tr1_3 = xf_store.at(3, ctx1).translation();
113+
auto tr_diff_3 = tr1_3 - tr0_3;
114+
EXPECT_POINT3_NEAR(tr_diff_3, shift, 1e-6);
115+
}

tests/unit_tests/cpu/navigation/intersection/intersection_kernel.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ using mask_container_t =
7373
using mask_link_t = typename mask_container_t::single_link;
7474
using material_link_t = dtyped_index<material_ids, dindex>;
7575

76-
using transform_container_t = single_store<test::transform3>;
76+
using transform_container_t =
77+
single_store<test::transform3, dvector, geometry_context>;
7778

7879
/// The Surface definition:
7980
using surface_t =

tests/unit_tests/device/cuda/container_cuda.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ TEST(container_cuda, single_store) {
4646
EXPECT_EQ(mng_store.size(), 0u);
4747

4848
// Test the managed memory allocation
49-
empty_context ctx{};
49+
geometry_context ctx{};
5050
mng_store.reserve(4, ctx);
5151
mng_store.emplace_back(ctx, 1.);
5252
mng_store.push_back(2., ctx);

tests/unit_tests/device/cuda/container_cuda_kernel.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ namespace detray {
1919

2020
// Single store test
2121
/// @{
22-
using single_store_t = single_store<double, vecmem::vector>;
23-
using single_store_dev_t = single_store<double, vecmem::device_vector>;
22+
using single_store_t = single_store<double, vecmem::vector, geometry_context>;
23+
using single_store_dev_t =
24+
single_store<double, vecmem::device_vector, geometry_context>;
2425
/// @}
2526

2627
// Tuple container test

tests/unit_tests/device/cuda/transform_store_cuda_kernel.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ using scalar = dscalar<test_algebra>;
2424
using point3 = dpoint3D<test_algebra>;
2525
using transform3 = dtransform3D<test_algebra>;
2626

27-
using host_transform_store_t = single_store<transform3, vecmem::vector>;
27+
using host_transform_store_t =
28+
single_store<transform3, vecmem::vector, geometry_context>;
2829

2930
using device_transform_store_t =
30-
single_store<transform3, vecmem::device_vector>;
31+
single_store<transform3, vecmem::device_vector, geometry_context>;
3132

3233
void transform_test(vecmem::data::vector_view<point3> input_data,
3334
typename host_transform_store_t::view_type store_data,

0 commit comments

Comments
 (0)