llvm-project
283 строки · 10.0 Кб
1//===--------- device.cpp - Target independent OpenMP target RTL ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Functionality for managing devices that are handled by RTL plugins.
10//
11//===----------------------------------------------------------------------===//
12
13#include "device.h"
14#include "OffloadEntry.h"
15#include "OpenMP/Mapping.h"
16#include "OpenMP/OMPT/Callback.h"
17#include "OpenMP/OMPT/Interface.h"
18#include "PluginManager.h"
19#include "Shared/APITypes.h"
20#include "Shared/Debug.h"
21#include "omptarget.h"
22#include "private.h"
23#include "rtl.h"
24
25#include "Shared/EnvironmentVar.h"
26#include "llvm/Support/Error.h"
27
28#include <cassert>
29#include <climits>
30#include <cstdint>
31#include <cstdio>
32#include <mutex>
33#include <string>
34#include <thread>
35
36#ifdef OMPT_SUPPORT
37using namespace llvm::omp::target::ompt;
38#endif
39
40int HostDataToTargetTy::addEventIfNecessary(DeviceTy &Device,
41AsyncInfoTy &AsyncInfo) const {
42// First, check if the user disabled atomic map transfer/malloc/dealloc.
43if (!MappingConfig::get().UseEventsForAtomicTransfers)
44return OFFLOAD_SUCCESS;
45
46void *Event = getEvent();
47bool NeedNewEvent = Event == nullptr;
48if (NeedNewEvent && Device.createEvent(&Event) != OFFLOAD_SUCCESS) {
49REPORT("Failed to create event\n");
50return OFFLOAD_FAIL;
51}
52
53// We cannot assume the event should not be nullptr because we don't
54// know if the target support event. But if a target doesn't,
55// recordEvent should always return success.
56if (Device.recordEvent(Event, AsyncInfo) != OFFLOAD_SUCCESS) {
57REPORT("Failed to set dependence on event " DPxMOD "\n", DPxPTR(Event));
58return OFFLOAD_FAIL;
59}
60
61if (NeedNewEvent)
62setEvent(Event);
63
64return OFFLOAD_SUCCESS;
65}
66
67DeviceTy::DeviceTy(GenericPluginTy *RTL, int32_t DeviceID, int32_t RTLDeviceID)
68: DeviceID(DeviceID), RTL(RTL), RTLDeviceID(RTLDeviceID),
69MappingInfo(*this) {}
70
71DeviceTy::~DeviceTy() {
72if (DeviceID == -1 || !(getInfoLevel() & OMP_INFOTYPE_DUMP_TABLE))
73return;
74
75ident_t Loc = {0, 0, 0, 0, ";libomptarget;libomptarget;0;0;;"};
76dumpTargetPointerMappings(&Loc, *this);
77}
78
79llvm::Error DeviceTy::init() {
80int32_t Ret = RTL->init_device(RTLDeviceID);
81if (Ret != OFFLOAD_SUCCESS)
82return llvm::createStringError(llvm::inconvertibleErrorCode(),
83"Failed to initialize device %d\n",
84DeviceID);
85
86// Enables recording kernels if set.
87BoolEnvar OMPX_RecordKernel("LIBOMPTARGET_RECORD", false);
88if (OMPX_RecordKernel) {
89// Enables saving the device memory kernel output post execution if set.
90BoolEnvar OMPX_ReplaySaveOutput("LIBOMPTARGET_RR_SAVE_OUTPUT", false);
91
92uint64_t ReqPtrArgOffset;
93RTL->initialize_record_replay(RTLDeviceID, 0, nullptr, true,
94OMPX_ReplaySaveOutput, ReqPtrArgOffset);
95}
96
97return llvm::Error::success();
98}
99
100// Load binary to device.
101llvm::Expected<__tgt_device_binary>
102DeviceTy::loadBinary(__tgt_device_image *Img) {
103__tgt_device_binary Binary;
104
105if (RTL->load_binary(RTLDeviceID, Img, &Binary) != OFFLOAD_SUCCESS)
106return llvm::createStringError(llvm::inconvertibleErrorCode(),
107"Failed to load binary %p", Img);
108return Binary;
109}
110
111void *DeviceTy::allocData(int64_t Size, void *HstPtr, int32_t Kind) {
112/// RAII to establish tool anchors before and after data allocation
113void *TargetPtr = nullptr;
114OMPT_IF_BUILT(InterfaceRAII TargetDataAllocRAII(
115RegionInterface.getCallbacks<ompt_target_data_alloc>(),
116DeviceID, HstPtr, &TargetPtr, Size,
117/*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
118
119TargetPtr = RTL->data_alloc(RTLDeviceID, Size, HstPtr, Kind);
120return TargetPtr;
121}
122
123int32_t DeviceTy::deleteData(void *TgtAllocBegin, int32_t Kind) {
124/// RAII to establish tool anchors before and after data deletion
125OMPT_IF_BUILT(InterfaceRAII TargetDataDeleteRAII(
126RegionInterface.getCallbacks<ompt_target_data_delete>(),
127DeviceID, TgtAllocBegin,
128/*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
129
130return RTL->data_delete(RTLDeviceID, TgtAllocBegin, Kind);
131}
132
133// Submit data to device
134int32_t DeviceTy::submitData(void *TgtPtrBegin, void *HstPtrBegin, int64_t Size,
135AsyncInfoTy &AsyncInfo, HostDataToTargetTy *Entry,
136MappingInfoTy::HDTTMapAccessorTy *HDTTMapPtr) {
137if (getInfoLevel() & OMP_INFOTYPE_DATA_TRANSFER)
138MappingInfo.printCopyInfo(TgtPtrBegin, HstPtrBegin, Size, /*H2D=*/true,
139Entry, HDTTMapPtr);
140
141/// RAII to establish tool anchors before and after data submit
142OMPT_IF_BUILT(
143InterfaceRAII TargetDataSubmitRAII(
144RegionInterface.getCallbacks<ompt_target_data_transfer_to_device>(),
145omp_get_initial_device(), HstPtrBegin, DeviceID, TgtPtrBegin, Size,
146/*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
147
148return RTL->data_submit_async(RTLDeviceID, TgtPtrBegin, HstPtrBegin, Size,
149AsyncInfo);
150}
151
152// Retrieve data from device
153int32_t DeviceTy::retrieveData(void *HstPtrBegin, void *TgtPtrBegin,
154int64_t Size, AsyncInfoTy &AsyncInfo,
155HostDataToTargetTy *Entry,
156MappingInfoTy::HDTTMapAccessorTy *HDTTMapPtr) {
157if (getInfoLevel() & OMP_INFOTYPE_DATA_TRANSFER)
158MappingInfo.printCopyInfo(TgtPtrBegin, HstPtrBegin, Size, /*H2D=*/false,
159Entry, HDTTMapPtr);
160
161/// RAII to establish tool anchors before and after data retrieval
162OMPT_IF_BUILT(
163InterfaceRAII TargetDataRetrieveRAII(
164RegionInterface.getCallbacks<ompt_target_data_transfer_from_device>(),
165DeviceID, TgtPtrBegin, omp_get_initial_device(), HstPtrBegin, Size,
166/*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
167
168return RTL->data_retrieve_async(RTLDeviceID, HstPtrBegin, TgtPtrBegin, Size,
169AsyncInfo);
170}
171
172// Copy data from current device to destination device directly
173int32_t DeviceTy::dataExchange(void *SrcPtr, DeviceTy &DstDev, void *DstPtr,
174int64_t Size, AsyncInfoTy &AsyncInfo) {
175/// RAII to establish tool anchors before and after data exchange
176/// Note: Despite the fact that this is a data exchange, we use 'from_device'
177/// operation enum (w.r.t. ompt_target_data_op_t) as there is currently
178/// no better alternative. It is still possible to distinguish this
179/// scenario from a real data retrieve by checking if both involved
180/// device numbers are less than omp_get_num_devices().
181OMPT_IF_BUILT(
182InterfaceRAII TargetDataExchangeRAII(
183RegionInterface.getCallbacks<ompt_target_data_transfer_from_device>(),
184RTLDeviceID, SrcPtr, DstDev.RTLDeviceID, DstPtr, Size,
185/*CodePtr=*/OMPT_GET_RETURN_ADDRESS);)
186if (!AsyncInfo) {
187return RTL->data_exchange(RTLDeviceID, SrcPtr, DstDev.RTLDeviceID, DstPtr,
188Size);
189}
190return RTL->data_exchange_async(RTLDeviceID, SrcPtr, DstDev.RTLDeviceID,
191DstPtr, Size, AsyncInfo);
192}
193
194int32_t DeviceTy::notifyDataMapped(void *HstPtr, int64_t Size) {
195DP("Notifying about new mapping: HstPtr=" DPxMOD ", Size=%" PRId64 "\n",
196DPxPTR(HstPtr), Size);
197
198if (RTL->data_notify_mapped(RTLDeviceID, HstPtr, Size)) {
199REPORT("Notifiying about data mapping failed.\n");
200return OFFLOAD_FAIL;
201}
202return OFFLOAD_SUCCESS;
203}
204
205int32_t DeviceTy::notifyDataUnmapped(void *HstPtr) {
206DP("Notifying about an unmapping: HstPtr=" DPxMOD "\n", DPxPTR(HstPtr));
207
208if (RTL->data_notify_unmapped(RTLDeviceID, HstPtr)) {
209REPORT("Notifiying about data unmapping failed.\n");
210return OFFLOAD_FAIL;
211}
212return OFFLOAD_SUCCESS;
213}
214
215// Run region on device
216int32_t DeviceTy::launchKernel(void *TgtEntryPtr, void **TgtVarsPtr,
217ptrdiff_t *TgtOffsets, KernelArgsTy &KernelArgs,
218AsyncInfoTy &AsyncInfo) {
219return RTL->launch_kernel(RTLDeviceID, TgtEntryPtr, TgtVarsPtr, TgtOffsets,
220&KernelArgs, AsyncInfo);
221}
222
223// Run region on device
224bool DeviceTy::printDeviceInfo() {
225RTL->print_device_info(RTLDeviceID);
226return true;
227}
228
229// Whether data can be copied to DstDevice directly
230bool DeviceTy::isDataExchangable(const DeviceTy &DstDevice) {
231if (RTL != DstDevice.RTL)
232return false;
233
234if (RTL->is_data_exchangable(RTLDeviceID, DstDevice.RTLDeviceID))
235return true;
236return false;
237}
238
239int32_t DeviceTy::synchronize(AsyncInfoTy &AsyncInfo) {
240return RTL->synchronize(RTLDeviceID, AsyncInfo);
241}
242
243int32_t DeviceTy::queryAsync(AsyncInfoTy &AsyncInfo) {
244return RTL->query_async(RTLDeviceID, AsyncInfo);
245}
246
247int32_t DeviceTy::createEvent(void **Event) {
248return RTL->create_event(RTLDeviceID, Event);
249}
250
251int32_t DeviceTy::recordEvent(void *Event, AsyncInfoTy &AsyncInfo) {
252return RTL->record_event(RTLDeviceID, Event, AsyncInfo);
253}
254
255int32_t DeviceTy::waitEvent(void *Event, AsyncInfoTy &AsyncInfo) {
256return RTL->wait_event(RTLDeviceID, Event, AsyncInfo);
257}
258
259int32_t DeviceTy::syncEvent(void *Event) {
260return RTL->sync_event(RTLDeviceID, Event);
261}
262
263int32_t DeviceTy::destroyEvent(void *Event) {
264return RTL->destroy_event(RTLDeviceID, Event);
265}
266
267void DeviceTy::dumpOffloadEntries() {
268fprintf(stderr, "Device %i offload entries:\n", DeviceID);
269for (auto &It : *DeviceOffloadEntries.getExclusiveAccessor()) {
270const char *Kind = "kernel";
271if (It.second.isLink())
272Kind = "link";
273else if (It.second.isGlobal())
274Kind = "global var.";
275fprintf(stderr, " %11s: %s\n", Kind, It.second.getNameAsCStr());
276}
277}
278
279bool DeviceTy::useAutoZeroCopy() {
280if (PM->getRequirements() & OMP_REQ_UNIFIED_SHARED_MEMORY)
281return false;
282return RTL->use_auto_zero_copy(RTLDeviceID);
283}
284