Files
clang-p2996/openmp/runtime/src/ompt-specific.c
Jonathan Peyton 69e596a5e7 [OMPT] Windows Support for OMPT
The problem is that the ompt_tool() function (which must be implemented by a
performance tool) should be defined in the RTL as well to cover the case when
the tool is not present in the address space of the process. This functionality
is accomplished with weak symbols in Unices. Unfortunately, Windows does not
support weak symbols.

The solution in these changes is to grab the list of all modules loaded by the
process and then search for symbol "ompt_tool()" within them. The function
ompt_tool_windows() performs the search of the ompt_tool symbol. If ompt_tool is
found, then its return value is used to initialize the tool. If ompt_tool is not
found, then ompt_tool_windows() returns NULL and OMPT is thus, disabled.

While doing these changes, the OMPT_SUPPORT detection in CMake was changed to
test for the required featuers for OMPT_SUPPORT, namely: builtin_frame_address()
existence, weak attribute existence and psapi.dll existence. For
LIBOMP_HAVE_OMPT_SUPPORT to be true, it must be that the builtin_frame_address()
intrinsic exists AND one of: either weak attributes exist or psapi.dll exists.

Also, since Process Status API is used I had to add new dependency -- psapi.dll
to the library dependency micro test.

Differential Revision: http://reviews.llvm.org/D14027

llvm-svn: 251654
2015-10-29 20:56:24 +00:00

333 lines
8.9 KiB
C

//******************************************************************************
// include files
//******************************************************************************
#include "kmp.h"
#include "ompt-internal.h"
#include "ompt-specific.h"
//******************************************************************************
// macros
//******************************************************************************
#define GTID_TO_OMPT_THREAD_ID(id) ((ompt_thread_id_t) (id >=0) ? id + 1: 0)
#define LWT_FROM_TEAM(team) (team)->t.ompt_serialized_team_info;
#define OMPT_THREAD_ID_BITS 16
// 2013 08 24 - John Mellor-Crummey
// ideally, a thread should assign its own ids based on thread private data.
// however, the way the intel runtime reinitializes thread data structures
// when it creates teams makes it difficult to maintain persistent thread
// data. using a shared variable instead is simple. I leave it to intel to
// sort out how to implement a higher performance version in their runtime.
// when using fetch_and_add to generate the IDs, there isn't any reason to waste
// bits for thread id.
#if 0
#define NEXT_ID(id_ptr,tid) \
((KMP_TEST_THEN_INC64(id_ptr) << OMPT_THREAD_ID_BITS) | (tid))
#else
#define NEXT_ID(id_ptr,tid) (KMP_TEST_THEN_INC64((volatile kmp_int64 *)id_ptr))
#endif
//******************************************************************************
// private operations
//******************************************************************************
//----------------------------------------------------------
// traverse the team and task hierarchy
// note: __ompt_get_teaminfo and __ompt_get_taskinfo
// traverse the hierarchy similarly and need to be
// kept consistent
//----------------------------------------------------------
ompt_team_info_t *
__ompt_get_teaminfo(int depth, int *size)
{
kmp_info_t *thr = ompt_get_thread();
if (thr) {
kmp_team *team = thr->th.th_team;
if (team == NULL) return NULL;
ompt_lw_taskteam_t *lwt = LWT_FROM_TEAM(team);
while(depth > 0) {
// next lightweight team (if any)
if (lwt) lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && team) team=team->t.t_parent;
depth--;
}
if (lwt) {
// lightweight teams have one task
if (size) *size = 1;
// return team info for lightweight team
return &lwt->ompt_team_info;
} else if (team) {
// extract size from heavyweight team
if (size) *size = team->t.t_nproc;
// return team info for heavyweight team
return &team->t.ompt_team_info;
}
}
return NULL;
}
ompt_task_info_t *
__ompt_get_taskinfo(int depth)
{
ompt_task_info_t *info = NULL;
kmp_info_t *thr = ompt_get_thread();
if (thr) {
kmp_taskdata_t *taskdata = thr->th.th_current_task;
ompt_lw_taskteam_t *lwt = LWT_FROM_TEAM(taskdata->td_team);
while (depth > 0) {
// next lightweight team (if any)
if (lwt) lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && taskdata) {
taskdata = taskdata->td_parent;
if (taskdata) {
lwt = LWT_FROM_TEAM(taskdata->td_team);
}
}
depth--;
}
if (lwt) {
info = &lwt->ompt_task_info;
} else if (taskdata) {
info = &taskdata->ompt_task_info;
}
}
return info;
}
//******************************************************************************
// interface operations
//******************************************************************************
//----------------------------------------------------------
// thread support
//----------------------------------------------------------
ompt_parallel_id_t
__ompt_thread_id_new()
{
static uint64_t ompt_thread_id = 1;
return NEXT_ID(&ompt_thread_id, 0);
}
void
__ompt_thread_begin(ompt_thread_type_t thread_type, int gtid)
{
ompt_callbacks.ompt_callback(ompt_event_thread_begin)(
thread_type, GTID_TO_OMPT_THREAD_ID(gtid));
}
void
__ompt_thread_end(ompt_thread_type_t thread_type, int gtid)
{
ompt_callbacks.ompt_callback(ompt_event_thread_end)(
thread_type, GTID_TO_OMPT_THREAD_ID(gtid));
}
ompt_thread_id_t
__ompt_get_thread_id_internal()
{
// FIXME
// until we have a better way of assigning ids, use __kmp_get_gtid
// since the return value might be negative, we need to test that before
// assigning it to an ompt_thread_id_t, which is unsigned.
int id = __kmp_get_gtid();
assert(id >= 0);
return GTID_TO_OMPT_THREAD_ID(id);
}
//----------------------------------------------------------
// state support
//----------------------------------------------------------
void
__ompt_thread_assign_wait_id(void *variable)
{
int gtid = __kmp_gtid_get_specific();
kmp_info_t *ti = ompt_get_thread_gtid(gtid);
ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t) variable;
}
ompt_state_t
__ompt_get_state_internal(ompt_wait_id_t *ompt_wait_id)
{
kmp_info_t *ti = ompt_get_thread();
if (ti) {
if (ompt_wait_id)
*ompt_wait_id = ti->th.ompt_thread_info.wait_id;
return ti->th.ompt_thread_info.state;
}
return ompt_state_undefined;
}
//----------------------------------------------------------
// idle frame support
//----------------------------------------------------------
void *
__ompt_get_idle_frame_internal(void)
{
kmp_info_t *ti = ompt_get_thread();
return ti ? ti->th.ompt_thread_info.idle_frame : NULL;
}
//----------------------------------------------------------
// parallel region support
//----------------------------------------------------------
ompt_parallel_id_t
__ompt_parallel_id_new(int gtid)
{
static uint64_t ompt_parallel_id = 1;
return gtid >= 0 ? NEXT_ID(&ompt_parallel_id, gtid) : 0;
}
void *
__ompt_get_parallel_function_internal(int depth)
{
ompt_team_info_t *info = __ompt_get_teaminfo(depth, NULL);
void *function = info ? info->microtask : NULL;
return function;
}
ompt_parallel_id_t
__ompt_get_parallel_id_internal(int depth)
{
ompt_team_info_t *info = __ompt_get_teaminfo(depth, NULL);
ompt_parallel_id_t id = info ? info->parallel_id : 0;
return id;
}
int
__ompt_get_parallel_team_size_internal(int depth)
{
// initialize the return value with the error value.
// if there is a team at the specified depth, the default
// value will be overwritten the size of that team.
int size = -1;
(void) __ompt_get_teaminfo(depth, &size);
return size;
}
//----------------------------------------------------------
// lightweight task team support
//----------------------------------------------------------
void
__ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr,
int gtid, void *microtask,
ompt_parallel_id_t ompt_pid)
{
lwt->ompt_team_info.parallel_id = ompt_pid;
lwt->ompt_team_info.microtask = microtask;
lwt->ompt_task_info.task_id = 0;
lwt->ompt_task_info.frame.reenter_runtime_frame = 0;
lwt->ompt_task_info.frame.exit_runtime_frame = 0;
lwt->ompt_task_info.function = NULL;
lwt->parent = 0;
}
void
__ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr)
{
ompt_lw_taskteam_t *my_parent = thr->th.th_team->t.ompt_serialized_team_info;
lwt->parent = my_parent;
thr->th.th_team->t.ompt_serialized_team_info = lwt;
}
ompt_lw_taskteam_t *
__ompt_lw_taskteam_unlink(kmp_info_t *thr)
{
ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info;
if (lwtask) thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent;
return lwtask;
}
//----------------------------------------------------------
// task support
//----------------------------------------------------------
ompt_task_id_t
__ompt_task_id_new(int gtid)
{
static uint64_t ompt_task_id = 1;
return NEXT_ID(&ompt_task_id, gtid);
}
ompt_task_id_t
__ompt_get_task_id_internal(int depth)
{
ompt_task_info_t *info = __ompt_get_taskinfo(depth);
ompt_task_id_t task_id = info ? info->task_id : 0;
return task_id;
}
void *
__ompt_get_task_function_internal(int depth)
{
ompt_task_info_t *info = __ompt_get_taskinfo(depth);
void *function = info ? info->function : NULL;
return function;
}
ompt_frame_t *
__ompt_get_task_frame_internal(int depth)
{
ompt_task_info_t *info = __ompt_get_taskinfo(depth);
ompt_frame_t *frame = info ? frame = &info->frame : NULL;
return frame;
}
//----------------------------------------------------------
// team support
//----------------------------------------------------------
void
__ompt_team_assign_id(kmp_team_t *team, ompt_parallel_id_t ompt_pid)
{
team->t.ompt_team_info.parallel_id = ompt_pid;
}