Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
025d36e
[OpenMP] Adds omp_target_is_accessible routine
nicebert May 2, 2025
b33b27e
Update offload/libomptarget/OpenMP/API.cpp
nicebert Jul 28, 2025
bf01578
Fix comment spelling
nicebert Jul 28, 2025
d20f4d5
[OpenMP] Adds omp_target_is_accessible routine
nicebert May 2, 2025
cb87242
[OpenMP] Adds omp_target_is_accessible routine
nicebert May 2, 2025
03d45cc
Merge branch 'feat/omp_target_is_accessible' of github.com:nicebert/l…
nicebert Jul 31, 2025
21b1d6a
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Jul 31, 2025
95ab6fe
[OpenMP] Reverts omp_get_initial_device changes
nicebert Aug 1, 2025
2436211
Merge branch 'feat/omp_target_is_accessible' of github.com:nicebert/l…
nicebert Aug 1, 2025
c92c94f
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Aug 1, 2025
eeb7604
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Aug 6, 2025
9d97424
[OpenMP] Adds omp_target_is_accessible routine
nicebert May 2, 2025
34acf27
Update offload/libomptarget/OpenMP/API.cpp
nicebert Jul 28, 2025
d4ecaf6
Fix comment spelling
nicebert Jul 28, 2025
2792290
[OpenMP] Adds omp_target_is_accessible routine
nicebert May 2, 2025
712bdd1
[OpenMP] Reverts omp_get_initial_device changes
nicebert Aug 1, 2025
dd15747
[OpenMP] Rework implementation to be conform to OpenMP 6.0
nicebert Sep 15, 2025
108e4b9
Merge branch 'feat/omp_target_is_accessible' of github.com:nicebert/l…
nicebert Sep 15, 2025
e9dccd6
Applies git-clang-format
nicebert Sep 17, 2025
4345232
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Sep 17, 2025
4b51745
Fixes formatting and comment issues.
nicebert Sep 19, 2025
0ef2e79
Merge branch 'feat/omp_target_is_accessible' of github.com:nicebert/l…
nicebert Sep 19, 2025
454df9e
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Sep 19, 2025
79dd36f
[OpenMP] Fixes check for host device number
nicebert Sep 19, 2025
0ccae1d
Merge branch 'feat/omp_target_is_accessible' of github.com:nicebert/l…
nicebert Sep 19, 2025
588c394
Fixes formatting
nicebert Sep 19, 2025
b751e75
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Sep 19, 2025
584553e
Merge branch 'main' into feat/omp_target_is_accessible
nicebert Sep 19, 2025
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
3 changes: 3 additions & 0 deletions offload/include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ struct DeviceTy {
/// Ask the device whether the runtime should use auto zero-copy.
bool useAutoZeroCopy();

/// Ask the device whether the storage is accessible.
bool isAccessiblePtr(const void *Ptr, size_t Size);

/// Check if there are pending images for this device.
bool hasPendingImages() const { return HasPendingImages; }

Expand Down
1 change: 1 addition & 0 deletions offload/include/omptarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ int omp_get_initial_device(void);
void *omp_target_alloc(size_t Size, int DeviceNum);
void omp_target_free(void *DevicePtr, int DeviceNum);
int omp_target_is_present(const void *Ptr, int DeviceNum);
int omp_target_is_accessible(const void *Ptr, size_t Size, int DeviceNum);
int omp_target_memcpy(void *Dst, const void *Src, size_t Length,
size_t DstOffset, size_t SrcOffset, int DstDevice,
int SrcDevice);
Expand Down
28 changes: 28 additions & 0 deletions offload/libomptarget/OpenMP/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,34 @@ EXTERN int omp_target_is_present(const void *Ptr, int DeviceNum) {
return Rc;
}

/// Check whether a pointer is accessible from a device.
/// Returns true when accessibility is guaranteed otherwise returns false.
EXTERN int omp_target_is_accessible(const void *Ptr, size_t Size,
int DeviceNum) {
TIMESCOPE();
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
DP("Call to omp_target_is_accessible for device %d, address " DPxMOD
", size %zu\n",
DeviceNum, DPxPTR(Ptr), Size);

if (!Ptr) {
DP("Call to omp_target_is_accessible with NULL ptr returning false\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

Does spec say so?

Copy link
Member

Choose a reason for hiding this comment

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

It does. OMP Specs 6.0, page 607 "If ptr is NULL, the routine returns zero". Please check the specs before asking.

return false;
}

if (DeviceNum == omp_get_initial_device() || DeviceNum == -1) {
DP("Call to omp_target_is_accessible on host, returning true\n");
return true;
}

// The device number must refer to a valid device
auto DeviceOrErr = PM->getDevice(DeviceNum);
if (!DeviceOrErr)
FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder whether this is a fatal message or simple just return false? What does the spec say when the device number is invalid?

Copy link
Member

Choose a reason for hiding this comment

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

I agree with @shiltian : let's return false if the device doesn't exist. A warning is also in order.


return DeviceOrErr->isAccessiblePtr(Ptr, Size);
}

EXTERN int omp_target_memcpy(void *Dst, const void *Src, size_t Length,
size_t DstOffset, size_t SrcOffset, int DstDevice,
int SrcDevice) {
Expand Down
4 changes: 4 additions & 0 deletions offload/libomptarget/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,7 @@ bool DeviceTy::useAutoZeroCopy() {
return false;
return RTL->use_auto_zero_copy(RTLDeviceID);
}

bool DeviceTy::isAccessiblePtr(const void *Ptr, size_t Size) {
return RTL->is_accessible_ptr(RTLDeviceID, Ptr, Size);
}
1 change: 1 addition & 0 deletions offload/libomptarget/exports
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ VERS1.0 {
omp_get_initial_device;
omp_target_alloc;
omp_target_free;
omp_target_is_accessible;
omp_target_is_present;
omp_target_memcpy;
omp_target_memcpy_rect;
Expand Down
23 changes: 23 additions & 0 deletions offload/plugins-nextgen/amdgpu/src/rtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3027,6 +3027,29 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
return ((IsAPU || OMPX_ApuMaps) && IsXnackEnabled);
}

bool isAccessiblePtrImpl(const void *Ptr, size_t Size) override {
hsa_amd_pointer_info_t Info;
Info.size = sizeof(hsa_amd_pointer_info_t);

hsa_agent_t *Agents = nullptr;
uint32_t Count = 0;
hsa_status_t Status =
hsa_amd_pointer_info(Ptr, &Info, malloc, &Count, &Agents);

if (Status != HSA_STATUS_SUCCESS)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we log here what is the reason of failing?

Copy link
Member

Choose a reason for hiding this comment

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

I guess that the two semantically relevant errors here would be:
HSA_EXT_POINTER_TYPE_UNKNOWN
and
HSA_STATUS_ERROR_INVALID_ARGUMENT (which we should never get because we already checked whether ptr is null). The rest of the errors "out of resources, hsa not initialized" would have been caught earlier on, is my guess

return false;

// Checks if the pointer is known by HSA and accessible by the device
for (uint32_t i = 0; i < Count; i++)
if (Agents[i].handle == getAgent().handle)
return Info.sizeInBytes >= Size;
Comment on lines +3043 to +3045
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
for (uint32_t i = 0; i < Count; i++)
if (Agents[i].handle == getAgent().handle)
return Info.sizeInBytes >= Size;
for (uint32_t i = 0; i < Count; i++) {
if (Agents[i].handle == getAgent().handle)
return Info.sizeInBytes >= Size;
}


// If the pointer is unknown to HSA it's assumed a host pointer
// in that case the device can access it on unified memory support is
// enabled
return IsXnackEnabled;
Copy link
Member

Choose a reason for hiding this comment

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

Just a nit: there are GPUs that do not have xnack, but still have the ability to access host memory. This behavior is fine for now, but we will have to revisit based on GPU (later, not in this PR).

Copy link
Contributor

Choose a reason for hiding this comment

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

Then it should be documented.

}

/// Getters and setters for stack and heap sizes.
Error getDeviceStackSize(uint64_t &Value) override {
Value = StackSize;
Expand Down
10 changes: 10 additions & 0 deletions offload/plugins-nextgen/common/include/PluginInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,13 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
bool useAutoZeroCopy();
virtual bool useAutoZeroCopyImpl() { return false; }

/// Returns true if the plugin can guarantee that the associated
/// storage is accessible
bool isAccessiblePtr(const void *Ptr, size_t Size);
virtual bool isAccessiblePtrImpl(const void *Ptr, size_t Size) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If this impl function is only for internal use, can we make them private?

return false;
}

virtual Expected<omp_interop_val_t *>
createInterop(int32_t InteropType, interop_spec_t &InteropSpec) {
return nullptr;
Expand Down Expand Up @@ -1499,6 +1506,9 @@ struct GenericPluginTy {
/// Returns if the plugin can support automatic copy.
int32_t use_auto_zero_copy(int32_t DeviceId);

/// Returns if the associated storage is accessible for a given device.
int32_t is_accessible_ptr(int32_t DeviceId, const void *Ptr, size_t Size);

/// Look up a global symbol in the given binary.
int32_t get_global(__tgt_device_binary Binary, uint64_t Size,
const char *Name, void **DevicePtr);
Expand Down
9 changes: 9 additions & 0 deletions offload/plugins-nextgen/common/src/PluginInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1593,6 +1593,10 @@ Error GenericDeviceTy::syncEvent(void *EventPtr) {

bool GenericDeviceTy::useAutoZeroCopy() { return useAutoZeroCopyImpl(); }

bool GenericDeviceTy::isAccessiblePtr(const void *Ptr, size_t Size) {
return isAccessiblePtrImpl(Ptr, Size);
}

Error GenericPluginTy::init() {
if (Initialized)
return Plugin::success();
Expand Down Expand Up @@ -2147,6 +2151,11 @@ int32_t GenericPluginTy::use_auto_zero_copy(int32_t DeviceId) {
return getDevice(DeviceId).useAutoZeroCopy();
}

int32_t GenericPluginTy::is_accessible_ptr(int32_t DeviceId, const void *Ptr,
size_t Size) {
return getDevice(DeviceId).isAccessiblePtr(Ptr, Size);
}

int32_t GenericPluginTy::get_global(__tgt_device_binary Binary, uint64_t Size,
const char *Name, void **DevicePtr) {
assert(Binary.handle && "Invalid device binary handle");
Expand Down
40 changes: 40 additions & 0 deletions offload/test/mapping/is_accessible.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %libomptarget-compilexx-generic
// RUN: env HSA_XNACK=1 %libomptarget-run-generic 2>&1 \
// RUN: | %fcheck-generic

// RUN: %libomptarget-compilexx-generic
// RUN: env HSA_XNACK=0 %libomptarget-run-generic 2>&1 \
// RUN: | %fcheck-generic -check-prefix=NO_USM

// REQUIRES: unified_shared_memory
// REQUIRES: amdgpu
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd make this a XFAIL for nvptx instead of a requirement, since it always returns false.


// CHECK: SUCCESS
// NO_USM: Not accessible

#include <assert.h>
#include <iostream>
#include <omp.h>
#include <stdio.h>

int main() {
int n = 10000;
int *a = new int[n];
int err = 0;

// program must be executed with HSA_XNACK=1
if (!omp_target_is_accessible(a, n * sizeof(int), /*device_num=*/0))
printf("Not accessible\n");
else {
#pragma omp target teams distribute parallel for
for (int i = 0; i < n; i++)
a[i] = i;

for (int i = 0; i < n; i++)
if (a[i] != i)
err++;
}

printf("%s\n", err == 0 ? "SUCCESS" : "FAIL");
return err;
}
Loading