Skip to content

Commit 0848add

Browse files
nicebertshiltian
authored andcommitted
[OpenMP] Adds omp_target_is_accessible routine (llvm#138294)
Adds omp_target_is_accessible routine. Refactors common code from omp_target_is_present to work for both routines. --------- Co-authored-by: Shilei Tian <[email protected]>
1 parent a65a304 commit 0848add

File tree

10 files changed

+133
-1
lines changed

10 files changed

+133
-1
lines changed

clang/docs/OpenMPSupport.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ implementation.
256256
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
257257
| device | device-specific environment variables | :none:`unclaimed` | |
258258
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
259-
| device | omp_target_is_accessible routine | :part:`In Progress` | https://github.com/llvm/llvm-project/pull/138294 |
259+
| device | omp_target_is_accessible routine | :good:`done` | https://github.com/llvm/llvm-project/pull/138294 |
260260
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
261261
| device | omp_get_mapped_ptr routine | :good:`done` | D141545 |
262262
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+

offload/include/device.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ struct DeviceTy {
158158
/// Ask the device whether the runtime should use auto zero-copy.
159159
bool useAutoZeroCopy();
160160

161+
/// Ask the device whether the storage is accessible.
162+
bool isAccessiblePtr(const void *Ptr, size_t Size);
163+
161164
/// Check if there are pending images for this device.
162165
bool hasPendingImages() const { return HasPendingImages; }
163166

offload/include/omptarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ int omp_get_initial_device(void);
278278
void *omp_target_alloc(size_t Size, int DeviceNum);
279279
void omp_target_free(void *DevicePtr, int DeviceNum);
280280
int omp_target_is_present(const void *Ptr, int DeviceNum);
281+
int omp_target_is_accessible(const void *Ptr, size_t Size, int DeviceNum);
281282
int omp_target_memcpy(void *Dst, const void *Src, size_t Length,
282283
size_t DstOffset, size_t SrcOffset, int DstDevice,
283284
int SrcDevice);

offload/libomptarget/OpenMP/API.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,34 @@ EXTERN int omp_target_is_present(const void *Ptr, int DeviceNum) {
196196
return Rc;
197197
}
198198

199+
/// Check whether a pointer is accessible from a device.
200+
/// Returns true when accessibility is guaranteed otherwise returns false.
201+
EXTERN int omp_target_is_accessible(const void *Ptr, size_t Size,
202+
int DeviceNum) {
203+
TIMESCOPE();
204+
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
205+
DP("Call to omp_target_is_accessible for device %d, address " DPxMOD
206+
", size %zu\n",
207+
DeviceNum, DPxPTR(Ptr), Size);
208+
209+
if (!Ptr) {
210+
DP("Call to omp_target_is_accessible with NULL ptr returning false\n");
211+
return false;
212+
}
213+
214+
if (DeviceNum == omp_get_initial_device() || DeviceNum == -1) {
215+
DP("Call to omp_target_is_accessible on host, returning true\n");
216+
return true;
217+
}
218+
219+
// The device number must refer to a valid device
220+
auto DeviceOrErr = PM->getDevice(DeviceNum);
221+
if (!DeviceOrErr)
222+
FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
223+
224+
return DeviceOrErr->isAccessiblePtr(Ptr, Size);
225+
}
226+
199227
EXTERN int omp_target_memcpy(void *Dst, const void *Src, size_t Length,
200228
size_t DstOffset, size_t SrcOffset, int DstDevice,
201229
int SrcDevice) {

offload/libomptarget/device.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,7 @@ bool DeviceTy::useAutoZeroCopy() {
367367
return false;
368368
return RTL->use_auto_zero_copy(RTLDeviceID);
369369
}
370+
371+
bool DeviceTy::isAccessiblePtr(const void *Ptr, size_t Size) {
372+
return RTL->is_accessible_ptr(RTLDeviceID, Ptr, Size);
373+
}

offload/libomptarget/exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ VERS1.0 {
4343
omp_get_initial_device;
4444
omp_target_alloc;
4545
omp_target_free;
46+
omp_target_is_accessible;
4647
omp_target_is_present;
4748
omp_target_memcpy;
4849
omp_target_memcpy_rect;

offload/plugins-nextgen/amdgpu/src/rtl.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3062,6 +3062,30 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
30623062
return ((IsAPU || OMPX_ApuMaps) && IsXnackEnabled);
30633063
}
30643064

3065+
Expected<bool> isAccessiblePtrImpl(const void *Ptr, size_t Size) override {
3066+
hsa_amd_pointer_info_t Info;
3067+
Info.size = sizeof(hsa_amd_pointer_info_t);
3068+
3069+
hsa_agent_t *Agents = nullptr;
3070+
uint32_t Count = 0;
3071+
hsa_status_t Status =
3072+
hsa_amd_pointer_info(Ptr, &Info, malloc, &Count, &Agents);
3073+
3074+
if (auto Err = Plugin::check(Status, "error in hsa_amd_pointer_info: %s"))
3075+
return std::move(Err);
3076+
3077+
// Checks if the pointer is known by HSA and accessible by the device
3078+
for (uint32_t i = 0; i < Count; i++) {
3079+
if (Agents[i].handle == getAgent().handle)
3080+
return Info.sizeInBytes >= Size;
3081+
}
3082+
3083+
// If the pointer is unknown to HSA it's assumed a host pointer
3084+
// in that case the device can access it on unified memory support is
3085+
// enabled
3086+
return IsXnackEnabled;
3087+
}
3088+
30653089
/// Getters and setters for stack and heap sizes.
30663090
Error getDeviceStackSize(uint64_t &Value) override {
30673091
Value = StackSize;

offload/plugins-nextgen/common/include/PluginInterface.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,10 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
10661066
bool useAutoZeroCopy();
10671067
virtual bool useAutoZeroCopyImpl() { return false; }
10681068

1069+
/// Returns true if the plugin can guarantee that the associated
1070+
/// storage is accessible
1071+
Expected<bool> isAccessiblePtr(const void *Ptr, size_t Size);
1072+
10691073
virtual Expected<omp_interop_val_t *>
10701074
createInterop(int32_t InteropType, interop_spec_t &InteropSpec) {
10711075
return nullptr;
@@ -1166,6 +1170,10 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
11661170
/// Per device setting of MemoryManager's Threshold
11671171
virtual size_t getMemoryManagerSizeThreshold() { return 0; }
11681172

1173+
virtual Expected<bool> isAccessiblePtrImpl(const void *Ptr, size_t Size) {
1174+
return false;
1175+
}
1176+
11691177
/// Environment variables defined by the OpenMP standard.
11701178
Int32Envar OMP_TeamLimit;
11711179
Int32Envar OMP_NumTeams;
@@ -1492,6 +1500,9 @@ struct GenericPluginTy {
14921500
/// Returns if the plugin can support automatic copy.
14931501
int32_t use_auto_zero_copy(int32_t DeviceId);
14941502

1503+
/// Returns if the associated storage is accessible for a given device.
1504+
int32_t is_accessible_ptr(int32_t DeviceId, const void *Ptr, size_t Size);
1505+
14951506
/// Look up a global symbol in the given binary.
14961507
int32_t get_global(__tgt_device_binary Binary, uint64_t Size,
14971508
const char *Name, void **DevicePtr);

offload/plugins-nextgen/common/src/PluginInterface.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,10 @@ Error GenericDeviceTy::syncEvent(void *EventPtr) {
15991599

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

1602+
Expected<bool> GenericDeviceTy::isAccessiblePtr(const void *Ptr, size_t Size) {
1603+
return isAccessiblePtrImpl(Ptr, Size);
1604+
}
1605+
16021606
Error GenericPluginTy::init() {
16031607
if (Initialized)
16041608
return Plugin::success();
@@ -2133,6 +2137,22 @@ int32_t GenericPluginTy::use_auto_zero_copy(int32_t DeviceId) {
21332137
return getDevice(DeviceId).useAutoZeroCopy();
21342138
}
21352139

2140+
int32_t GenericPluginTy::is_accessible_ptr(int32_t DeviceId, const void *Ptr,
2141+
size_t Size) {
2142+
auto HandleError = [&](Error Err) -> bool {
2143+
[[maybe_unused]] std::string ErrStr = toString(std::move(Err));
2144+
DP("Failure while checking accessibility of pointer %p for device %d: %s",
2145+
Ptr, DeviceId, ErrStr.c_str());
2146+
return false;
2147+
};
2148+
2149+
auto AccessibleOrErr = getDevice(DeviceId).isAccessiblePtr(Ptr, Size);
2150+
if (Error Err = AccessibleOrErr.takeError())
2151+
return HandleError(std::move(Err));
2152+
2153+
return *AccessibleOrErr;
2154+
}
2155+
21362156
int32_t GenericPluginTy::get_global(__tgt_device_binary Binary, uint64_t Size,
21372157
const char *Name, void **DevicePtr) {
21382158
assert(Binary.handle && "Invalid device binary handle");
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %libomptarget-compilexx-generic
2+
// RUN: env HSA_XNACK=1 %libomptarget-run-generic 2>&1 \
3+
// RUN: | %fcheck-generic
4+
5+
// RUN: %libomptarget-compilexx-generic
6+
// RUN: env HSA_XNACK=0 %libomptarget-run-generic 2>&1 \
7+
// RUN: | %fcheck-generic -check-prefix=NO_USM
8+
9+
// REQUIRES: unified_shared_memory
10+
// XFAIL: nvptx
11+
12+
// CHECK: SUCCESS
13+
// NO_USM: Not accessible
14+
15+
#include <assert.h>
16+
#include <iostream>
17+
#include <omp.h>
18+
#include <stdio.h>
19+
20+
int main() {
21+
int n = 10000;
22+
int *a = new int[n];
23+
int err = 0;
24+
25+
// program must be executed with HSA_XNACK=1
26+
if (!omp_target_is_accessible(a, n * sizeof(int), /*device_num=*/0))
27+
printf("Not accessible\n");
28+
else {
29+
#pragma omp target teams distribute parallel for
30+
for (int i = 0; i < n; i++)
31+
a[i] = i;
32+
33+
for (int i = 0; i < n; i++)
34+
if (a[i] != i)
35+
err++;
36+
}
37+
38+
printf("%s\n", err == 0 ? "SUCCESS" : "FAIL");
39+
return err;
40+
}

0 commit comments

Comments
 (0)