aboutsummaryrefslogtreecommitdiff
path: root/final/runtime/src/ompt-general.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'final/runtime/src/ompt-general.cpp')
-rw-r--r--final/runtime/src/ompt-general.cpp732
1 files changed, 732 insertions, 0 deletions
diff --git a/final/runtime/src/ompt-general.cpp b/final/runtime/src/ompt-general.cpp
new file mode 100644
index 0000000..00bf606
--- /dev/null
+++ b/final/runtime/src/ompt-general.cpp
@@ -0,0 +1,732 @@
+/*
+ * ompt-general.cpp -- OMPT implementation of interface functions
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+/*****************************************************************************
+ * system include files
+ ****************************************************************************/
+
+#include <assert.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if KMP_OS_UNIX
+#include <dlfcn.h>
+#endif
+
+/*****************************************************************************
+ * ompt include files
+ ****************************************************************************/
+
+#include "ompt-specific.cpp"
+
+/*****************************************************************************
+ * macros
+ ****************************************************************************/
+
+#define ompt_get_callback_success 1
+#define ompt_get_callback_failure 0
+
+#define no_tool_present 0
+
+#define OMPT_API_ROUTINE static
+
+#ifndef OMPT_STR_MATCH
+#define OMPT_STR_MATCH(haystack, needle) (!strcasecmp(haystack, needle))
+#endif
+
+/*****************************************************************************
+ * types
+ ****************************************************************************/
+
+typedef struct {
+ const char *state_name;
+ ompt_state_t state_id;
+} ompt_state_info_t;
+
+typedef struct {
+ const char *name;
+ kmp_mutex_impl_t id;
+} kmp_mutex_impl_info_t;
+
+enum tool_setting_e {
+ omp_tool_error,
+ omp_tool_unset,
+ omp_tool_disabled,
+ omp_tool_enabled
+};
+
+/*****************************************************************************
+ * global variables
+ ****************************************************************************/
+
+ompt_callbacks_active_t ompt_enabled;
+
+ompt_state_info_t ompt_state_info[] = {
+#define ompt_state_macro(state, code) {#state, state},
+ FOREACH_OMPT_STATE(ompt_state_macro)
+#undef ompt_state_macro
+};
+
+kmp_mutex_impl_info_t kmp_mutex_impl_info[] = {
+#define kmp_mutex_impl_macro(name, id) {#name, name},
+ FOREACH_KMP_MUTEX_IMPL(kmp_mutex_impl_macro)
+#undef kmp_mutex_impl_macro
+};
+
+ompt_callbacks_internal_t ompt_callbacks;
+
+static ompt_start_tool_result_t *ompt_start_tool_result = NULL;
+
+/*****************************************************************************
+ * forward declarations
+ ****************************************************************************/
+
+static ompt_interface_fn_t ompt_fn_lookup(const char *s);
+
+OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void);
+
+/*****************************************************************************
+ * initialization and finalization (private operations)
+ ****************************************************************************/
+
+typedef ompt_start_tool_result_t *(*ompt_start_tool_t)(unsigned int,
+ const char *);
+
+#if KMP_OS_DARWIN
+
+// While Darwin supports weak symbols, the library that wishes to provide a new
+// implementation has to link against this runtime which defeats the purpose
+// of having tools that are agnostic of the underlying runtime implementation.
+//
+// Fortunately, the linker includes all symbols of an executable in the global
+// symbol table by default so dlsym() even finds static implementations of
+// ompt_start_tool. For this to work on Linux, -Wl,--export-dynamic needs to be
+// passed when building the application which we don't want to rely on.
+
+static ompt_start_tool_result_t *ompt_tool_darwin(unsigned int omp_version,
+ const char *runtime_version) {
+ ompt_start_tool_result_t *ret = NULL;
+ // Search symbol in the current address space.
+ ompt_start_tool_t start_tool =
+ (ompt_start_tool_t)dlsym(RTLD_DEFAULT, "ompt_start_tool");
+ if (start_tool) {
+ ret = start_tool(omp_version, runtime_version);
+ }
+ return ret;
+}
+
+#elif OMPT_HAVE_WEAK_ATTRIBUTE
+
+// On Unix-like systems that support weak symbols the following implementation
+// of ompt_start_tool() will be used in case no tool-supplied implementation of
+// this function is present in the address space of a process.
+
+_OMP_EXTERN OMPT_WEAK_ATTRIBUTE ompt_start_tool_result_t *
+ompt_start_tool(unsigned int omp_version, const char *runtime_version) {
+ ompt_start_tool_result_t *ret = NULL;
+ // Search next symbol in the current address space. This can happen if the
+ // runtime library is linked before the tool. Since glibc 2.2 strong symbols
+ // don't override weak symbols that have been found before unless the user
+ // sets the environment variable LD_DYNAMIC_WEAK.
+ ompt_start_tool_t next_tool =
+ (ompt_start_tool_t)dlsym(RTLD_NEXT, "ompt_start_tool");
+ if (next_tool) {
+ ret = next_tool(omp_version, runtime_version);
+ }
+ return ret;
+}
+
+#elif OMPT_HAVE_PSAPI
+
+// On Windows, the ompt_tool_windows function is used to find the
+// ompt_start_tool symbol across all modules loaded by a process. If
+// ompt_start_tool is found, ompt_start_tool's return value is used to
+// initialize the tool. Otherwise, NULL is returned and OMPT won't be enabled.
+
+#include <psapi.h>
+#pragma comment(lib, "psapi.lib")
+
+// The number of loaded modules to start enumeration with EnumProcessModules()
+#define NUM_MODULES 128
+
+static ompt_start_tool_result_t *
+ompt_tool_windows(unsigned int omp_version, const char *runtime_version) {
+ int i;
+ DWORD needed, new_size;
+ HMODULE *modules;
+ HANDLE process = GetCurrentProcess();
+ modules = (HMODULE *)malloc(NUM_MODULES * sizeof(HMODULE));
+ ompt_start_tool_t ompt_tool_p = NULL;
+
+#if OMPT_DEBUG
+ printf("ompt_tool_windows(): looking for ompt_start_tool\n");
+#endif
+ if (!EnumProcessModules(process, modules, NUM_MODULES * sizeof(HMODULE),
+ &needed)) {
+ // Regardless of the error reason use the stub initialization function
+ free(modules);
+ return NULL;
+ }
+ // Check if NUM_MODULES is enough to list all modules
+ new_size = needed / sizeof(HMODULE);
+ if (new_size > NUM_MODULES) {
+#if OMPT_DEBUG
+ printf("ompt_tool_windows(): resize buffer to %d bytes\n", needed);
+#endif
+ modules = (HMODULE *)realloc(modules, needed);
+ // If resizing failed use the stub function.
+ if (!EnumProcessModules(process, modules, needed, &needed)) {
+ free(modules);
+ return NULL;
+ }
+ }
+ for (i = 0; i < new_size; ++i) {
+ (FARPROC &)ompt_tool_p = GetProcAddress(modules[i], "ompt_start_tool");
+ if (ompt_tool_p) {
+#if OMPT_DEBUG
+ TCHAR modName[MAX_PATH];
+ if (GetModuleFileName(modules[i], modName, MAX_PATH))
+ printf("ompt_tool_windows(): ompt_start_tool found in module %s\n",
+ modName);
+#endif
+ free(modules);
+ return (*ompt_tool_p)(omp_version, runtime_version);
+ }
+#if OMPT_DEBUG
+ else {
+ TCHAR modName[MAX_PATH];
+ if (GetModuleFileName(modules[i], modName, MAX_PATH))
+ printf("ompt_tool_windows(): ompt_start_tool not found in module %s\n",
+ modName);
+ }
+#endif
+ }
+ free(modules);
+ return NULL;
+}
+#else
+#error Activation of OMPT is not supported on this platform.
+#endif
+
+static ompt_start_tool_result_t *
+ompt_try_start_tool(unsigned int omp_version, const char *runtime_version) {
+ ompt_start_tool_result_t *ret = NULL;
+ ompt_start_tool_t start_tool = NULL;
+#if KMP_OS_WINDOWS
+ // Cannot use colon to describe a list of absolute paths on Windows
+ const char *sep = ";";
+#else
+ const char *sep = ":";
+#endif
+
+#if KMP_OS_DARWIN
+ // Try in the current address space
+ ret = ompt_tool_darwin(omp_version, runtime_version);
+#elif OMPT_HAVE_WEAK_ATTRIBUTE
+ ret = ompt_start_tool(omp_version, runtime_version);
+#elif OMPT_HAVE_PSAPI
+ ret = ompt_tool_windows(omp_version, runtime_version);
+#else
+#error Activation of OMPT is not supported on this platform.
+#endif
+ if (ret)
+ return ret;
+
+ // Try tool-libraries-var ICV
+ const char *tool_libs = getenv("OMP_TOOL_LIBRARIES");
+ if (tool_libs) {
+ char *libs = __kmp_str_format("%s", tool_libs);
+ char *buf;
+ char *fname = __kmp_str_token(libs, sep, &buf);
+ while (fname) {
+#if KMP_OS_UNIX
+ void *h = dlopen(fname, RTLD_LAZY);
+ if (h) {
+ start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
+#elif KMP_OS_WINDOWS
+ HMODULE h = LoadLibrary(fname);
+ if (h) {
+ start_tool = (ompt_start_tool_t)GetProcAddress(h, "ompt_start_tool");
+#else
+#error Activation of OMPT is not supported on this platform.
+#endif
+ if (start_tool && (ret = (*start_tool)(omp_version, runtime_version)))
+ break;
+ }
+ fname = __kmp_str_token(NULL, sep, &buf);
+ }
+ __kmp_str_free(&libs);
+ }
+ return ret;
+}
+
+void ompt_pre_init() {
+ //--------------------------------------------------
+ // Execute the pre-initialization logic only once.
+ //--------------------------------------------------
+ static int ompt_pre_initialized = 0;
+
+ if (ompt_pre_initialized)
+ return;
+
+ ompt_pre_initialized = 1;
+
+ //--------------------------------------------------
+ // Use a tool iff a tool is enabled and available.
+ //--------------------------------------------------
+ const char *ompt_env_var = getenv("OMP_TOOL");
+ tool_setting_e tool_setting = omp_tool_error;
+
+ if (!ompt_env_var || !strcmp(ompt_env_var, ""))
+ tool_setting = omp_tool_unset;
+ else if (OMPT_STR_MATCH(ompt_env_var, "disabled"))
+ tool_setting = omp_tool_disabled;
+ else if (OMPT_STR_MATCH(ompt_env_var, "enabled"))
+ tool_setting = omp_tool_enabled;
+
+#if OMPT_DEBUG
+ printf("ompt_pre_init(): tool_setting = %d\n", tool_setting);
+#endif
+ switch (tool_setting) {
+ case omp_tool_disabled:
+ break;
+
+ case omp_tool_unset:
+ case omp_tool_enabled:
+
+ //--------------------------------------------------
+ // Load tool iff specified in environment variable
+ //--------------------------------------------------
+ ompt_start_tool_result =
+ ompt_try_start_tool(__kmp_openmp_version, ompt_get_runtime_version());
+
+ memset(&ompt_enabled, 0, sizeof(ompt_enabled));
+ break;
+
+ case omp_tool_error:
+ fprintf(stderr, "Warning: OMP_TOOL has invalid value \"%s\".\n"
+ " legal values are (NULL,\"\",\"disabled\","
+ "\"enabled\").\n",
+ ompt_env_var);
+ break;
+ }
+#if OMPT_DEBUG
+ printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled);
+#endif
+}
+
+extern "C" int omp_get_initial_device(void);
+
+void ompt_post_init() {
+ //--------------------------------------------------
+ // Execute the post-initialization logic only once.
+ //--------------------------------------------------
+ static int ompt_post_initialized = 0;
+
+ if (ompt_post_initialized)
+ return;
+
+ ompt_post_initialized = 1;
+
+ //--------------------------------------------------
+ // Initialize the tool if so indicated.
+ //--------------------------------------------------
+ if (ompt_start_tool_result) {
+ ompt_enabled.enabled = !!ompt_start_tool_result->initialize(
+ ompt_fn_lookup, omp_get_initial_device(), &(ompt_start_tool_result->tool_data));
+
+ if (!ompt_enabled.enabled) {
+ // tool not enabled, zero out the bitmap, and done
+ memset(&ompt_enabled, 0, sizeof(ompt_enabled));
+ return;
+ }
+
+ kmp_info_t *root_thread = ompt_get_thread();
+
+ ompt_set_thread_state(root_thread, ompt_state_overhead);
+
+ if (ompt_enabled.ompt_callback_thread_begin) {
+ ompt_callbacks.ompt_callback(ompt_callback_thread_begin)(
+ ompt_thread_initial, __ompt_get_thread_data_internal());
+ }
+ ompt_data_t *task_data;
+ ompt_data_t *parallel_data;
+ __ompt_get_task_info_internal(0, NULL, &task_data, NULL, &parallel_data, NULL);
+ if (ompt_enabled.ompt_callback_implicit_task) {
+ ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
+ ompt_scope_begin, parallel_data, task_data, 1, 1, ompt_task_initial);
+ }
+
+ ompt_set_thread_state(root_thread, ompt_state_work_serial);
+ }
+}
+
+void ompt_fini() {
+ if (ompt_enabled.enabled) {
+ ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data));
+ }
+
+ memset(&ompt_enabled, 0, sizeof(ompt_enabled));
+}
+
+/*****************************************************************************
+ * interface operations
+ ****************************************************************************/
+
+/*****************************************************************************
+ * state
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state,
+ const char **next_state_name) {
+ const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
+ int i = 0;
+
+ for (i = 0; i < len - 1; i++) {
+ if (ompt_state_info[i].state_id == current_state) {
+ *next_state = ompt_state_info[i + 1].state_id;
+ *next_state_name = ompt_state_info[i + 1].state_name;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl,
+ int *next_impl,
+ const char **next_impl_name) {
+ const static int len =
+ sizeof(kmp_mutex_impl_info) / sizeof(kmp_mutex_impl_info_t);
+ int i = 0;
+ for (i = 0; i < len - 1; i++) {
+ if (kmp_mutex_impl_info[i].id != current_impl)
+ continue;
+ *next_impl = kmp_mutex_impl_info[i + 1].id;
+ *next_impl_name = kmp_mutex_impl_info[i + 1].name;
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************
+ * callbacks
+ ****************************************************************************/
+
+OMPT_API_ROUTINE ompt_set_result_t ompt_set_callback(ompt_callbacks_t which,
+ ompt_callback_t callback) {
+ switch (which) {
+
+#define ompt_event_macro(event_name, callback_type, event_id) \
+ case event_name: \
+ if (ompt_event_implementation_status(event_name)) { \
+ ompt_callbacks.ompt_callback(event_name) = (callback_type)callback; \
+ ompt_enabled.event_name = (callback != 0); \
+ } \
+ if (callback) \
+ return ompt_event_implementation_status(event_name); \
+ else \
+ return ompt_set_always;
+
+ FOREACH_OMPT_EVENT(ompt_event_macro)
+
+#undef ompt_event_macro
+
+ default:
+ return ompt_set_error;
+ }
+}
+
+OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which,
+ ompt_callback_t *callback) {
+ if (!ompt_enabled.enabled)
+ return ompt_get_callback_failure;
+
+ switch (which) {
+
+#define ompt_event_macro(event_name, callback_type, event_id) \
+ case event_name: \
+ if (ompt_event_implementation_status(event_name)) { \
+ ompt_callback_t mycb = \
+ (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \
+ if (ompt_enabled.event_name && mycb) { \
+ *callback = mycb; \
+ return ompt_get_callback_success; \
+ } \
+ } \
+ return ompt_get_callback_failure;
+
+ FOREACH_OMPT_EVENT(ompt_event_macro)
+
+#undef ompt_event_macro
+
+ default:
+ return ompt_get_callback_failure;
+ }
+}
+
+/*****************************************************************************
+ * parallel regions
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level,
+ ompt_data_t **parallel_data,
+ int *team_size) {
+ if (!ompt_enabled.enabled)
+ return 0;
+ return __ompt_get_parallel_info_internal(ancestor_level, parallel_data,
+ team_size);
+}
+
+OMPT_API_ROUTINE int ompt_get_state(ompt_wait_id_t *wait_id) {
+ if (!ompt_enabled.enabled)
+ return ompt_state_work_serial;
+ int thread_state = __ompt_get_state_internal(wait_id);
+
+ if (thread_state == ompt_state_undefined) {
+ thread_state = ompt_state_work_serial;
+ }
+
+ return thread_state;
+}
+
+/*****************************************************************************
+ * tasks
+ ****************************************************************************/
+
+OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) {
+ if (!ompt_enabled.enabled)
+ return NULL;
+ return __ompt_get_thread_data_internal();
+}
+
+OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type,
+ ompt_data_t **task_data,
+ ompt_frame_t **task_frame,
+ ompt_data_t **parallel_data,
+ int *thread_num) {
+ if (!ompt_enabled.enabled)
+ return 0;
+ return __ompt_get_task_info_internal(ancestor_level, type, task_data,
+ task_frame, parallel_data, thread_num);
+}
+
+OMPT_API_ROUTINE int ompt_get_task_memory(void **addr, size_t *size,
+ int block) {
+ return __ompt_get_task_memory_internal(addr, size, block);
+}
+
+/*****************************************************************************
+ * num_procs
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_get_num_procs(void) {
+ // copied from kmp_ftn_entry.h (but modified: OMPT can only be called when
+ // runtime is initialized)
+ return __kmp_avail_proc;
+}
+
+/*****************************************************************************
+ * places
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_get_num_places(void) {
+// copied from kmp_ftn_entry.h (but modified)
+#if !KMP_AFFINITY_SUPPORTED
+ return 0;
+#else
+ if (!KMP_AFFINITY_CAPABLE())
+ return 0;
+ return __kmp_affinity_num_masks;
+#endif
+}
+
+OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size,
+ int *ids) {
+// copied from kmp_ftn_entry.h (but modified)
+#if !KMP_AFFINITY_SUPPORTED
+ return 0;
+#else
+ int i, count;
+ int tmp_ids[ids_size];
+ if (!KMP_AFFINITY_CAPABLE())
+ return 0;
+ if (place_num < 0 || place_num >= (int)__kmp_affinity_num_masks)
+ return 0;
+ /* TODO: Is this safe for asynchronous call from signal handler during runtime
+ * shutdown? */
+ kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity_masks, place_num);
+ count = 0;
+ KMP_CPU_SET_ITERATE(i, mask) {
+ if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) ||
+ (!KMP_CPU_ISSET(i, mask))) {
+ continue;
+ }
+ if (count < ids_size)
+ tmp_ids[count] = i;
+ count++;
+ }
+ if (ids_size >= count) {
+ for (i = 0; i < count; i++) {
+ ids[i] = tmp_ids[i];
+ }
+ }
+ return count;
+#endif
+}
+
+OMPT_API_ROUTINE int ompt_get_place_num(void) {
+// copied from kmp_ftn_entry.h (but modified)
+#if !KMP_AFFINITY_SUPPORTED
+ return -1;
+#else
+ if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
+ return -1;
+
+ int gtid;
+ kmp_info_t *thread;
+ if (!KMP_AFFINITY_CAPABLE())
+ return -1;
+ gtid = __kmp_entry_gtid();
+ thread = __kmp_thread_from_gtid(gtid);
+ if (thread == NULL || thread->th.th_current_place < 0)
+ return -1;
+ return thread->th.th_current_place;
+#endif
+}
+
+OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size,
+ int *place_nums) {
+// copied from kmp_ftn_entry.h (but modified)
+#if !KMP_AFFINITY_SUPPORTED
+ return 0;
+#else
+ if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
+ return 0;
+
+ int i, gtid, place_num, first_place, last_place, start, end;
+ kmp_info_t *thread;
+ if (!KMP_AFFINITY_CAPABLE())
+ return 0;
+ gtid = __kmp_entry_gtid();
+ thread = __kmp_thread_from_gtid(gtid);
+ if (thread == NULL)
+ return 0;
+ first_place = thread->th.th_first_place;
+ last_place = thread->th.th_last_place;
+ if (first_place < 0 || last_place < 0)
+ return 0;
+ if (first_place <= last_place) {
+ start = first_place;
+ end = last_place;
+ } else {
+ start = last_place;
+ end = first_place;
+ }
+ if (end - start <= place_nums_size)
+ for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) {
+ place_nums[i] = place_num;
+ }
+ return end - start + 1;
+#endif
+}
+
+/*****************************************************************************
+ * places
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_get_proc_id(void) {
+ if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
+ return -1;
+#if KMP_OS_LINUX
+ return sched_getcpu();
+#elif KMP_OS_WINDOWS
+ PROCESSOR_NUMBER pn;
+ GetCurrentProcessorNumberEx(&pn);
+ return 64 * pn.Group + pn.Number;
+#else
+ return -1;
+#endif
+}
+
+/*****************************************************************************
+ * compatability
+ ****************************************************************************/
+
+/*
+ * Currently unused function
+OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
+*/
+
+/*****************************************************************************
+* application-facing API
+ ****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ | control
+ ---------------------------------------------------------------------------*/
+
+int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) {
+
+ if (ompt_enabled.enabled) {
+ if (ompt_enabled.ompt_callback_control_tool) {
+ return ompt_callbacks.ompt_callback(ompt_callback_control_tool)(
+ command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid()));
+ } else {
+ return -1;
+ }
+ } else {
+ return -2;
+ }
+}
+
+/*****************************************************************************
+ * misc
+ ****************************************************************************/
+
+OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) {
+ return __ompt_get_unique_id_internal();
+}
+
+OMPT_API_ROUTINE void ompt_finalize_tool(void) { __kmp_internal_end_atexit(); }
+
+/*****************************************************************************
+ * Target
+ ****************************************************************************/
+
+OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num,
+ ompt_id_t *target_id,
+ ompt_id_t *host_op_id) {
+ return 0; // thread is not in a target region
+}
+
+OMPT_API_ROUTINE int ompt_get_num_devices(void) {
+ return 1; // only one device (the current device) is available
+}
+
+/*****************************************************************************
+ * API inquiry for tool
+ ****************************************************************************/
+
+static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
+
+#define ompt_interface_fn(fn) \
+ fn##_t fn##_f = fn; \
+ if (strcmp(s, #fn) == 0) \
+ return (ompt_interface_fn_t)fn##_f;
+
+ FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
+
+ return (ompt_interface_fn_t)0;
+}