@@ -446,3 +446,193 @@ int main(int argc, char **argv) {
446446 ::testing::InitGoogleTest (&argc, argv);
447447 return RUN_ALL_TESTS ();
448448}
449+ // Test: obtain the device-visible alias of mapped host memory.
450+ TEST_F (DeviceAdaptorTest, HostGetDevicePointer) {
451+ ASSERT_NE (devHandle->hostGetDevicePointer , nullptr );
452+ void *hostPtr = nullptr ;
453+ ASSERT_EQ (devHandle->deviceMalloc (&hostPtr, TEST_SIZE , flagcxMemHost, nullptr ),
454+ flagcxSuccess);
455+ ASSERT_NE (hostPtr, nullptr );
456+ void *devicePtr = nullptr ;
457+ EXPECT_EQ (devHandle->hostGetDevicePointer (&devicePtr, hostPtr), flagcxSuccess);
458+ EXPECT_NE (devicePtr, nullptr );
459+ EXPECT_EQ (devHandle->hostGetDevicePointer (nullptr , hostPtr),
460+ flagcxInvalidArgument);
461+ EXPECT_EQ (devHandle->hostGetDevicePointer (&devicePtr, nullptr ),
462+ flagcxInvalidArgument);
463+ EXPECT_EQ (devHandle->deviceFree (hostPtr, flagcxMemHost, nullptr ),
464+ flagcxSuccess);
465+ }
466+
467+ // Test: Host memory register / get device pointer / unregister
468+ // flagcxDeviceHandle does not expose hostRegister/hostUnregister, so we
469+ // access them through the internal deviceAdaptor pointer (from adaptor.h).
470+ // Portable across all backends: skips if not implemented (NULL or NotSupported).
471+ TEST_F (DeviceAdaptorTest, HostRegisterUnregister) {
472+ if (!deviceAdaptor->hostRegister || !deviceAdaptor->hostUnregister ) {
473+ GTEST_SKIP () << " hostRegister/hostUnregister not implemented" ;
474+ }
475+
476+ const size_t sz = 4096 ;
477+ void *hostPtr = malloc (sz);
478+ ASSERT_NE (hostPtr, nullptr );
479+
480+ // Register host memory as pinned (page-locked) memory.
481+ auto result = deviceAdaptor->hostRegister (hostPtr, sz);
482+ if (result == flagcxNotSupported) {
483+ free (hostPtr);
484+ GTEST_SKIP () << " hostRegister not supported on this backend" ;
485+ }
486+ EXPECT_EQ (result, flagcxSuccess);
487+
488+ if (result == flagcxSuccess) {
489+ // Unregister
490+ auto r2 = deviceAdaptor->hostUnregister (hostPtr);
491+ EXPECT_EQ (r2, flagcxSuccess);
492+ }
493+ free (hostPtr);
494+
495+ // Verify invalid arguments are rejected (only if backend has real impl)
496+ auto nullResult = deviceAdaptor->hostRegister (NULL , sz);
497+ if (nullResult != flagcxNotSupported) {
498+ EXPECT_EQ (nullResult, flagcxInvalidArgument);
499+ }
500+ auto zeroResult = deviceAdaptor->hostRegister (hostPtr, 0 );
501+ if (zeroResult != flagcxNotSupported) {
502+ EXPECT_EQ (zeroResult, flagcxInvalidArgument);
503+ }
504+ auto unregNullResult = deviceAdaptor->hostUnregister (NULL );
505+ if (unregNullResult != flagcxNotSupported) {
506+ EXPECT_EQ (unregNullResult, flagcxInvalidArgument);
507+ }
508+ }
509+
510+ // Test: getDevicePciBusId — string format and invalid-arg guards
511+ TEST_F (DeviceAdaptorTest, GetDevicePciBusId) {
512+ int numDevices = 0 ;
513+ ASSERT_EQ (devHandle->getDeviceCount (&numDevices), flagcxSuccess);
514+ ASSERT_GT (numDevices, 0 );
515+
516+ for (int dev = 0 ; dev < numDevices; dev++) {
517+ char pciBusId[FLAGCX_DEVICE_PCI_BUSID_BUFFER_SIZE ] = {};
518+ ASSERT_EQ (deviceAdaptor->getDevicePciBusId (pciBusId, sizeof (pciBusId), dev),
519+ flagcxSuccess)
520+ << " getDevicePciBusId failed for device " << dev;
521+ EXPECT_NE (pciBusId[0 ], ' \0 ' ) << " empty PCI bus ID for device " << dev;
522+
523+ // Verify format: domain:bus:device.function (4 hex fields)
524+ unsigned int domain = 0 , bus = 0 , pciDevice = 0 , function = 0 ;
525+ EXPECT_EQ (sscanf (pciBusId, " %x:%x:%x.%x" , &domain, &bus, &pciDevice, &function),
526+ 4 )
527+ << " unexpected PCI bus ID format: " << pciBusId;
528+
529+ std::cout << " Device " << dev << " : pci=" << pciBusId << std::endl;
530+ }
531+
532+ // Invalid-argument guards
533+ char buf[FLAGCX_DEVICE_PCI_BUSID_BUFFER_SIZE ] = {};
534+ EXPECT_EQ (deviceAdaptor->getDevicePciBusId (nullptr , sizeof (buf), 0 ),
535+ flagcxInvalidArgument);
536+
537+ // Out-of-range device index
538+ EXPECT_NE (deviceAdaptor->getDevicePciBusId (buf, sizeof (buf), -1 ), flagcxSuccess);
539+ EXPECT_NE (deviceAdaptor->getDevicePciBusId (buf, sizeof (buf), numDevices),
540+ flagcxSuccess);
541+ }
542+
543+ // Test: getDeviceProperties — name and PCI fields, invalid-arg guards
544+ TEST_F (DeviceAdaptorTest, GetDeviceProperties) {
545+ int numDevices = 0 ;
546+ ASSERT_EQ (devHandle->getDeviceCount (&numDevices), flagcxSuccess);
547+ ASSERT_GT (numDevices, 0 );
548+
549+ for (int dev = 0 ; dev < numDevices; dev++) {
550+ flagcxDevProps props = {};
551+ ASSERT_EQ (deviceAdaptor->getDeviceProperties (&props, dev), flagcxSuccess)
552+ << " getDeviceProperties failed for device " << dev;
553+ EXPECT_NE (props.name [0 ], ' \0 ' ) << " empty device name for device " << dev;
554+
555+ // PCI fields are parsed from cudaDeviceGetPCIBusId string
556+ EXPECT_GE (props.pciBusId , 0 ) << " pciBusId out of range for device " << dev;
557+ EXPECT_LE (props.pciBusId , 255 ) << " pciBusId out of range for device " << dev;
558+ EXPECT_GE (props.pciDeviceId , 0 ) << " pciDeviceId out of range for device " << dev;
559+ EXPECT_LE (props.pciDeviceId , 31 ) << " pciDeviceId out of range for device " << dev;
560+ EXPECT_GE (props.pciDomainId , 0 ) << " pciDomainId out of range for device " << dev;
561+ EXPECT_LE (props.pciDomainId , 65535 ) << " pciDomainId out of range for device " << dev;
562+
563+ std::cout << " Device " << dev << " : name=" << props.name
564+ << " , pciBusId=" << props.pciBusId
565+ << " , pciDeviceId=" << props.pciDeviceId
566+ << " , pciDomainId=" << props.pciDomainId << std::endl;
567+ }
568+
569+ // Invalid-argument guards
570+ EXPECT_EQ (deviceAdaptor->getDeviceProperties (nullptr , 0 ),
571+ flagcxInvalidArgument);
572+
573+ // Out-of-range device index
574+ flagcxDevProps props = {};
575+ EXPECT_NE (deviceAdaptor->getDeviceProperties (&props, -1 ), flagcxSuccess);
576+ EXPECT_NE (deviceAdaptor->getDeviceProperties (&props, numDevices),
577+ flagcxSuccess);
578+ }
579+
580+ // Test: getDeviceByPciBusId — reverse lookup and invalid-arg guards
581+ TEST_F (DeviceAdaptorTest, GetDeviceByPciBusId) {
582+ int numDevices = 0 ;
583+ ASSERT_EQ (devHandle->getDeviceCount (&numDevices), flagcxSuccess);
584+ ASSERT_GT (numDevices, 0 );
585+
586+ for (int dev = 0 ; dev < numDevices; dev++) {
587+ // Get PCI bus ID string directly from runtime (independent of getDevicePciBusId)
588+ char pciBusId[FLAGCX_DEVICE_PCI_BUSID_BUFFER_SIZE ] = {};
589+ ASSERT_EQ (cudaDeviceGetPCIBusId (pciBusId, sizeof (pciBusId), dev), cudaSuccess)
590+ << " cudaDeviceGetPCIBusId failed for dev=" << dev;
591+
592+ // Reverse lookup: string -> device index
593+ int result = -1 ;
594+ ASSERT_EQ (deviceAdaptor->getDeviceByPciBusId (&result, pciBusId), flagcxSuccess)
595+ << " getDeviceByPciBusId failed for pci=" << pciBusId;
596+ EXPECT_EQ (result, dev)
597+ << " round-trip mismatch: pci=" << pciBusId
598+ << " returned dev=" << result << " expected=" << dev;
599+
600+ std::cout << " Device " << dev << " : pci=" << pciBusId
601+ << " -> dev=" << result << std::endl;
602+ }
603+
604+ // Invalid-argument guards
605+ int dev = -1 ;
606+ char pciBusId[FLAGCX_DEVICE_PCI_BUSID_BUFFER_SIZE ] = {};
607+ EXPECT_EQ (deviceAdaptor->getDeviceByPciBusId (nullptr , pciBusId),
608+ flagcxInvalidArgument);
609+ EXPECT_EQ (deviceAdaptor->getDeviceByPciBusId (&dev, nullptr ),
610+ flagcxInvalidArgument);
611+
612+ // Invalid PCI string
613+ EXPECT_NE (deviceAdaptor->getDeviceByPciBusId (&dev, " invalid" ), flagcxSuccess);
614+ }
615+
616+ // Test: eventElapsedTime reports the duration between two timing events.
617+ TEST_F (DeviceAdaptorTest, EventElapsedTime) {
618+ ASSERT_NE (devHandle->eventElapsedTime , nullptr );
619+ flagcxEvent_t startEvent = nullptr ;
620+ flagcxEvent_t endEvent = nullptr ;
621+ ASSERT_EQ (devHandle->eventCreate (&startEvent, flagcxEventDefault), flagcxSuccess);
622+ ASSERT_EQ (devHandle->eventCreate (&endEvent, flagcxEventDefault), flagcxSuccess);
623+ ASSERT_EQ (devHandle->eventRecord (startEvent, stream), flagcxSuccess);
624+ ASSERT_EQ (devHandle->eventRecord (endEvent, stream), flagcxSuccess);
625+ ASSERT_EQ (devHandle->eventSynchronize (endEvent), flagcxSuccess);
626+ float elapsedMs = -1 .0f ;
627+ EXPECT_EQ (devHandle->eventElapsedTime (&elapsedMs, startEvent, endEvent),
628+ flagcxSuccess);
629+ EXPECT_GE (elapsedMs, 0 .0f );
630+ EXPECT_EQ (devHandle->eventElapsedTime (nullptr , startEvent, endEvent),
631+ flagcxInvalidArgument);
632+ EXPECT_EQ (devHandle->eventElapsedTime (&elapsedMs, nullptr , endEvent),
633+ flagcxInvalidArgument);
634+ EXPECT_EQ (devHandle->eventElapsedTime (&elapsedMs, startEvent, nullptr ),
635+ flagcxInvalidArgument);
636+ EXPECT_EQ (devHandle->eventDestroy (startEvent), flagcxSuccess);
637+ EXPECT_EQ (devHandle->eventDestroy (endEvent), flagcxSuccess);
638+ }
0 commit comments