1 //===-- OmptCallback.cpp - Target independent OpenMP target RTL --- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Implementation of OMPT callback interfaces for target independent layer
11 //===----------------------------------------------------------------------===//
15 #include "llvm/Support/DynamicLibrary.h"
22 #include "OmptCallback.h"
23 #include "OmptConnector.h"
24 #include "OmptInterface.h"
27 #define DEBUG_PREFIX "OMPT"
29 using namespace llvm::omp::target::ompt
;
31 // Define OMPT callback functions (bound to actual callbacks later on)
32 #define defineOmptCallback(Name, Type, Code) \
33 Name##_t llvm::omp::target::ompt::Name##_fn = nullptr;
34 FOREACH_OMPT_NOEMI_EVENT(defineOmptCallback
)
35 FOREACH_OMPT_EMI_EVENT(defineOmptCallback
)
36 #undef defineOmptCallback
38 /// Forward declaration
39 class LibomptargetRtlFinalizer
;
41 /// Object that will maintain the RTL finalizer from the plugin
42 LibomptargetRtlFinalizer
*LibraryFinalizer
= nullptr;
44 thread_local Interface
llvm::omp::target::ompt::RegionInterface
;
46 bool llvm::omp::target::ompt::Initialized
= false;
48 ompt_get_callback_t
llvm::omp::target::ompt::lookupCallbackByCode
= nullptr;
49 ompt_function_lookup_t
llvm::omp::target::ompt::lookupCallbackByName
= nullptr;
50 ompt_get_target_task_data_t ompt_get_target_task_data_fn
= nullptr;
51 ompt_get_task_data_t ompt_get_task_data_fn
= nullptr;
53 /// Unique correlation id
54 static std::atomic
<uint64_t> IdCounter(1);
56 /// Used to create a new correlation id
57 static uint64_t createId() { return IdCounter
.fetch_add(1); }
59 /// Create a new correlation id and update the operations id
60 static uint64_t createOpId() {
61 uint64_t NewId
= createId();
62 RegionInterface
.setHostOpId(NewId
);
66 /// Create a new correlation id and update the target region id
67 static uint64_t createRegionId() {
68 uint64_t NewId
= createId();
69 RegionInterface
.setTargetDataValue(NewId
);
73 void Interface::beginTargetDataAlloc(int64_t DeviceId
, void *HstPtrBegin
,
74 void **TgtPtrBegin
, size_t Size
,
76 beginTargetDataOperation();
77 if (ompt_callback_target_data_op_emi_fn
) {
78 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
80 ompt_callback_target_data_op_emi_fn(
81 ompt_scope_begin
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
82 ompt_target_data_alloc
, HstPtrBegin
,
83 /* SrcDeviceNum */ omp_get_initial_device(), *TgtPtrBegin
,
84 /* TgtDeviceNum */ DeviceId
, Size
, Code
);
85 } else if (ompt_callback_target_data_op_fn
) {
86 // HostOpId is set by the runtime
87 HostOpId
= createOpId();
88 // Invoke the tool supplied data op callback
89 ompt_callback_target_data_op_fn(
90 TargetData
.value
, HostOpId
, ompt_target_data_alloc
, HstPtrBegin
,
91 /* SrcDeviceNum */ omp_get_initial_device(), *TgtPtrBegin
,
92 /* TgtDeviceNum */ DeviceId
, Size
, Code
);
96 void Interface::endTargetDataAlloc(int64_t DeviceId
, void *HstPtrBegin
,
97 void **TgtPtrBegin
, size_t Size
,
99 // Only EMI callback handles end scope
100 if (ompt_callback_target_data_op_emi_fn
) {
101 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
103 ompt_callback_target_data_op_emi_fn(
104 ompt_scope_end
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
105 ompt_target_data_alloc
, HstPtrBegin
,
106 /* SrcDeviceNum */ omp_get_initial_device(), *TgtPtrBegin
,
107 /* TgtDeviceNum */ DeviceId
, Size
, Code
);
109 endTargetDataOperation();
112 void Interface::beginTargetDataSubmit(int64_t DeviceId
, void *TgtPtrBegin
,
113 void *HstPtrBegin
, size_t Size
,
115 beginTargetDataOperation();
116 if (ompt_callback_target_data_op_emi_fn
) {
117 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
119 ompt_callback_target_data_op_emi_fn(
120 ompt_scope_begin
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
121 ompt_target_data_transfer_to_device
, HstPtrBegin
,
122 /* SrcDeviceNum */ omp_get_initial_device(), TgtPtrBegin
, DeviceId
,
124 } else if (ompt_callback_target_data_op_fn
) {
125 // HostOpId is set by the runtime
126 HostOpId
= createOpId();
127 // Invoke the tool supplied data op callback
128 ompt_callback_target_data_op_fn(
129 TargetData
.value
, HostOpId
, ompt_target_data_transfer_to_device
,
130 HstPtrBegin
, /* SrcDeviceNum */ omp_get_initial_device(), TgtPtrBegin
,
131 DeviceId
, Size
, Code
);
135 void Interface::endTargetDataSubmit(int64_t DeviceId
, void *TgtPtrBegin
,
136 void *HstPtrBegin
, size_t Size
,
138 // Only EMI callback handles end scope
139 if (ompt_callback_target_data_op_emi_fn
) {
140 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
142 ompt_callback_target_data_op_emi_fn(
143 ompt_scope_end
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
144 ompt_target_data_transfer_to_device
, HstPtrBegin
,
145 /* SrcDeviceNum */ omp_get_initial_device(), TgtPtrBegin
, DeviceId
,
148 endTargetDataOperation();
151 void Interface::beginTargetDataDelete(int64_t DeviceId
, void *TgtPtrBegin
,
153 beginTargetDataOperation();
154 if (ompt_callback_target_data_op_emi_fn
) {
155 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
157 ompt_callback_target_data_op_emi_fn(
158 ompt_scope_begin
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
159 ompt_target_data_delete
, TgtPtrBegin
, DeviceId
,
160 /* TgtPtrBegin */ nullptr, /* TgtDeviceNum */ -1, /* Bytes */ 0, Code
);
161 } else if (ompt_callback_target_data_op_fn
) {
162 // HostOpId is set by the runtime
163 HostOpId
= createOpId();
164 // Invoke the tool supplied data op callback
165 ompt_callback_target_data_op_fn(TargetData
.value
, HostOpId
,
166 ompt_target_data_delete
, TgtPtrBegin
,
167 DeviceId
, /* TgtPtrBegin */ nullptr,
168 /* TgtDeviceNum */ -1, /* Bytes */ 0, Code
);
172 void Interface::endTargetDataDelete(int64_t DeviceId
, void *TgtPtrBegin
,
174 // Only EMI callback handles end scope
175 if (ompt_callback_target_data_op_emi_fn
) {
176 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
178 ompt_callback_target_data_op_emi_fn(
179 ompt_scope_end
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
180 ompt_target_data_delete
, TgtPtrBegin
, DeviceId
,
181 /* TgtPtrBegin */ nullptr, /* TgtDeviceNum */ -1, /* Bytes */ 0, Code
);
183 endTargetDataOperation();
186 void Interface::beginTargetDataRetrieve(int64_t DeviceId
, void *HstPtrBegin
,
187 void *TgtPtrBegin
, size_t Size
,
189 beginTargetDataOperation();
190 if (ompt_callback_target_data_op_emi_fn
) {
191 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
193 ompt_callback_target_data_op_emi_fn(
194 ompt_scope_begin
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
195 ompt_target_data_transfer_from_device
, TgtPtrBegin
, DeviceId
,
197 /* TgtDeviceNum */ omp_get_initial_device(), Size
, Code
);
198 } else if (ompt_callback_target_data_op_fn
) {
199 // HostOpId is set by the runtime
200 HostOpId
= createOpId();
201 // Invoke the tool supplied data op callback
202 ompt_callback_target_data_op_fn(
203 TargetData
.value
, HostOpId
, ompt_target_data_transfer_from_device
,
204 TgtPtrBegin
, DeviceId
, HstPtrBegin
,
205 /* TgtDeviceNum */ omp_get_initial_device(), Size
, Code
);
209 void Interface::endTargetDataRetrieve(int64_t DeviceId
, void *HstPtrBegin
,
210 void *TgtPtrBegin
, size_t Size
,
212 // Only EMI callback handles end scope
213 if (ompt_callback_target_data_op_emi_fn
) {
214 // HostOpId will be set by the tool. Invoke the tool supplied data op EMI
216 ompt_callback_target_data_op_emi_fn(
217 ompt_scope_end
, TargetTaskData
, &TargetData
, &TargetRegionOpId
,
218 ompt_target_data_transfer_from_device
, TgtPtrBegin
, DeviceId
,
220 /* TgtDeviceNum */ omp_get_initial_device(), Size
, Code
);
222 endTargetDataOperation();
225 void Interface::beginTargetSubmit(unsigned int numTeams
) {
226 if (ompt_callback_target_submit_emi_fn
) {
227 // HostOpId is set by the tool. Invoke the tool supplied target submit EMI
229 ompt_callback_target_submit_emi_fn(ompt_scope_begin
, &TargetData
, &HostOpId
,
231 } else if (ompt_callback_target_submit_fn
) {
232 // HostOpId is set by the runtime
233 HostOpId
= createOpId();
234 ompt_callback_target_submit_fn(TargetData
.value
, HostOpId
, numTeams
);
238 void Interface::endTargetSubmit(unsigned int numTeams
) {
239 // Only EMI callback handles end scope
240 if (ompt_callback_target_submit_emi_fn
) {
241 // HostOpId is set by the tool. Invoke the tool supplied target submit EMI
243 ompt_callback_target_submit_emi_fn(ompt_scope_end
, &TargetData
, &HostOpId
,
248 void Interface::beginTargetDataEnter(int64_t DeviceId
, void *Code
) {
250 if (ompt_callback_target_emi_fn
) {
251 // Invoke the tool supplied target EMI callback
252 ompt_callback_target_emi_fn(ompt_target_enter_data
, ompt_scope_begin
,
253 DeviceId
, TaskData
, TargetTaskData
, &TargetData
,
255 } else if (ompt_callback_target_fn
) {
256 // Invoke the tool supplied target callback
257 ompt_callback_target_fn(ompt_target_enter_data
, ompt_scope_begin
, DeviceId
,
258 TaskData
, TargetData
.value
, Code
);
262 void Interface::endTargetDataEnter(int64_t DeviceId
, void *Code
) {
263 if (ompt_callback_target_emi_fn
) {
264 // Invoke the tool supplied target EMI callback
265 ompt_callback_target_emi_fn(ompt_target_enter_data
, ompt_scope_end
,
266 DeviceId
, TaskData
, TargetTaskData
, &TargetData
,
268 } else if (ompt_callback_target_fn
) {
269 // Invoke the tool supplied target callback
270 ompt_callback_target_fn(ompt_target_enter_data
, ompt_scope_end
, DeviceId
,
271 TaskData
, TargetData
.value
, Code
);
276 void Interface::beginTargetDataExit(int64_t DeviceId
, void *Code
) {
278 if (ompt_callback_target_emi_fn
) {
279 // Invoke the tool supplied target EMI callback
280 ompt_callback_target_emi_fn(ompt_target_exit_data
, ompt_scope_begin
,
281 DeviceId
, TaskData
, TargetTaskData
, &TargetData
,
283 } else if (ompt_callback_target_fn
) {
284 TargetData
.value
= createRegionId();
285 // Invoke the tool supplied target callback
286 ompt_callback_target_fn(ompt_target_exit_data
, ompt_scope_begin
, DeviceId
,
287 TaskData
, TargetData
.value
, Code
);
291 void Interface::endTargetDataExit(int64_t DeviceId
, void *Code
) {
292 if (ompt_callback_target_emi_fn
) {
293 // Invoke the tool supplied target EMI callback
294 ompt_callback_target_emi_fn(ompt_target_exit_data
, ompt_scope_end
, DeviceId
,
295 TaskData
, TargetTaskData
, &TargetData
, Code
);
296 } else if (ompt_callback_target_fn
) {
297 // Invoke the tool supplied target callback
298 ompt_callback_target_fn(ompt_target_exit_data
, ompt_scope_end
, DeviceId
,
299 TaskData
, TargetData
.value
, Code
);
304 void Interface::beginTargetUpdate(int64_t DeviceId
, void *Code
) {
306 if (ompt_callback_target_emi_fn
) {
307 // Invoke the tool supplied target EMI callback
308 ompt_callback_target_emi_fn(ompt_target_update
, ompt_scope_begin
, DeviceId
,
309 TaskData
, TargetTaskData
, &TargetData
, Code
);
310 } else if (ompt_callback_target_fn
) {
311 TargetData
.value
= createRegionId();
312 // Invoke the tool supplied target callback
313 ompt_callback_target_fn(ompt_target_update
, ompt_scope_begin
, DeviceId
,
314 TaskData
, TargetData
.value
, Code
);
318 void Interface::endTargetUpdate(int64_t DeviceId
, void *Code
) {
319 if (ompt_callback_target_emi_fn
) {
320 // Invoke the tool supplied target EMI callback
321 ompt_callback_target_emi_fn(ompt_target_update
, ompt_scope_end
, DeviceId
,
322 TaskData
, TargetTaskData
, &TargetData
, Code
);
323 } else if (ompt_callback_target_fn
) {
324 // Invoke the tool supplied target callback
325 ompt_callback_target_fn(ompt_target_update
, ompt_scope_end
, DeviceId
,
326 TaskData
, TargetData
.value
, Code
);
331 void Interface::beginTarget(int64_t DeviceId
, void *Code
) {
333 if (ompt_callback_target_emi_fn
) {
334 // Invoke the tool supplied target EMI callback
335 ompt_callback_target_emi_fn(ompt_target
, ompt_scope_begin
, DeviceId
,
336 TaskData
, TargetTaskData
, &TargetData
, Code
);
337 } else if (ompt_callback_target_fn
) {
338 TargetData
.value
= createRegionId();
339 // Invoke the tool supplied target callback
340 ompt_callback_target_fn(ompt_target
, ompt_scope_begin
, DeviceId
, TaskData
,
341 TargetData
.value
, Code
);
345 void Interface::endTarget(int64_t DeviceId
, void *Code
) {
346 if (ompt_callback_target_emi_fn
) {
347 // Invoke the tool supplied target EMI callback
348 ompt_callback_target_emi_fn(ompt_target
, ompt_scope_end
, DeviceId
, TaskData
,
349 TargetTaskData
, &TargetData
, Code
);
350 } else if (ompt_callback_target_fn
) {
351 // Invoke the tool supplied target callback
352 ompt_callback_target_fn(ompt_target
, ompt_scope_end
, DeviceId
, TaskData
,
353 TargetData
.value
, Code
);
358 void Interface::beginTargetDataOperation() {
359 DP("in ompt_target_region_begin (TargetRegionOpId = %lu)\n",
363 void Interface::endTargetDataOperation() {
364 DP("in ompt_target_region_end (TargetRegionOpId = %lu)\n", TargetData
.value
);
367 void Interface::beginTargetRegion() {
369 assert(ompt_get_task_data_fn
&& "Calling a null task data function");
370 TaskData
= ompt_get_task_data_fn();
371 // Set up target task state
372 assert(ompt_get_target_task_data_fn
&&
373 "Calling a null target task data function");
374 TargetTaskData
= ompt_get_target_task_data_fn();
375 // Target state will be set later
376 TargetData
= ompt_data_none
;
379 void Interface::endTargetRegion() {
382 TargetData
= ompt_data_none
;
385 /// Used to maintain the finalization functions that are received
386 /// from the plugins during connect.
387 /// Note: Currently, there are no plugin-specific finalizations, so each plugin
388 /// will call the same (empty) function.
389 class LibomptargetRtlFinalizer
{
391 LibomptargetRtlFinalizer() {}
393 void registerRtl(ompt_finalize_t FinalizationFunction
) {
394 if (FinalizationFunction
) {
395 RtlFinalizationFunctions
.emplace_back(FinalizationFunction
);
400 for (auto FinalizationFunction
: RtlFinalizationFunctions
)
401 FinalizationFunction(/* tool_data */ nullptr);
402 RtlFinalizationFunctions
.clear();
406 llvm::SmallVector
<ompt_finalize_t
> RtlFinalizationFunctions
;
409 int llvm::omp::target::ompt::initializeLibrary(ompt_function_lookup_t lookup
,
410 int initial_device_num
,
411 ompt_data_t
*tool_data
) {
412 DP("Executing initializeLibrary (libomp)\n");
413 #define bindOmptFunctionName(OmptFunction, DestinationFunction) \
414 DestinationFunction = (OmptFunction##_t)lookup(#OmptFunction); \
415 DP("initializeLibrary (libomp) bound %s=%p\n", #DestinationFunction, \
416 ((void *)(uint64_t)DestinationFunction));
418 bindOmptFunctionName(ompt_get_callback
, lookupCallbackByCode
);
419 bindOmptFunctionName(ompt_get_task_data
, ompt_get_task_data_fn
);
420 bindOmptFunctionName(ompt_get_target_task_data
, ompt_get_target_task_data_fn
);
421 #undef bindOmptFunctionName
423 // Store pointer of 'ompt_libomp_target_fn_lookup' for use by libomptarget
424 lookupCallbackByName
= lookup
;
426 assert(lookupCallbackByCode
&& "lookupCallbackByCode should be non-null");
427 assert(lookupCallbackByName
&& "lookupCallbackByName should be non-null");
428 assert(ompt_get_task_data_fn
&& "ompt_get_task_data_fn should be non-null");
429 assert(ompt_get_target_task_data_fn
&&
430 "ompt_get_target_task_data_fn should be non-null");
431 assert(LibraryFinalizer
== nullptr &&
432 "LibraryFinalizer should not be initialized yet");
434 LibraryFinalizer
= new LibomptargetRtlFinalizer();
441 void llvm::omp::target::ompt::finalizeLibrary(ompt_data_t
*data
) {
442 DP("Executing finalizeLibrary (libomp)\n");
443 // Before disabling OMPT, call the (plugin) finalizations that were registered
445 LibraryFinalizer
->finalize();
446 delete LibraryFinalizer
;
450 void llvm::omp::target::ompt::connectLibrary() {
451 DP("Entering connectLibrary (libomp)\n");
452 // Connect with libomp
453 static OmptLibraryConnectorTy
LibompConnector("libomp");
454 static ompt_start_tool_result_t OmptResult
;
456 // Initialize OmptResult with the init and fini functions that will be
457 // called by the connector
458 OmptResult
.initialize
= ompt::initializeLibrary
;
459 OmptResult
.finalize
= ompt::finalizeLibrary
;
460 OmptResult
.tool_data
.value
= 0;
462 // Now call connect that causes the above init/fini functions to be called
463 LibompConnector
.connect(&OmptResult
);
465 #define bindOmptCallback(Name, Type, Code) \
466 if (lookupCallbackByCode) \
467 lookupCallbackByCode( \
468 (ompt_callbacks_t)(Code), \
469 (ompt_callback_t *)&(llvm::omp::target::ompt::Name##_fn));
470 FOREACH_OMPT_NOEMI_EVENT(bindOmptCallback
)
471 FOREACH_OMPT_EMI_EVENT(bindOmptCallback
)
472 #undef bindOmptCallback
474 DP("Exiting connectLibrary (libomp)\n");
478 /// Used for connecting libomptarget with a plugin
479 void ompt_libomptarget_connect(ompt_start_tool_result_t
*result
) {
480 DP("Enter ompt_libomptarget_connect\n");
481 if (Initialized
&& result
&& LibraryFinalizer
) {
482 // Cache each fini function, so that they can be invoked on exit
483 LibraryFinalizer
->registerRtl(result
->finalize
);
484 // Invoke the provided init function with the lookup function maintained
485 // in this library so that callbacks maintained by this library are
487 result
->initialize(lookupCallbackByName
,
488 /* initial_device_num */ 0, /* tool_data */ nullptr);
490 DP("Leave ompt_libomptarget_connect\n");
495 /// Dummy definition when OMPT is disabled
496 void ompt_libomptarget_connect() {}
498 #endif // OMPT_SUPPORT