diff --git a/openmp/libomptarget/include/PluginManager.h b/openmp/libomptarget/include/PluginManager.h index 6a91e245453c8..3a1c97fc52c95 100644 --- a/openmp/libomptarget/include/PluginManager.h +++ b/openmp/libomptarget/include/PluginManager.h @@ -14,6 +14,7 @@ #define OMPTARGET_PLUGIN_MANAGER_H #include "Shared/APITypes.h" +#include "Shared/PluginAPI.h" #include "device.h" @@ -25,49 +26,6 @@ #include struct PluginAdaptorTy { - typedef int32_t(init_plugin_ty)(); - typedef int32_t(is_valid_binary_ty)(void *); - typedef int32_t(is_valid_binary_info_ty)(void *, void *); - typedef int32_t(is_data_exchangable_ty)(int32_t, int32_t); - typedef int32_t(number_of_devices_ty)(); - typedef int32_t(init_device_ty)(int32_t); - typedef __tgt_target_table *(load_binary_ty)(int32_t, void *); - typedef void *(data_alloc_ty)(int32_t, int64_t, void *, int32_t); - typedef int32_t(data_submit_ty)(int32_t, void *, void *, int64_t); - typedef int32_t(data_submit_async_ty)(int32_t, void *, void *, int64_t, - __tgt_async_info *); - typedef int32_t(data_retrieve_ty)(int32_t, void *, void *, int64_t); - typedef int32_t(data_retrieve_async_ty)(int32_t, void *, void *, int64_t, - __tgt_async_info *); - typedef int32_t(data_exchange_ty)(int32_t, void *, int32_t, void *, int64_t); - typedef int32_t(data_exchange_async_ty)(int32_t, void *, int32_t, void *, - int64_t, __tgt_async_info *); - typedef int32_t(data_delete_ty)(int32_t, void *, int32_t); - typedef int32_t(launch_kernel_ty)(int32_t, void *, void **, ptrdiff_t *, - const KernelArgsTy *, __tgt_async_info *); - typedef int64_t(init_requires_ty)(int64_t); - typedef int32_t(synchronize_ty)(int32_t, __tgt_async_info *); - typedef int32_t(query_async_ty)(int32_t, __tgt_async_info *); - typedef int32_t(supports_empty_images_ty)(); - typedef void(print_device_info_ty)(int32_t); - typedef void(set_info_flag_ty)(uint32_t); - typedef int32_t(create_event_ty)(int32_t, void **); - typedef int32_t(record_event_ty)(int32_t, void *, __tgt_async_info *); - typedef int32_t(wait_event_ty)(int32_t, void *, __tgt_async_info *); - typedef int32_t(sync_event_ty)(int32_t, void *); - typedef int32_t(destroy_event_ty)(int32_t, void *); - typedef int32_t(release_async_info_ty)(int32_t, __tgt_async_info *); - typedef int32_t(init_async_info_ty)(int32_t, __tgt_async_info **); - typedef int64_t(init_device_into_ty)(int64_t, __tgt_device_info *, - const char **); - typedef int32_t(data_lock_ty)(int32_t, void *, int64_t, void **); - typedef int32_t(data_unlock_ty)(int32_t, void *); - typedef int32_t(data_notify_mapped_ty)(int32_t, void *, int64_t); - typedef int32_t(data_notify_unmapped_ty)(int32_t, void *); - typedef int32_t(set_device_offset_ty)(int32_t); - typedef int32_t(activate_record_replay_ty)(int32_t, uint64_t, void *, bool, - bool, uint64_t &); - int32_t Idx = -1; // RTL index, index is the number of devices // of other RTLs that were registered before, // i.e. the OpenMP index of the first device @@ -80,43 +38,12 @@ struct PluginAdaptorTy { std::string RTLName; #endif - // Functions implemented in the RTL. - init_plugin_ty *init_plugin = nullptr; - is_valid_binary_ty *is_valid_binary = nullptr; - is_valid_binary_info_ty *is_valid_binary_info = nullptr; - is_data_exchangable_ty *is_data_exchangable = nullptr; - number_of_devices_ty *number_of_devices = nullptr; - init_device_ty *init_device = nullptr; - load_binary_ty *load_binary = nullptr; - data_alloc_ty *data_alloc = nullptr; - data_submit_ty *data_submit = nullptr; - data_submit_async_ty *data_submit_async = nullptr; - data_retrieve_ty *data_retrieve = nullptr; - data_retrieve_async_ty *data_retrieve_async = nullptr; - data_exchange_ty *data_exchange = nullptr; - data_exchange_async_ty *data_exchange_async = nullptr; - data_delete_ty *data_delete = nullptr; - launch_kernel_ty *launch_kernel = nullptr; - init_requires_ty *init_requires = nullptr; - synchronize_ty *synchronize = nullptr; - query_async_ty *query_async = nullptr; - supports_empty_images_ty *supports_empty_images = nullptr; - set_info_flag_ty *set_info_flag = nullptr; - print_device_info_ty *print_device_info = nullptr; - create_event_ty *create_event = nullptr; - record_event_ty *record_event = nullptr; - wait_event_ty *wait_event = nullptr; - sync_event_ty *sync_event = nullptr; - destroy_event_ty *destroy_event = nullptr; - init_async_info_ty *init_async_info = nullptr; - init_device_into_ty *init_device_info = nullptr; - release_async_info_ty *release_async_info = nullptr; - data_lock_ty *data_lock = nullptr; - data_unlock_ty *data_unlock = nullptr; - data_notify_mapped_ty *data_notify_mapped = nullptr; - data_notify_unmapped_ty *data_notify_unmapped = nullptr; - set_device_offset_ty *set_device_offset = nullptr; - activate_record_replay_ty *activate_record_replay = nullptr; +#define PLUGIN_API_HANDLE(NAME, MANDATORY) \ + using NAME##_ty = decltype(__tgt_rtl_##NAME); \ + NAME##_ty *NAME = nullptr; + +#include "Shared/PluginAPI.inc" +#undef PLUGIN_API_HANDLE // Are there images associated with this RTL. bool IsUsed = false; diff --git a/openmp/libomptarget/include/Shared/APITypes.h b/openmp/libomptarget/include/Shared/APITypes.h index fc494cd5f5865..8e2aee2deb295 100644 --- a/openmp/libomptarget/include/Shared/APITypes.h +++ b/openmp/libomptarget/include/Shared/APITypes.h @@ -86,6 +86,32 @@ struct __tgt_async_info { /// happening. KernelLaunchEnvironmentTy KernelLaunchEnvironment; }; + +/// This struct contains all of the arguments to a target kernel region launch. +struct KernelArgsTy { + uint32_t Version; // Version of this struct for ABI compatibility. + uint32_t NumArgs; // Number of arguments in each input pointer. + void **ArgBasePtrs; // Base pointer of each argument (e.g. a struct). + void **ArgPtrs; // Pointer to the argument data. + int64_t *ArgSizes; // Size of the argument data in bytes. + int64_t *ArgTypes; // Type of the data (e.g. to / from). + void **ArgNames; // Name of the data for debugging, possibly null. + void **ArgMappers; // User-defined mappers, possibly null. + uint64_t Tripcount; // Tripcount for the teams / distribute loop, 0 otherwise. + struct { + uint64_t NoWait : 1; // Was this kernel spawned with a `nowait` clause. + uint64_t Unused : 63; + } Flags; + uint32_t NumTeams[3]; // The number of teams (for x,y,z dimension). + uint32_t ThreadLimit[3]; // The number of threads (for x,y,z dimension). + uint32_t DynCGroupMem; // Amount of dynamic cgroup memory requested. +}; +static_assert(sizeof(KernelArgsTy().Flags) == sizeof(uint64_t), + "Invalid struct size"); +static_assert(sizeof(KernelArgsTy) == + (8 * sizeof(int32_t) + 3 * sizeof(int64_t) + + 4 * sizeof(void **) + 2 * sizeof(int64_t *)), + "Invalid struct size"); } #endif // OMPTARGET_SHARED_API_TYPES_H diff --git a/openmp/libomptarget/include/Shared/PluginAPI.h b/openmp/libomptarget/include/Shared/PluginAPI.h index 94beab2dcea19..41d1908da2153 100644 --- a/openmp/libomptarget/include/Shared/PluginAPI.h +++ b/openmp/libomptarget/include/Shared/PluginAPI.h @@ -215,6 +215,16 @@ int32_t __tgt_rtl_data_notify_unmapped(int32_t ID, void *HstPtr); // Set the global device identifier offset, such that the plugin may determine a // unique device number. int32_t __tgt_rtl_set_device_offset(int32_t DeviceIdOffset); + +int32_t __tgt_rtl_launch_kernel(int32_t DeviceId, void *TgtEntryPtr, + void **TgtArgs, ptrdiff_t *TgtOffsets, + KernelArgsTy *KernelArgs, + __tgt_async_info *AsyncInfoPtr); + +int32_t __tgt_rtl_initialize_record_replay(int32_t DeviceId, int64_t MemorySize, + void *VAddr, bool isRecord, + bool SaveOutput, + uint64_t &ReqPtrArgOffset); } #endif // OMPTARGET_SHARED_PLUGIN_API_H diff --git a/openmp/libomptarget/include/Shared/PluginAPI.inc b/openmp/libomptarget/include/Shared/PluginAPI.inc new file mode 100644 index 0000000000000..0949e4e593dde --- /dev/null +++ b/openmp/libomptarget/include/Shared/PluginAPI.inc @@ -0,0 +1,50 @@ +//===-- Shared/PluginAPI.inc - Target independent plugin API ----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the names of the interface functions between target +// independent offload runtime library and target dependent plugins. +// +//===----------------------------------------------------------------------===// + +// No include guards! + +PLUGIN_API_HANDLE(init_plugin, true); +PLUGIN_API_HANDLE(is_valid_binary, true); +PLUGIN_API_HANDLE(is_valid_binary_info, false); +PLUGIN_API_HANDLE(is_data_exchangable, false); +PLUGIN_API_HANDLE(number_of_devices, true); +PLUGIN_API_HANDLE(init_device, true); +PLUGIN_API_HANDLE(load_binary, true); +PLUGIN_API_HANDLE(data_alloc, true); +PLUGIN_API_HANDLE(data_submit, true); +PLUGIN_API_HANDLE(data_submit_async, false); +PLUGIN_API_HANDLE(data_retrieve, true); +PLUGIN_API_HANDLE(data_retrieve_async, false); +PLUGIN_API_HANDLE(data_exchange, false); +PLUGIN_API_HANDLE(data_exchange_async, false); +PLUGIN_API_HANDLE(data_delete, true); +PLUGIN_API_HANDLE(launch_kernel, true); +PLUGIN_API_HANDLE(init_requires, false); +PLUGIN_API_HANDLE(synchronize, false); +PLUGIN_API_HANDLE(query_async, false); +PLUGIN_API_HANDLE(supports_empty_images, false); +PLUGIN_API_HANDLE(set_info_flag, false); +PLUGIN_API_HANDLE(print_device_info, false); +PLUGIN_API_HANDLE(create_event, false); +PLUGIN_API_HANDLE(record_event, false); +PLUGIN_API_HANDLE(wait_event, false); +PLUGIN_API_HANDLE(sync_event, false); +PLUGIN_API_HANDLE(destroy_event, false); +PLUGIN_API_HANDLE(init_async_info, false); +PLUGIN_API_HANDLE(init_device_info, false); +PLUGIN_API_HANDLE(data_lock, false); +PLUGIN_API_HANDLE(data_unlock, false); +PLUGIN_API_HANDLE(data_notify_mapped, false); +PLUGIN_API_HANDLE(data_notify_unmapped, false); +PLUGIN_API_HANDLE(set_device_offset, false); +PLUGIN_API_HANDLE(initialize_record_replay, false); diff --git a/openmp/libomptarget/include/device.h b/openmp/libomptarget/include/device.h index 5e58879bd738b..8d253df19215e 100644 --- a/openmp/libomptarget/include/device.h +++ b/openmp/libomptarget/include/device.h @@ -150,7 +150,7 @@ struct DeviceTy { // calls to RTL int32_t initOnce(); - __tgt_target_table *loadBinary(void *Img); + __tgt_target_table *loadBinary(__tgt_device_image *Img); // device memory allocation/deallocation routines /// Allocates \p Size bytes on the device, host or shared memory space @@ -192,7 +192,7 @@ struct DeviceTy { // Launch the kernel identified by \p TgtEntryPtr with the given arguments. int32_t launchKernel(void *TgtEntryPtr, void **TgtVarsPtr, - ptrdiff_t *TgtOffsets, const KernelArgsTy &KernelArgs, + ptrdiff_t *TgtOffsets, KernelArgsTy &KernelArgs, AsyncInfoTy &AsyncInfo); /// Synchronize device/queue/event based on \p AsyncInfo and return diff --git a/openmp/libomptarget/include/omptarget.h b/openmp/libomptarget/include/omptarget.h index 45fb40c397afe..829e000f4fb3a 100644 --- a/openmp/libomptarget/include/omptarget.h +++ b/openmp/libomptarget/include/omptarget.h @@ -121,29 +121,6 @@ enum TargetAllocTy : int32_t { TARGET_ALLOC_DEFAULT }; -/// This struct contains all of the arguments to a target kernel region launch. -struct KernelArgsTy { - uint32_t Version; // Version of this struct for ABI compatibility. - uint32_t NumArgs; // Number of arguments in each input pointer. - void **ArgBasePtrs; // Base pointer of each argument (e.g. a struct). - void **ArgPtrs; // Pointer to the argument data. - int64_t *ArgSizes; // Size of the argument data in bytes. - int64_t *ArgTypes; // Type of the data (e.g. to / from). - void **ArgNames; // Name of the data for debugging, possibly null. - void **ArgMappers; // User-defined mappers, possibly null. - uint64_t Tripcount; // Tripcount for the teams / distribute loop, 0 otherwise. - struct { - uint64_t NoWait : 1; // Was this kernel spawned with a `nowait` clause. - uint64_t Unused : 63; - } Flags; - uint32_t NumTeams[3]; // The number of teams (for x,y,z dimension). - uint32_t ThreadLimit[3]; // The number of threads (for x,y,z dimension). - uint32_t DynCGroupMem; // Amount of dynamic cgroup memory requested. -}; -static_assert(sizeof(KernelArgsTy().Flags) == sizeof(uint64_t), - "Invalid struct size"); -static_assert(sizeof(KernelArgsTy) == (8 * sizeof(int32_t) + 3 * sizeof(int64_t) + 4 * sizeof(void**) + 2 * sizeof(int64_t*)), - "Invalid struct size"); inline KernelArgsTy CTorDTorKernelArgs = {1, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 0, {0,0}, {1, 0, 0}, {1, 0, 0}, 0}; diff --git a/openmp/libomptarget/src/device.cpp b/openmp/libomptarget/src/device.cpp index 8e292eb7b4fdc..2431d7c073352 100644 --- a/openmp/libomptarget/src/device.cpp +++ b/openmp/libomptarget/src/device.cpp @@ -542,8 +542,8 @@ void DeviceTy::init() { "LIBOMPTARGET_RR_SAVE_OUTPUT", false); uint64_t ReqPtrArgOffset; - RTL->activate_record_replay(RTLDeviceID, 0, nullptr, true, - OMPX_ReplaySaveOutput, ReqPtrArgOffset); + RTL->initialize_record_replay(RTLDeviceID, 0, nullptr, true, + OMPX_ReplaySaveOutput, ReqPtrArgOffset); } IsInit = true; @@ -565,7 +565,7 @@ int32_t DeviceTy::initOnce() { } // Load binary to device. -__tgt_target_table *DeviceTy::loadBinary(void *Img) { +__tgt_target_table *DeviceTy::loadBinary(__tgt_device_image *Img) { std::lock_guardMtx)> LG(RTL->Mtx); return RTL->load_binary(RTLDeviceID, Img); } @@ -702,8 +702,7 @@ int32_t DeviceTy::notifyDataUnmapped(void *HstPtr) { // Run region on device int32_t DeviceTy::launchKernel(void *TgtEntryPtr, void **TgtVarsPtr, - ptrdiff_t *TgtOffsets, - const KernelArgsTy &KernelArgs, + ptrdiff_t *TgtOffsets, KernelArgsTy &KernelArgs, AsyncInfoTy &AsyncInfo) { return RTL->launch_kernel(RTLDeviceID, TgtEntryPtr, TgtVarsPtr, TgtOffsets, &KernelArgs, AsyncInfo); diff --git a/openmp/libomptarget/src/omptarget.cpp b/openmp/libomptarget/src/omptarget.cpp index 5b43c7e67eaf7..9d75fd360108f 100644 --- a/openmp/libomptarget/src/omptarget.cpp +++ b/openmp/libomptarget/src/omptarget.cpp @@ -1733,9 +1733,9 @@ int target(ident_t *Loc, DeviceTy &Device, void *HostPtr, int target_activate_rr(DeviceTy &Device, uint64_t MemorySize, void *VAddr, bool IsRecord, bool SaveOutput, uint64_t &ReqPtrArgOffset) { - return Device.RTL->activate_record_replay(Device.DeviceID, MemorySize, VAddr, - IsRecord, SaveOutput, - ReqPtrArgOffset); + return Device.RTL->initialize_record_replay(Device.DeviceID, MemorySize, + VAddr, IsRecord, SaveOutput, + ReqPtrArgOffset); } /// Executes a kernel using pre-recorded information for loading to diff --git a/openmp/libomptarget/src/rtl.cpp b/openmp/libomptarget/src/rtl.cpp index 6248acff686dc..e80d6e09c4840 100644 --- a/openmp/libomptarget/src/rtl.cpp +++ b/openmp/libomptarget/src/rtl.cpp @@ -14,6 +14,7 @@ #include "OpenMP/OMPT/Callback.h" #include "PluginManager.h" +#include "Shared/Debug.h" #include "device.h" #include "private.h" #include "rtl.h" @@ -132,50 +133,21 @@ bool PluginAdaptorManagerTy::attemptLoadRTL(const std::string &RTLName, PluginAd DP("Successfully loaded library '%s'!\n", Name); - // Remove plugin on failure to call optional init_plugin - *((void **)&RTL.init_plugin) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_init_plugin"); - if (RTL.init_plugin) { - int32_t Rc = RTL.init_plugin(); - if (Rc != OFFLOAD_SUCCESS) { - DP("Unable to initialize library '%s': %u!\n", Name, Rc); - return false; - } +#define PLUGIN_API_HANDLE(NAME, MANDATORY) \ + *((void **)&RTL.NAME) = \ + DynLibrary->getAddressOfSymbol(GETNAME(__tgt_rtl_##NAME)); \ + if (MANDATORY && !RTL.NAME) { \ + DP("Invalid plugin as necessary interface is not found.\n"); \ + return false; \ } - bool ValidPlugin = true; - - if (!(*((void **)&RTL.is_valid_binary) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary"))) - ValidPlugin = false; - if (!(*((void **)&RTL.number_of_devices) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_number_of_devices"))) - ValidPlugin = false; - if (!(*((void **)&RTL.init_device) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device"))) - ValidPlugin = false; - if (!(*((void **)&RTL.load_binary) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_load_binary"))) - ValidPlugin = false; - if (!(*((void **)&RTL.data_alloc) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_alloc"))) - ValidPlugin = false; - if (!(*((void **)&RTL.data_submit) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit"))) - ValidPlugin = false; - if (!(*((void **)&RTL.data_retrieve) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve"))) - ValidPlugin = false; - if (!(*((void **)&RTL.data_delete) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_delete"))) - ValidPlugin = false; - if (!(*((void **)&RTL.launch_kernel) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_launch_kernel"))) - ValidPlugin = false; - - // Invalid plugin - if (!ValidPlugin) { - DP("Invalid plugin as necessary interface is not found.\n"); +#include "Shared/PluginAPI.inc" +#undef PLUGIN_API_HANDLE + + // Remove plugin on failure to call optional init_plugin + int32_t Rc = RTL.init_plugin(); + if (Rc != OFFLOAD_SUCCESS) { + DP("Unable to initialize library '%s': %u!\n", Name, Rc); return false; } @@ -192,62 +164,6 @@ bool PluginAdaptorManagerTy::attemptLoadRTL(const std::string &RTLName, PluginAd DP("Registering RTL %s supporting %d devices!\n", Name, RTL.NumberOfDevices); - // Optional functions - *((void **)&RTL.is_valid_binary_info) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_is_valid_binary_info"); - *((void **)&RTL.init_requires) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_init_requires"); - *((void **)&RTL.data_submit_async) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_submit_async"); - *((void **)&RTL.data_retrieve_async) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_retrieve_async"); - *((void **)&RTL.synchronize) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_synchronize"); - *((void **)&RTL.query_async) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_query_async"); - *((void **)&RTL.data_exchange) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange"); - *((void **)&RTL.data_exchange_async) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_exchange_async"); - *((void **)&RTL.is_data_exchangable) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_is_data_exchangable"); - *((void **)&RTL.supports_empty_images) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_supports_empty_images"); - *((void **)&RTL.set_info_flag) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_set_info_flag"); - *((void **)&RTL.print_device_info) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_print_device_info"); - *((void **)&RTL.create_event) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_create_event"); - *((void **)&RTL.record_event) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_record_event"); - *((void **)&RTL.wait_event) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_wait_event"); - *((void **)&RTL.sync_event) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_sync_event"); - *((void **)&RTL.destroy_event) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_destroy_event"); - *((void **)&RTL.release_async_info) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_release_async_info"); - *((void **)&RTL.init_async_info) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_init_async_info"); - *((void **)&RTL.init_device_info) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_init_device_info"); - *((void **)&RTL.data_lock) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_lock"); - *((void **)&RTL.data_unlock) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_unlock"); - *((void **)&RTL.data_notify_mapped) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_notify_mapped"); - *((void **)&RTL.data_notify_unmapped) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_data_notify_unmapped"); - *((void **)&RTL.set_device_offset) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_set_device_offset"); - - // Record Replay RTL - *((void **)&RTL.activate_record_replay) = - DynLibrary->getAddressOfSymbol("__tgt_rtl_initialize_record_replay"); - RTL.LibraryHandler = std::move(DynLibrary); // Successfully loaded