55
66#include < folly/init/Init.h>
77#include < cstddef>
8+ #include < limits>
89#include < memory>
910#include < vector>
1011
@@ -151,12 +152,39 @@ struct TransportHandle {
151152 ibrc->deregisterBuffer (ptr);
152153 }
153154 }
155+
156+ IbBufferRegistrationLease registerIbBulkBuffer (void * ptr, std::size_t size) {
157+ return ibgda ? ibgda->registerIbBulkBuffer (ptr, size)
158+ : ibrc->registerIbBulkBuffer (ptr, size);
159+ }
160+
161+ std::optional<IbBufferRegistrationView> lookupIbBulkBuffer (
162+ const IbBufferRegistrationLease& lease,
163+ void * ptr,
164+ std::size_t size) const {
165+ return ibgda ? ibgda->lookupIbBulkBuffer (lease, ptr, size)
166+ : ibrc->lookupIbBulkBuffer (lease, ptr, size);
167+ }
168+
169+ void deregisterIbBulkBuffer (IbBufferRegistrationLease& lease) {
170+ if (ibgda) {
171+ ibgda->deregisterIbBulkBuffer (lease);
172+ } else {
173+ ibrc->deregisterIbBulkBuffer (lease);
174+ }
175+ }
176+
177+ bool isIbBulkBufferViewActive (const IbBufferRegistrationView& view) const {
178+ return ibgda ? ibgda->isIbBulkBufferViewActive (view)
179+ : ibrc->isIbBulkBufferViewActive (view);
180+ }
154181};
155182
156- TransportHandle createTransport (IbTestBackend backend) {
183+ TransportHandle createTransport (
184+ IbTestBackend backend,
185+ const MultipeerIbTransportConfig& config) {
157186 auto bootstrap = std::make_shared<
158187 testing::NiceMock<meta::comms::testing::MockBootstrap>>();
159- auto config = makeConfig ();
160188 TransportHandle handle;
161189 if (backend == IbTestBackend::Ibgda) {
162190 handle.ibgda = std::make_unique<MultipeerIbgdaTransport>(
@@ -168,6 +196,10 @@ TransportHandle createTransport(IbTestBackend backend) {
168196 return handle;
169197}
170198
199+ TransportHandle createTransport (IbTestBackend backend) {
200+ return createTransport (backend, makeConfig ());
201+ }
202+
171203class MultiSegmentRegistrationTest
172204 : public ::testing::TestWithParam<IbTestBackend> {};
173205
@@ -251,6 +283,161 @@ TEST_P(MultiSegmentRegistrationTest, ContiguousBufferRegistration) {
251283 CUDACHECK_TEST (cudaFree (devPtr));
252284}
253285
286+ TEST_P (MultiSegmentRegistrationTest, BulkLeaseBoundsContainedViews) {
287+ CUDACHECK_TEST (cudaSetDevice (0 ));
288+
289+ TransportHandle transport;
290+ try {
291+ transport = createTransport (GetParam ());
292+ } catch (const std::exception& e) {
293+ GTEST_SKIP () << backendName (GetParam ())
294+ << " transport not available: " << e.what ();
295+ }
296+
297+ constexpr std::size_t kAllocationSize = 4 * 1024 * 1024 ;
298+ constexpr std::size_t kLeaseOffset = 512 * 1024 ;
299+ constexpr std::size_t kLeaseSize = 2 * 1024 * 1024 ;
300+ constexpr std::size_t kViewOffset = 128 * 1024 ;
301+ constexpr std::size_t kViewSize = 256 * 1024 ;
302+ void * allocation = nullptr ;
303+ CUDACHECK_TEST (cudaMalloc (&allocation, kAllocationSize ));
304+ auto * const leasePtr = static_cast <char *>(allocation) + kLeaseOffset ;
305+
306+ EXPECT_THROW (
307+ transport.registerIbBulkBuffer (leasePtr, 0 ), std::invalid_argument);
308+ auto lease = transport.registerIbBulkBuffer (leasePtr, kLeaseSize );
309+ EXPECT_THROW (
310+ transport.lookupIbBulkBuffer (lease, leasePtr, 0 ), std::invalid_argument);
311+ EXPECT_THROW (
312+ transport.lookupIbBulkBuffer (
313+ lease, leasePtr, std::numeric_limits<std::size_t >::max ()),
314+ std::invalid_argument);
315+ auto exact = transport.lookupIbBulkBuffer (lease, leasePtr, kLeaseSize );
316+ auto contained =
317+ transport.lookupIbBulkBuffer (lease, leasePtr + kViewOffset , kViewSize );
318+ auto tail = transport.lookupIbBulkBuffer (lease, leasePtr + kLeaseSize - 1 , 1 );
319+ auto before = transport.lookupIbBulkBuffer (lease, leasePtr - 1 , kViewSize );
320+ auto after = transport.lookupIbBulkBuffer (
321+ lease, leasePtr + kLeaseSize - kViewSize + 1 , kViewSize );
322+
323+ ASSERT_TRUE (exact.has_value ());
324+ ASSERT_TRUE (contained.has_value ());
325+ ASSERT_TRUE (tail.has_value ());
326+ EXPECT_EQ (exact->localBuffer .ptr , leasePtr);
327+ EXPECT_EQ (contained->localBuffer .ptr , leasePtr + kViewOffset );
328+ EXPECT_EQ (contained->size , kViewSize );
329+ EXPECT_EQ (contained->leaseGeneration , lease.generation ());
330+ EXPECT_FALSE (before.has_value ());
331+ EXPECT_FALSE (after.has_value ());
332+ EXPECT_TRUE (transport.isIbBulkBufferViewActive (*contained));
333+
334+ transport.deregisterIbBulkBuffer (lease);
335+ EXPECT_FALSE (lease.valid ());
336+ EXPECT_FALSE (
337+ transport.lookupIbBulkBuffer (lease, leasePtr, kViewSize ).has_value ());
338+ EXPECT_FALSE (transport.isIbBulkBufferViewActive (*contained));
339+ EXPECT_THROW (transport.deregisterIbBulkBuffer (lease), std::invalid_argument);
340+ CUDACHECK_TEST (cudaFree (allocation));
341+ }
342+
343+ TEST_P (MultiSegmentRegistrationTest, BulkLeaseReportsEffectiveStrictOrdering) {
344+ CUDACHECK_TEST (cudaSetDevice (0 ));
345+
346+ auto config = makeConfig ();
347+ config.enablePciRelaxedOrdering =
348+ MultipeerIbTransportConfig::PciRelaxedOrderingMode::Disabled;
349+ TransportHandle transport;
350+ try {
351+ transport = createTransport (GetParam (), std::move (config));
352+ } catch (const std::exception& e) {
353+ GTEST_SKIP () << backendName (GetParam ())
354+ << " transport not available: " << e.what ();
355+ }
356+
357+ constexpr std::size_t kSize = 2 * 1024 * 1024 ;
358+ void * allocation = nullptr ;
359+ CUDACHECK_TEST (cudaMalloc (&allocation, kSize ));
360+
361+ auto lease = transport.registerIbBulkBuffer (allocation, kSize );
362+ auto view = transport.lookupIbBulkBuffer (lease, allocation, kSize );
363+ ASSERT_TRUE (view.has_value ());
364+ EXPECT_FALSE (view->relaxedOrdering );
365+
366+ transport.deregisterIbBulkBuffer (lease);
367+ CUDACHECK_TEST (cudaFree (allocation));
368+ }
369+
370+ TEST_P (MultiSegmentRegistrationTest, OverlappingBulkLeasesRemainDistinct) {
371+ CUDACHECK_TEST (cudaSetDevice (0 ));
372+
373+ TransportHandle transport;
374+ try {
375+ transport = createTransport (GetParam ());
376+ } catch (const std::exception& e) {
377+ GTEST_SKIP () << backendName (GetParam ())
378+ << " transport not available: " << e.what ();
379+ }
380+
381+ constexpr std::size_t kAllocationSize = 4 * 1024 * 1024 ;
382+ constexpr std::size_t kOuterSize = 3 * 1024 * 1024 ;
383+ constexpr std::size_t kInnerOffset = 1024 * 1024 ;
384+ constexpr std::size_t kInnerSize = 1024 * 1024 ;
385+ void * allocation = nullptr ;
386+ CUDACHECK_TEST (cudaMalloc (&allocation, kAllocationSize ));
387+ auto * const base = static_cast <char *>(allocation);
388+
389+ auto outer = transport.registerIbBulkBuffer (base, kOuterSize );
390+ auto inner = transport.registerIbBulkBuffer (base + kInnerOffset , kInnerSize );
391+ auto outerView =
392+ transport.lookupIbBulkBuffer (outer, base + kInnerOffset , kInnerSize );
393+ auto innerView =
394+ transport.lookupIbBulkBuffer (inner, base + kInnerOffset , kInnerSize );
395+
396+ ASSERT_TRUE (outerView.has_value ());
397+ ASSERT_TRUE (innerView.has_value ());
398+ EXPECT_NE (outer.generation (), inner.generation ());
399+ EXPECT_EQ (outerView->leaseGeneration , outer.generation ());
400+ EXPECT_EQ (innerView->leaseGeneration , inner.generation ());
401+
402+ transport.deregisterIbBulkBuffer (inner);
403+ EXPECT_FALSE (transport.isIbBulkBufferViewActive (*innerView));
404+ EXPECT_TRUE (transport.isIbBulkBufferViewActive (*outerView));
405+ transport.deregisterIbBulkBuffer (outer);
406+ CUDACHECK_TEST (cudaFree (allocation));
407+ }
408+
409+ TEST_P (MultiSegmentRegistrationTest, ReregistrationChangesLeaseGeneration) {
410+ CUDACHECK_TEST (cudaSetDevice (0 ));
411+
412+ TransportHandle transport;
413+ try {
414+ transport = createTransport (GetParam ());
415+ } catch (const std::exception& e) {
416+ GTEST_SKIP () << backendName (GetParam ())
417+ << " transport not available: " << e.what ();
418+ }
419+
420+ constexpr std::size_t kSize = 2 * 1024 * 1024 ;
421+ void * allocation = nullptr ;
422+ CUDACHECK_TEST (cudaMalloc (&allocation, kSize ));
423+
424+ auto first = transport.registerIbBulkBuffer (allocation, kSize );
425+ auto firstView = transport.lookupIbBulkBuffer (first, allocation, kSize );
426+ ASSERT_TRUE (firstView.has_value ());
427+ const uint64_t firstGeneration = first.generation ();
428+ transport.deregisterIbBulkBuffer (first);
429+
430+ auto second = transport.registerIbBulkBuffer (allocation, kSize );
431+ auto secondView = transport.lookupIbBulkBuffer (second, allocation, kSize );
432+ ASSERT_TRUE (secondView.has_value ());
433+ EXPECT_NE (firstGeneration, second.generation ());
434+ EXPECT_FALSE (transport.isIbBulkBufferViewActive (*firstView));
435+ EXPECT_TRUE (transport.isIbBulkBufferViewActive (*secondView));
436+
437+ transport.deregisterIbBulkBuffer (second);
438+ CUDACHECK_TEST (cudaFree (allocation));
439+ }
440+
254441} // namespace comms::prims::tests
255442
256443int main (int argc, char ** argv) {
0 commit comments