diff --git a/openmp/libomptarget/CMakeLists.txt b/openmp/libomptarget/CMakeLists.txt --- a/openmp/libomptarget/CMakeLists.txt +++ b/openmp/libomptarget/CMakeLists.txt @@ -69,8 +69,24 @@ add_definitions(-DOMPTARGET_DEBUG) endif() +# OMPT support for libomptarget +set(OMPT_TARGET_DEFAULT FALSE) +if ((LIBOMP_HAVE_OMPT_SUPPORT) AND (NOT WIN32)) + set (OMPT_TARGET_DEFAULT TRUE) +endif() +set(LIBOMPTARGET_OMPT_SUPPORT ${OMPT_TARGET_DEFAULT} CACHE BOOL "OMPT-target-support?") +if (LIBOMPTARGET_OMPT_SUPPORT) + add_definitions(-DOMPT_SUPPORT=1) + message(STATUS "OMPT target enabled") +else() + message(STATUS "OMPT target disabled") +endif() + +pythonize_bool(LIBOMPTARGET_OMPT_SUPPORT) + set(LIBOMPTARGET_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) -include_directories(${LIBOMPTARGET_INCLUDE_DIR}) +message(STATUS "OpenMP tools dir in libomptarget: ${LIBOMP_OMP_TOOLS_INCLUDE_DIR}") +include_directories(${LIBOMPTARGET_INCLUDE_DIR} ${LIBOMP_OMP_TOOLS_INCLUDE_DIR}) # Build target agnostic offloading library. set(LIBOMPTARGET_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) diff --git a/openmp/libomptarget/include/ompt-connector.h b/openmp/libomptarget/include/ompt-connector.h new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/include/ompt-connector.h @@ -0,0 +1,89 @@ +//=== ompt-connector.h - Target independent OpenMP target RTL -- C++ ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Support used by OMPT implementation to establish communication between +// various OpenMP runtime libraries: host openmp library, target-independent +// runtime library, and device-dependent runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef _OMPT_CONNECTOR_H +#define _OMPT_CONNECTOR_H + +#include +#include + +#include "Debug.h" +#include "omp-tools.h" +#include "omptarget.h" + +#define LIBOMPTARGET_STRINGIFY(s) #s + +/// Type for the function to be invoked for connecting two libraries. +typedef void (*OmptConnectRtnTy)(ompt_start_tool_result_t *result); + +/// Establish connection between openmp runtime libraries +/// +/// This class is used to communicate between an OMPT implementation in +/// libomptarget and libomp. It is also used to communicate between an +/// OMPT implementation in a device-specific plugin and +/// libomptarget. The decision whether OMPT is enabled or not needs to +/// be made when the library is loaded before any functions in the +/// library are invoked. For that reason, an instance of this class is +/// intended to be defined in the constructor for libomptarget or a +/// plugin so that the decision about whether OMPT is supposed to be +/// enabled is known before any interface function in the library is +/// invoked. +class OmptLibraryConnectorTy { +public: + /// Use \p LibName as the prefix of the global function used for connecting + /// two libraries, the source indicated by \p LibName and the destination + /// being the one that creates this object. + OmptLibraryConnectorTy(const char *LibName) { + LibConnRtn.append(LibName); + LibConnRtn.append("_connect"); + IsInitialized = false; + } + OmptLibraryConnectorTy() = delete; + /// Use \p OmptResult init to connect the two libraries denoted by this + /// object. The init function of \p OmptResult will be used during connection + /// and the fini function of \p OmptResult will be used during teardown. + void connect(ompt_start_tool_result_t *OmptResult) { + initialize(); + if (!LibConnHandle) + return; + // Call the function provided by the source library for connect + LibConnHandle(OmptResult); + } + +private: + void initialize() { + if (IsInitialized) + return; + + DP("OMPT: Library connection routine = %s\n", LibConnRtn.c_str()); + + void *VPtr = dlsym(NULL, LibConnRtn.c_str()); + // If dlsym fails, the handle will be null. connect() checks + // for this condition + LibConnHandle = + reinterpret_cast(reinterpret_cast(VPtr)); + DP("OMPT: Library connection handle = %p\n", LibConnHandle); + IsInitialized = true; + } + +private: + /// Ensure initialization occurs only once + bool IsInitialized; + /// Handle of connect routine provided by source library + OmptConnectRtnTy LibConnHandle; + /// Name of connect routine provided by source library + std::string LibConnRtn; +}; + +#endif diff --git a/openmp/libomptarget/src/CMakeLists.txt b/openmp/libomptarget/src/CMakeLists.txt --- a/openmp/libomptarget/src/CMakeLists.txt +++ b/openmp/libomptarget/src/CMakeLists.txt @@ -18,6 +18,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/interface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/interop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/omptarget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ompt_callback.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rtl.cpp ) diff --git a/openmp/libomptarget/src/ompt_callback.cpp b/openmp/libomptarget/src/ompt_callback.cpp new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/src/ompt_callback.cpp @@ -0,0 +1,75 @@ +//===-- ompt_callback.cpp - Target independent OpenMP target RTL -- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of OMPT callback interfaces for target independent layer +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + +#include "omp-tools.h" +#include "ompt-connector.h" +#include "private.h" + +#define fnptr_to_ptr(x) ((void *)(uint64_t)x) + +/// Used to indicate whether OMPT was enabled for this library +bool ompt_enabled = false; + +#ifdef OMPT_SUPPORT +/// This is the function called by the higher layer (libomp) responsible +/// for initializing OMPT in this library. This is passed to libomp +/// as part of the OMPT connector object. +/// \p lookup to be used to query callbacks registered with libomp +/// \p initial_device_num Initial device num provided by libomp +/// \p tool_data as provided by the tool +static int ompt_libomptarget_initialize(ompt_function_lookup_t lookup, + int initial_device_num, + ompt_data_t *tool_data) { + DP("enter ompt_libomptarget_initialize!\n"); + ompt_enabled = true; + // TODO use the parameters to populate callbacks in libomptarget + DP("exit ompt_libomptarget_initialize!\n"); + return 0; +} + +static void ompt_libomptarget_finalize(ompt_data_t *data) { + DP("enter ompt_libomptarget_finalize!\n"); + ompt_enabled = false; + DP("exit ompt_libomptarget_finalize!\n"); +} + +/***************************************************************************** + * constructor + *****************************************************************************/ +/// Used to initialize callbacks implemented by the tool. This interface +/// will lookup the callbacks table in libomp and assign them to the callbacks +/// maintained in libomptarget. Using priority 102 to have this constructor +/// run after the init target library constructor with priority 101 (see +/// rtl.cpp). +__attribute__((constructor(102))) static void ompt_init(void) { + DP("OMPT: Enter ompt_init\n"); + // Connect with libomp + static OmptLibraryConnectorTy LibompConnector("ompt_libomp"); + static ompt_start_tool_result_t OmptResult; + + // Initialize OmptResult with the init and fini functions that will be + // called by the connector + OmptResult.initialize = ompt_libomptarget_initialize; + OmptResult.finalize = ompt_libomptarget_finalize; + OmptResult.tool_data.value = 0; + + // Now call connect that causes the above init/fini functions to be called + LibompConnector.connect(&OmptResult); + DP("OMPT: Exit ompt_init\n"); +} +#endif diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt --- a/openmp/runtime/CMakeLists.txt +++ b/openmp/runtime/CMakeLists.txt @@ -414,6 +414,7 @@ # make these variables available for tools: set(LIBOMP_LIBRARY_DIR ${LIBOMP_LIBRARY_DIR} PARENT_SCOPE) set(LIBOMP_INCLUDE_DIR ${LIBOMP_INCLUDE_DIR} PARENT_SCOPE) +set(LIBOMP_OMP_TOOLS_INCLUDE_DIR ${LIBOMP_OMP_TOOLS_INCLUDE_DIR} PARENT_SCOPE) # make these variables available for tools/libompd: set(LIBOMP_SRC_DIR ${LIBOMP_SRC_DIR} PARENT_SCOPE) set(LIBOMP_OMPD_SUPPORT ${LIBOMP_OMPD_SUPPORT} PARENT_SCOPE) diff --git a/openmp/runtime/cmake/config-ix.cmake b/openmp/runtime/cmake/config-ix.cmake --- a/openmp/runtime/cmake/config-ix.cmake +++ b/openmp/runtime/cmake/config-ix.cmake @@ -330,6 +330,8 @@ endif() endif() +set(LIBOMP_HAVE_OMPT_SUPPORT ${LIBOMP_HAVE_OMPT_SUPPORT} PARENT_SCOPE) + # Check if HWLOC support is available if(${LIBOMP_USE_HWLOC}) set(CMAKE_REQUIRED_INCLUDES ${LIBOMP_HWLOC_INSTALL_DIR}/include) diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -385,6 +385,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/omp-tools.h DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH}) # install under legacy name ompt.h install(FILES ${CMAKE_CURRENT_BINARY_DIR}/omp-tools.h DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH} RENAME ompt.h) + set(LIBOMP_OMP_TOOLS_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) endif() if(${LIBOMP_FORTRAN_MODULES}) install(FILES diff --git a/openmp/runtime/src/exports_so.txt b/openmp/runtime/src/exports_so.txt --- a/openmp/runtime/src/exports_so.txt +++ b/openmp/runtime/src/exports_so.txt @@ -26,6 +26,7 @@ # OMPT API # ompt_start_tool; # OMPT start interface + ompt_libomp_connect; # OMPT libomptarget interface ompc_*; # omp.h renames some standard functions to ompc_*. kmp_*; # Intel extensions. diff --git a/openmp/runtime/src/ompt-general.cpp b/openmp/runtime/src/ompt-general.cpp --- a/openmp/runtime/src/ompt-general.cpp +++ b/openmp/runtime/src/ompt-general.cpp @@ -110,6 +110,9 @@ #define OMPT_DLCLOSE(Lib) dlclose(Lib) #endif +/// Used to track the initializer and the finalizer provided by libomptarget +static ompt_start_tool_result_t *libomptarget_ompt_result = NULL; + /***************************************************************************** * forward declarations ****************************************************************************/ @@ -456,7 +459,7 @@ if (verbose_init && verbose_file != stderr && verbose_file != stdout) fclose(verbose_file); #if OMPT_DEBUG - printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled); + printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled.enabled); #endif } @@ -509,12 +512,13 @@ } void ompt_fini() { - if (ompt_enabled.enabled -#if OMPD_SUPPORT - && ompt_start_tool_result && ompt_start_tool_result->finalize -#endif - ) { - ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data)); + if (ompt_enabled.enabled) { + if (ompt_start_tool_result && ompt_start_tool_result->finalize) { + ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data)); + } + if (libomptarget_ompt_result && libomptarget_ompt_result->finalize) { + libomptarget_ompt_result->finalize(NULL); + } } if (ompt_tool_module) @@ -869,5 +873,50 @@ FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn) +#undef ompt_interface_fn + return NULL; } + +/// Lookup function to query libomp callbacks registered by the tool +static ompt_interface_fn_t ompt_libomp_target_fn_lookup(const char *s) { +#define ompt_interface_fn(fn, type, code) \ + if (strcmp(s, #fn) == 0) \ + return (ompt_interface_fn_t)ompt_callbacks.ompt_callback(fn); + + FOREACH_OMPT_DEVICE_EVENT(ompt_interface_fn) + FOREACH_OMPT_EMI_EVENT(ompt_interface_fn) + FOREACH_OMPT_NOEMI_EVENT(ompt_interface_fn) + +#undef ompt_interface_fn + + return (ompt_interface_fn_t)0; +} + +/// This function is called by the libomptarget connector to assign +/// callbacks already registered with libomp. +_OMP_EXTERN void ompt_libomp_connect(ompt_start_tool_result_t *result) { + OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Enter libomp_ompt_connect\n"); + + // Ensure libomp callbacks have been added if not already + __ompt_force_initialization(); + + if (ompt_enabled.enabled && + // Callbacks are initiated only if the device initialize callback + // has been registered by the tool + ompt_callbacks.ompt_callback(ompt_callback_device_initialize)) { + if (result) { + OMPT_VERBOSE_INIT_PRINT( + "libomp --> OMPT: Connecting with libomptarget\n"); + // Pass in the libomp lookup function so that the already registered + // functions can be extracted and assigned to the callbacks in + // libomptarget + result->initialize(ompt_libomp_target_fn_lookup, + 0 /* initial_device_num */, nullptr /* tool_data */); + // Track the object provided by libomptarget so that the finalizer can be + // called during OMPT finalization + libomptarget_ompt_result = result; + } + } + OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Exit libomp_ompt_connect\n"); +} diff --git a/openmp/runtime/src/ompt-specific.h b/openmp/runtime/src/ompt-specific.h --- a/openmp/runtime/src/ompt-specific.h +++ b/openmp/runtime/src/ompt-specific.h @@ -20,6 +20,10 @@ * forward declarations ****************************************************************************/ +/// Entrypoint used by libomptarget to register callbacks in libomp, if not +/// done already +void __ompt_force_initialization(); + void __ompt_team_assign_id(kmp_team_t *team, ompt_data_t ompt_pid); void __ompt_thread_assign_wait_id(void *variable); diff --git a/openmp/runtime/src/ompt-specific.cpp b/openmp/runtime/src/ompt-specific.cpp --- a/openmp/runtime/src/ompt-specific.cpp +++ b/openmp/runtime/src/ompt-specific.cpp @@ -188,6 +188,11 @@ //****************************************************************************** // interface operations //****************************************************************************** +//---------------------------------------------------------- +// initialization support +//---------------------------------------------------------- + +void __ompt_force_initialization() { __kmp_serial_initialize(); } //---------------------------------------------------------- // thread support