[OpenMP] Implement OpenMP 5.0 affinity format functionality

This patch adds the affinity format functionality introduced in OpenMP 5.0.
This patch adds: Two new environment variables:

OMP_DISPLAY_AFFINITY=TRUE|FALSE
OMP_AFFINITY_FORMAT=<string>
and Four new API:
1) omp_set_affinity_format()
2) omp_get_affinity_format()
3) omp_display_affinity()
4) omp_capture_affinity()
The affinity format functionality has two ICV's associated with it:
affinity-display-var (bool) and affinity-format-var (string).
The affinity-display-var enables/disables the functionality through the
envirable OMP_DISPLAY_AFFINITY. The affinity-format-var is a formatted
string with the special field types beginning with a '%' character
similar to printf
For example, the affinity-format-var could be:
"OMP: host:%H pid:%P OStid:%i num_threads:%N thread_num:%n affinity:{%A}"

The affinity-format-var is displayed by every thread implicitly at the beginning
of a parallel region when any thread's affinity has changed (including a brand
new thread being spawned), or explicitly using the omp_display_affinity() API.
The omp_capture_affinity() function can capture the affinity-format-var in a
char buffer. And omp_set|get_affinity_format() allow the user to set|get the
affinity-format-var explicitly at runtime. omp_capture_affinity() and
omp_get_affinity_format() both return the number of characters needed to hold
the entire string it tried to make (not including NULL character). If not
enough buffer space is available,
both these functions truncate their output.

Differential Revision: https://reviews.llvm.org/D55148

llvm-svn: 349089
This commit is contained in:
Jonathan Peyton 2018-12-13 23:14:24 +00:00
parent 66c6c5abea
commit 6d88e049dc
23 changed files with 1024 additions and 129 deletions

View File

@ -547,6 +547,14 @@ kmp_set_disp_num_buffers 890
omp_get_default_allocator 893
omp_alloc 894
omp_free 895
omp_set_affinity_format 748
omp_get_affinity_format 749
omp_display_affinity 750
omp_capture_affinity 751
ompc_set_affinity_format 752
ompc_get_affinity_format 753
ompc_display_affinity 754
ompc_capture_affinity 755
OMP_NULL_ALLOCATOR DATA
omp_default_mem_alloc DATA

View File

@ -425,6 +425,7 @@ AffHWSubsetManyNodes "KMP_HW_SUBSET ignored: too many NUMA Nodes request
AffHWSubsetManyTiles "KMP_HW_SUBSET ignored: too many L2 Caches requested."
AffHWSubsetManyProcs "KMP_HW_SUBSET ignored: too many Procs requested."
HierSchedInvalid "Hierarchy ignored: unsupported level: %1$s."
AffFormatDefault "OMP: pid %1$s tid %2$s thread %3$s bound to OS proc set {%4$s}"
# --------------------------------------------------------------------------------------------------

View File

@ -25,6 +25,11 @@
extern "C" {
# endif
# define omp_set_affinity_format ompc_set_affinity_format
# define omp_get_affinity_format ompc_get_affinity_format
# define omp_display_affinity ompc_display_affinity
# define omp_capture_affinity ompc_capture_affinity
# if defined(_WIN32)
# define __KAI_KMPC_CONVENTION __cdecl
# ifndef __KMP_IMP
@ -235,6 +240,12 @@
extern void __KAI_KMPC_CONVENTION omp_free(void *ptr, const omp_allocator_t *allocator);
#endif
/* OpenMP 5.0 Affinity Format */
extern void __KAI_KMPC_CONVENTION omp_set_affinity_format(char const *);
extern size_t __KAI_KMPC_CONVENTION omp_get_affinity_format(char *, size_t);
extern void __KAI_KMPC_CONVENTION omp_display_affinity(char const *);
extern size_t __KAI_KMPC_CONVENTION omp_capture_affinity(char *, size_t, char const *);
# undef __KAI_KMPC_CONVENTION
# undef __KMP_IMP

View File

@ -375,6 +375,27 @@
integer (kind=omp_allocator_kind) omp_get_default_allocator
end function omp_get_default_allocator
subroutine omp_set_affinity_format(format)
character (len=*) format
end subroutine omp_set_affinity_format
function omp_get_affinity_format(buffer)
use omp_lib_kinds
character (len=*) buffer
integer (kind=kmp_size_t_kind) omp_get_affinity_format
end function omp_get_affinity_format
subroutine omp_display_affinity(format)
character (len=*) format
end subroutine omp_display_affinity
function omp_capture_affinity(buffer, format)
use omp_lib_kinds
character (len=*) format
character (len=*) buffer
integer (kind=kmp_size_t_kind) omp_capture_affinity
end function omp_capture_affinity
! ***
! *** kmp_* entry points
! ***
@ -594,6 +615,10 @@
!dec$ attributes alias:'OMP_IS_INITIAL_DEVICE' :: omp_is_initial_device
!dec$ attributes alias:'OMP_GET_MAX_TASK_PRIORITY' :: omp_get_max_task_priority
!dec$ attributes alias:'OMP_CONTROL_TOOL' :: omp_control_tool
!dec$ attributes alias:'OMP_SET_AFFINITY_FORMAT' :: omp_set_affinity_format
!dec$ attributes alias:'OMP_GET_AFFINITY_FORMAT' :: omp_get_affinity_format
!dec$ attributes alias:'OMP_DISPLAY_AFFINITY' :: omp_display_affinity
!dec$ attributes alias:'OMP_CAPTURE_AFFINITY' :: omp_capture_affinity
!dec$ attributes alias:'omp_init_lock' :: omp_init_lock
!dec$ attributes alias:'omp_init_lock_with_hint' :: omp_init_lock_with_hint
@ -675,6 +700,10 @@
!dec$ attributes alias:'_OMP_IS_INITIAL_DEVICE' :: omp_is_initial_device
!dec$ attributes alias:'_OMP_GET_MAX_TASK_PRIORTY' :: omp_get_max_task_priority
!dec$ attributes alias:'_OMP_CONTROL_TOOL' :: omp_control_tool
!dec$ attributes alias:'_OMP_SET_AFFINITY_FORMAT' :: omp_set_affinity_format
!dec$ attributes alias:'_OMP_GET_AFFINITY_FORMAT' :: omp_get_affinity_format
!dec$ attributes alias:'_OMP_DISPLAY_AFFINITY' :: omp_display_affinity
!dec$ attributes alias:'_OMP_CAPTURE_AFFINITY' :: omp_capture_affinity
!dec$ attributes alias:'_omp_init_lock' :: omp_init_lock
!dec$ attributes alias:'_omp_init_lock_with_hint' :: omp_init_lock_with_hint
@ -758,6 +787,10 @@
!dec$ attributes alias:'omp_get_cancellation_'::omp_get_cancellation
!dec$ attributes alias:'omp_is_initial_device_'::omp_is_initial_device
!dec$ attributes alias:'omp_get_max_task_priority_'::omp_get_max_task_priority
!dec$ attributes alias:'omp_set_affinity_format_' :: omp_set_affinity_format
!dec$ attributes alias:'omp_get_affinity_format_' :: omp_get_affinity_format
!dec$ attributes alias:'omp_display_affinity_' :: omp_display_affinity
!dec$ attributes alias:'omp_capture_affinity_' :: omp_capture_affinity
!dec$ attributes alias:'omp_init_lock_'::omp_init_lock
!dec$ attributes alias:'omp_init_lock_with_hint_'::omp_init_lock_with_hint
@ -852,6 +885,10 @@
!dec$ attributes alias:'_omp_unset_nest_lock_'::omp_unset_nest_lock
!dec$ attributes alias:'_omp_test_nest_lock_'::omp_test_nest_lock
!dec$ attributes alias:'_omp_control_tool_'::omp_control_tool
!dec$ attributes alias:'_omp_set_affinity_format_' :: omp_set_affinity_format
!dec$ attributes alias:'_omp_get_affinity_format_' :: omp_get_affinity_format
!dec$ attributes alias:'_omp_display_affinity_' :: omp_display_affinity
!dec$ attributes alias:'_omp_capture_affinity_' :: omp_capture_affinity
!dec$ attributes alias:'_kmp_set_stacksize_'::kmp_set_stacksize
!dec$ attributes alias:'_kmp_set_stacksize_s_'::kmp_set_stacksize_s

View File

@ -391,6 +391,27 @@
integer (kind=omp_allocator_kind) omp_get_default_allocator
end function omp_get_default_allocator
subroutine omp_set_affinity_format(format)
character (len=*) :: format
end subroutine omp_set_affinity_format
function omp_get_affinity_format(buffer)
use omp_lib_kinds
character (len=*) :: buffer
integer (kind=kmp_size_t_kind) :: omp_get_affinity_format
end function omp_get_affinity_format
subroutine omp_display_affinity(format)
character (len=*) :: format
end subroutine omp_display_affinity
function omp_capture_affinity(buffer, format)
use omp_lib_kinds
character (len=*) :: format
character (len=*) :: buffer
integer (kind=kmp_size_t_kind) :: omp_capture_affinity
end function omp_capture_affinity
! ***
! *** kmp_* entry points
! ***

View File

@ -424,6 +424,27 @@
integer (kind=omp_allocator_kind) omp_get_default_allocator
end function omp_get_default_allocator
subroutine omp_set_affinity_format(format)
character (len=*) :: format
end subroutine omp_set_affinity_format
function omp_get_affinity_format(buffer)
import
character (len=*) :: buffer
integer (kind=kmp_size_t_kind) :: omp_get_affinity_format
end function omp_get_affinity_format
subroutine omp_display_affinity(format)
character (len=*) :: format
end subroutine omp_display_affinity
function omp_capture_affinity(buffer, format)
import
character (len=*) :: format
character (len=*) :: buffer
integer (kind=kmp_size_t_kind) :: omp_capture_affinity
end function omp_capture_affinity
! ***
! *** kmp_* entry points
! ***
@ -637,6 +658,10 @@
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_unset_nest_lock
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_test_nest_lock
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_max_task_priority
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_set_affinity_format
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_get_affinity_format
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_display_affinity
!DIR$ ATTRIBUTES OFFLOAD:MIC :: omp_capture_affinity
!DIR$ ATTRIBUTES OFFLOAD:MIC :: kmp_set_stacksize
!DIR$ ATTRIBUTES OFFLOAD:MIC :: kmp_set_stacksize_s
!DIR$ ATTRIBUTES OFFLOAD:MIC :: kmp_set_blocktime
@ -710,6 +735,10 @@
!$omp declare target(omp_unset_nest_lock )
!$omp declare target(omp_test_nest_lock )
!$omp declare target(omp_get_max_task_priority )
!$omp declare target(omp_set_affinity_format )
!$omp declare target(omp_get_affinity_format )
!$omp declare target(omp_display_affinity )
!$omp declare target(omp_capture_affinity )
!$omp declare target(kmp_set_stacksize )
!$omp declare target(kmp_set_stacksize_s )
!$omp declare target(kmp_set_blocktime )

View File

@ -129,6 +129,11 @@ class kmp_stats_list;
#include "ompt-internal.h"
#endif
#if OMP_50_ENABLED
// Affinity format function
#include "kmp_str.h"
#endif
// 0 - no fast memory allocation, alignment: 8-byte on x86, 16-byte on x64.
// 3 - fast allocation using sync, non-sync free lists of any size, non-self
// free lists of limited size.
@ -797,6 +802,12 @@ extern kmp_nested_proc_bind_t __kmp_nested_proc_bind;
#endif /* OMP_40_ENABLED */
#if OMP_50_ENABLED
extern int __kmp_display_affinity;
extern char *__kmp_affinity_format;
static const size_t KMP_AFFINITY_FORMAT_SIZE = 512;
#endif // OMP_50_ENABLED
#if KMP_AFFINITY_SUPPORTED
#define KMP_PLACE_ALL (-1)
#define KMP_PLACE_UNDEFINED (-2)
@ -2507,6 +2518,10 @@ typedef struct KMP_ALIGN_CACHE kmp_base_info {
int th_last_place; /* last place in partition */
#endif
#endif
#if OMP_50_ENABLED
int th_prev_level; /* previous level for affinity format */
int th_prev_num_threads; /* previous num_threads for affinity format */
#endif
#if USE_ITT_BUILD
kmp_uint64 th_bar_arrive_time; /* arrival to barrier timestamp */
kmp_uint64 th_bar_min_time; /* minimum arrival time at the barrier */
@ -2700,6 +2715,9 @@ typedef struct KMP_ALIGN_CACHE kmp_base_team {
int t_first_place; // first & last place in parent thread's partition.
int t_last_place; // Restore these values to master after par region.
#endif // OMP_40_ENABLED && KMP_AFFINITY_SUPPORTED
#if OMP_50_ENABLED
int t_display_affinity;
#endif
int t_size_changed; // team size was changed?: 0: no, 1: yes, -1: changed via
// omp_set_num_threads() call
#if OMP_50_ENABLED
@ -3383,6 +3401,8 @@ extern void __kmp_runtime_destroy(void);
#if KMP_AFFINITY_SUPPORTED
extern char *__kmp_affinity_print_mask(char *buf, int buf_len,
kmp_affin_mask_t *mask);
extern kmp_str_buf_t *__kmp_affinity_str_buf_mask(kmp_str_buf_t *buf,
kmp_affin_mask_t *mask);
extern void __kmp_affinity_initialize(void);
extern void __kmp_affinity_uninitialize(void);
extern void __kmp_affinity_set_init_mask(
@ -3402,6 +3422,14 @@ extern void __kmp_balanced_affinity(kmp_info_t *th, int team_size);
extern int kmp_set_thread_affinity_mask_initial(void);
#endif
#endif /* KMP_AFFINITY_SUPPORTED */
#if OMP_50_ENABLED
// No need for KMP_AFFINITY_SUPPORTED guard as only one field in the
// format string is for affinity, so platforms that do not support
// affinity can still use the other fields, e.g., %n for num_threads
extern size_t __kmp_aux_capture_affinity(int gtid, const char *format,
kmp_str_buf_t *buffer);
extern void __kmp_aux_display_affinity(int gtid, const char *format);
#endif
extern void __kmp_cleanup_hierarchy();
extern void __kmp_get_hierarchy(kmp_uint32 nproc, kmp_bstate_t *thr_bar);
@ -3554,6 +3582,8 @@ KMP_EXPORT int __kmpc_invoke_task_func(int gtid);
#if OMP_40_ENABLED
extern int __kmp_invoke_teams_master(int gtid);
extern void __kmp_teams_master(int gtid);
extern int __kmp_aux_get_team_num();
extern int __kmp_aux_get_num_teams();
#endif
extern void __kmp_save_internal_controls(kmp_info_t *thread);
extern void __kmp_user_set_library(enum library_type arg);

View File

@ -83,55 +83,135 @@ void KMPAffinity::destroy_api() {
}
}
#define KMP_ADVANCE_SCAN(scan) \
while (*scan != '\0') { \
scan++; \
}
// Print the affinity mask to the character array in a pretty format.
// The format is a comma separated list of non-negative integers or integer
// ranges: e.g., 1,2,3-5,7,9-15
// The format can also be the string "{<empty>}" if no bits are set in mask
char *__kmp_affinity_print_mask(char *buf, int buf_len,
kmp_affin_mask_t *mask) {
int start = 0, finish = 0, previous = 0;
bool first_range;
KMP_ASSERT(buf);
KMP_ASSERT(buf_len >= 40);
KMP_ASSERT(mask);
char *scan = buf;
char *end = buf + buf_len - 1;
// Find first element / check for empty set.
int i;
i = mask->begin();
if (i == mask->end()) {
// Check for empty set.
if (mask->begin() == mask->end()) {
KMP_SNPRINTF(scan, end - scan + 1, "{<empty>}");
while (*scan != '\0')
scan++;
KMP_ADVANCE_SCAN(scan);
KMP_ASSERT(scan <= end);
return buf;
}
KMP_SNPRINTF(scan, end - scan + 1, "{%d", i);
while (*scan != '\0')
scan++;
i++;
for (; i != mask->end(); i = mask->next(i)) {
if (!KMP_CPU_ISSET(i, mask)) {
continue;
first_range = true;
start = mask->begin();
while (1) {
// Find next range
// [start, previous] is inclusive range of contiguous bits in mask
for (finish = mask->next(start), previous = start;
finish == previous + 1 && finish != mask->end();
finish = mask->next(finish)) {
previous = finish;
}
// Check for buffer overflow. A string of the form ",<n>" will have at most
// 10 characters, plus we want to leave room to print ",...}" if the set is
// too large to print for a total of 15 characters. We already left room for
// '\0' in setting end.
if (end - scan < 15) {
break;
// The first range does not need a comma printed before it, but the rest
// of the ranges do need a comma beforehand
if (!first_range) {
KMP_SNPRINTF(scan, end - scan + 1, "%s", ",");
KMP_ADVANCE_SCAN(scan);
} else {
first_range = false;
}
KMP_SNPRINTF(scan, end - scan + 1, ",%-d", i);
while (*scan != '\0')
scan++;
// Range with three or more contiguous bits in the affinity mask
if (previous - start > 1) {
KMP_SNPRINTF(scan, end - scan + 1, "%d-%d", static_cast<int>(start),
static_cast<int>(previous));
} else {
// Range with one or two contiguous bits in the affinity mask
KMP_SNPRINTF(scan, end - scan + 1, "%d", static_cast<int>(start));
KMP_ADVANCE_SCAN(scan);
if (previous - start > 0) {
KMP_SNPRINTF(scan, end - scan + 1, ",%d", static_cast<int>(previous));
}
}
KMP_ADVANCE_SCAN(scan);
// Start over with new start point
start = finish;
if (start == mask->end())
break;
// Check for overflow
if (end - scan < 2)
break;
}
if (i != mask->end()) {
KMP_SNPRINTF(scan, end - scan + 1, ",...");
while (*scan != '\0')
scan++;
}
KMP_SNPRINTF(scan, end - scan + 1, "}");
while (*scan != '\0')
scan++;
// Check for overflow
KMP_ASSERT(scan <= end);
return buf;
}
#undef KMP_ADVANCE_SCAN
// Print the affinity mask to the string buffer object in a pretty format
// The format is a comma separated list of non-negative integers or integer
// ranges: e.g., 1,2,3-5,7,9-15
// The format can also be the string "{<empty>}" if no bits are set in mask
kmp_str_buf_t *__kmp_affinity_str_buf_mask(kmp_str_buf_t *buf,
kmp_affin_mask_t *mask) {
int start = 0, finish = 0, previous = 0;
bool first_range;
KMP_ASSERT(buf);
KMP_ASSERT(mask);
__kmp_str_buf_clear(buf);
// Check for empty set.
if (mask->begin() == mask->end()) {
__kmp_str_buf_print(buf, "%s", "{<empty>}");
return buf;
}
first_range = true;
start = mask->begin();
while (1) {
// Find next range
// [start, previous] is inclusive range of contiguous bits in mask
for (finish = mask->next(start), previous = start;
finish == previous + 1 && finish != mask->end();
finish = mask->next(finish)) {
previous = finish;
}
// The first range does not need a comma printed before it, but the rest
// of the ranges do need a comma beforehand
if (!first_range) {
__kmp_str_buf_print(buf, "%s", ",");
} else {
first_range = false;
}
// Range with three or more contiguous bits in the affinity mask
if (previous - start > 1) {
__kmp_str_buf_print(buf, "%d-%d", static_cast<int>(start),
static_cast<int>(previous));
} else {
// Range with one or two contiguous bits in the affinity mask
__kmp_str_buf_print(buf, "%d", static_cast<int>(start));
if (previous - start > 0) {
__kmp_str_buf_print(buf, ",%d", static_cast<int>(previous));
}
}
// Start over with new start point
start = finish;
if (start == mask->end())
break;
}
return buf;
}
void __kmp_affinity_entire_machine_mask(kmp_affin_mask_t *mask) {
KMP_CPU_ZERO(mask);

View File

@ -1698,6 +1698,11 @@ void __kmp_join_barrier(int gtid) {
if (__kmp_tasking_mode != tskm_immediate_exec) {
__kmp_task_team_wait(this_thr, team USE_ITT_BUILD_ARG(itt_sync_obj));
}
#if OMP_50_ENABLED
if (__kmp_display_affinity) {
KMP_CHECK_UPDATE(team->t.t_display_affinity, 0);
}
#endif
#if KMP_STATS_ENABLED
// Have master thread flag the workers to indicate they are now waiting for
// next parallel region, Also wake them up so they switch their timers to
@ -1985,6 +1990,19 @@ void __kmp_fork_barrier(int gtid, int tid) {
}
#endif
#if OMP_50_ENABLED
// Perform the display affinity functionality
if (__kmp_display_affinity) {
if (team->t.t_display_affinity
#if KMP_AFFINITY_SUPPORTED
|| (__kmp_affinity_type == affinity_balanced && team->t.t_size_changed)
#endif
) {
// NULL means use the affinity-format-var ICV
__kmp_aux_display_affinity(gtid, NULL);
this_thr->th.th_prev_num_threads = team->t.t_nproc;
this_thr->th.th_prev_level = team->t.t_level;
}
}
if (!KMP_MASTER_TID(tid))
KMP_CHECK_UPDATE(this_thr->th.th_def_allocator, team->t.t_def_allocator);
#endif

View File

@ -1867,6 +1867,59 @@ int ompc_get_team_size(int level) {
return __kmp_get_team_size(__kmp_entry_gtid(), level);
}
#if OMP_50_ENABLED
/* OpenMP 5.0 Affinity Format API */
void ompc_set_affinity_format(char const *format) {
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
__kmp_strncpy_truncate(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE,
format, KMP_STRLEN(format) + 1);
}
size_t ompc_get_affinity_format(char *buffer, size_t size) {
size_t format_size;
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
format_size = KMP_STRLEN(__kmp_affinity_format);
if (buffer && size) {
__kmp_strncpy_truncate(buffer, size, __kmp_affinity_format,
format_size + 1);
}
return format_size;
}
void ompc_display_affinity(char const *format) {
int gtid;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
__kmp_aux_display_affinity(gtid, format);
}
size_t ompc_capture_affinity(char *buffer, size_t buf_size,
char const *format) {
int gtid;
size_t num_required;
kmp_str_buf_t capture_buf;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
__kmp_str_buf_init(&capture_buf);
num_required = __kmp_aux_capture_affinity(gtid, format, &capture_buf);
if (buffer && buf_size) {
__kmp_strncpy_truncate(buffer, buf_size, capture_buf.str,
capture_buf.used + 1);
}
__kmp_str_buf_free(&capture_buf);
return num_required;
}
#endif /* OMP_50_ENABLED */
void kmpc_set_stacksize(int arg) {
// __kmp_aux_set_stacksize initializes the library if needed
__kmp_aux_set_stacksize(arg);

View File

@ -21,6 +21,12 @@
#include "kmp_i18n.h"
#if OMP_50_ENABLED
// For affinity format functions
#include "kmp_io.h"
#include "kmp_str.h"
#endif
#if OMPT_SUPPORT
#include "ompt-specific.h"
#endif
@ -389,6 +395,137 @@ void FTN_STDCALL FTN_FREE(void *ptr, const omp_allocator_t *allocator) {
__kmpc_free(__kmp_entry_gtid(), ptr, allocator);
#endif
}
/* OpenMP 5.0 affinity format support */
#ifndef KMP_STUB
static void __kmp_fortran_strncpy_truncate(char *buffer, size_t buf_size,
char const *csrc, size_t csrc_size) {
size_t capped_src_size = csrc_size;
if (csrc_size >= buf_size) {
capped_src_size = buf_size - 1;
}
KMP_STRNCPY_S(buffer, buf_size, csrc, capped_src_size);
if (csrc_size >= buf_size) {
KMP_DEBUG_ASSERT(buffer[buf_size - 1] == '\0');
buffer[buf_size - 1] = csrc[buf_size - 1];
} else {
for (size_t i = csrc_size; i < buf_size; ++i)
buffer[i] = ' ';
}
}
// Convert a Fortran string to a C string by adding null byte
class ConvertedString {
char *buf;
kmp_info_t *th;
public:
ConvertedString(char const *fortran_str, size_t size) {
th = __kmp_get_thread();
buf = (char *)__kmp_thread_malloc(th, size + 1);
KMP_STRNCPY_S(buf, size + 1, fortran_str, size);
buf[size] = '\0';
}
~ConvertedString() { __kmp_thread_free(th, buf); }
const char *get() const { return buf; }
};
#endif // KMP_STUB
/*
* Set the value of the affinity-format-var ICV on the current device to the
* format specified in the argument.
*/
void FTN_STDCALL FTN_SET_AFFINITY_FORMAT(char const *format, size_t size) {
#ifdef KMP_STUB
return;
#else
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
ConvertedString cformat(format, size);
// Since the __kmp_affinity_format variable is a C string, do not
// use the fortran strncpy function
__kmp_strncpy_truncate(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE,
cformat.get(), KMP_STRLEN(cformat.get()));
#endif
}
/*
* Returns the number of characters required to hold the entire affinity format
* specification (not including null byte character) and writes the value of the
* affinity-format-var ICV on the current device to buffer. If the return value
* is larger than size, the affinity format specification is truncated.
*/
size_t FTN_STDCALL FTN_GET_AFFINITY_FORMAT(char *buffer, size_t size) {
#ifdef KMP_STUB
return 0;
#else
size_t format_size;
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
format_size = KMP_STRLEN(__kmp_affinity_format);
if (buffer && size) {
__kmp_fortran_strncpy_truncate(buffer, size, __kmp_affinity_format,
format_size);
}
return format_size;
#endif
}
/*
* Prints the thread affinity information of the current thread in the format
* specified by the format argument. If the format is NULL or a zero-length
* string, the value of the affinity-format-var ICV is used.
*/
void FTN_STDCALL FTN_DISPLAY_AFFINITY(char const *format, size_t size) {
#ifdef KMP_STUB
return;
#else
int gtid;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
ConvertedString cformat(format, size);
__kmp_aux_display_affinity(gtid, cformat.get());
#endif
}
/*
* Returns the number of characters required to hold the entire affinity format
* specification (not including null byte) and prints the thread affinity
* information of the current thread into the character string buffer with the
* size of size in the format specified by the format argument. If the format is
* NULL or a zero-length string, the value of the affinity-format-var ICV is
* used. The buffer must be allocated prior to calling the routine. If the
* return value is larger than size, the affinity format specification is
* truncated.
*/
size_t FTN_STDCALL FTN_CAPTURE_AFFINITY(char *buffer, char const *format,
size_t buf_size, size_t for_size) {
#if defined(KMP_STUB)
return 0;
#else
int gtid;
size_t num_required;
kmp_str_buf_t capture_buf;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
__kmp_str_buf_init(&capture_buf);
ConvertedString cformat(format, for_size);
num_required = __kmp_aux_capture_affinity(gtid, cformat.get(), &capture_buf);
if (buffer && buf_size) {
__kmp_fortran_strncpy_truncate(buffer, buf_size, capture_buf.str,
capture_buf.used);
}
__kmp_str_buf_free(&capture_buf);
return num_required;
#endif
}
#endif /* OMP_50_ENABLED */
int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_THREAD_NUM)(void) {
@ -778,34 +915,7 @@ int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_NUM_TEAMS)(void) {
#ifdef KMP_STUB
return 1;
#else
kmp_info_t *thr = __kmp_entry_thread();
if (thr->th.th_teams_microtask) {
kmp_team_t *team = thr->th.th_team;
int tlevel = thr->th.th_teams_level;
int ii = team->t.t_level; // the level of the teams construct
int dd = team->t.t_serialized;
int level = tlevel + 1;
KMP_DEBUG_ASSERT(ii >= tlevel);
while (ii > level) {
for (dd = team->t.t_serialized; (dd > 0) && (ii > level); dd--, ii--) {
}
if (team->t.t_serialized && (!dd)) {
team = team->t.t_parent;
continue;
}
if (ii > level) {
team = team->t.t_parent;
ii--;
}
}
if (dd > 1) {
return 1; // teams region is serialized ( 1 team of 1 thread ).
} else {
return team->t.t_parent->t.t_nproc;
}
} else {
return 1;
}
return __kmp_aux_get_num_teams();
#endif
}
@ -813,34 +923,7 @@ int FTN_STDCALL KMP_EXPAND_NAME(FTN_GET_TEAM_NUM)(void) {
#ifdef KMP_STUB
return 0;
#else
kmp_info_t *thr = __kmp_entry_thread();
if (thr->th.th_teams_microtask) {
kmp_team_t *team = thr->th.th_team;
int tlevel = thr->th.th_teams_level; // the level of the teams construct
int ii = team->t.t_level;
int dd = team->t.t_serialized;
int level = tlevel + 1;
KMP_DEBUG_ASSERT(ii >= tlevel);
while (ii > level) {
for (dd = team->t.t_serialized; (dd > 0) && (ii > level); dd--, ii--) {
}
if (team->t.t_serialized && (!dd)) {
team = team->t.t_parent;
continue;
}
if (ii > level) {
team = team->t.t_parent;
ii--;
}
}
if (dd > 1) {
return 0; // teams region is serialized ( 1 team of 1 thread ).
} else {
return team->t.t_master_tid;
}
} else {
return 0;
}
return __kmp_aux_get_team_num();
#endif
}

View File

@ -139,6 +139,10 @@
#define FTN_GET_DEFAULT_ALLOCATOR omp_get_default_allocator
#define FTN_ALLOC omp_alloc
#define FTN_FREE omp_free
#define FTN_SET_AFFINITY_FORMAT omp_set_affinity_format
#define FTN_GET_AFFINITY_FORMAT omp_get_affinity_format
#define FTN_DISPLAY_AFFINITY omp_display_affinity
#define FTN_CAPTURE_AFFINITY omp_capture_affinity
#endif
#endif /* KMP_FTN_PLAIN */
@ -265,6 +269,10 @@
#define FTN_GET_DEFAULT_ALLOCATOR omp_get_default_allocator_
#define FTN_ALLOC omp_alloc_
#define FTN_FREE omp_free_
#define FTN_SET_AFFINITY_FORMAT omp_set_affinity_format_
#define FTN_GET_AFFINITY_FORMAT omp_get_affinity_format_
#define FTN_DISPLAY_AFFINITY omp_display_affinity_
#define FTN_CAPTURE_AFFINITY omp_capture_affinity_
#endif
#endif /* KMP_FTN_APPEND */
@ -391,6 +399,10 @@
#define FTN_GET_DEFAULT_ALLOCATOR OMP_GET_DEFAULT_ALLOCATOR
#define FTN_ALLOC OMP_ALLOC
#define FTN_FREE OMP_FREE
#define FTN_SET_AFFINITY_FORMAT OMP_SET_AFFINITY_FORMAT
#define FTN_GET_AFFINITY_FORMAT OMP_GET_AFFINITY_FORMAT
#define FTN_DISPLAY_AFFINITY OMP_DISPLAY_AFFINITY
#define FTN_CAPTURE_AFFINITY OMP_CAPTURE_AFFINITY
#endif
#endif /* KMP_FTN_UPPER */
@ -517,6 +529,10 @@
#define FTN_GET_DEFAULT_ALLOCATOR OMP_GET_DEFAULT_ALLOCATOR_
#define FTN_ALLOC OMP_ALLOC_
#define FTN_FREE OMP_FREE_
#define FTN_SET_AFFINITY_FORMAT OMP_SET_AFFINITY_FORMAT_
#define FTN_GET_AFFINITY_FORMAT OMP_GET_AFFINITY_FORMAT_
#define FTN_DISPLAY_AFFINITY OMP_DISPLAY_AFFINITY_
#define FTN_CAPTURE_AFFINITY OMP_CAPTURE_AFFINITY_
#endif
#endif /* KMP_FTN_UAPPEND */

View File

@ -282,6 +282,11 @@ kmp_nested_proc_bind_t __kmp_nested_proc_bind = {NULL, 0, 0};
int __kmp_affinity_num_places = 0;
#endif
#if OMP_50_ENABLED
int __kmp_display_affinity = FALSE;
char *__kmp_affinity_format = NULL;
#endif // OMP_50_ENABLED
kmp_hws_item_t __kmp_hws_socket = {0, 0};
kmp_hws_item_t __kmp_hws_node = {0, 0};
kmp_hws_item_t __kmp_hws_tile = {0, 0};

View File

@ -46,10 +46,7 @@ kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
#if KMP_OS_WINDOWS
#ifdef KMP_DEBUG
/* __kmp_stdout is used only for dev build */
static HANDLE __kmp_stdout = NULL;
#endif
static HANDLE __kmp_stderr = NULL;
static int __kmp_console_exists = FALSE;
static kmp_str_buf_t __kmp_console_buf;
@ -76,10 +73,7 @@ void __kmp_close_console(void) {
/* wait until user presses return before closing window */
/* TODO only close if a window was opened */
if (__kmp_console_exists) {
#ifdef KMP_DEBUG
/* standard out is used only in dev build */
__kmp_stdout = NULL;
#endif
__kmp_stderr = NULL;
__kmp_str_buf_free(&__kmp_console_buf);
__kmp_console_exists = FALSE;
@ -92,21 +86,17 @@ static void __kmp_redirect_output(void) {
__kmp_acquire_bootstrap_lock(&__kmp_console_lock);
if (!__kmp_console_exists) {
#ifdef KMP_DEBUG
/* standard out is used only in dev build */
HANDLE ho;
#endif
HANDLE he;
__kmp_str_buf_init(&__kmp_console_buf);
AllocConsole();
// We do not check the result of AllocConsole because
// 1. the call is harmless
// 2. it is not clear how to communicate failue
// 3. we will detect failure later when we get handle(s)
// We do not check the result of AllocConsole because
// 1. the call is harmless
// 2. it is not clear how to communicate failue
// 3. we will detect failure later when we get handle(s)
#ifdef KMP_DEBUG
ho = GetStdHandle(STD_OUTPUT_HANDLE);
if (ho == INVALID_HANDLE_VALUE || ho == NULL) {
@ -118,7 +108,6 @@ static void __kmp_redirect_output(void) {
__kmp_stdout = ho; // temporary code, need new global for ho
}
#endif
he = GetStdHandle(STD_ERROR_HANDLE);
if (he == INVALID_HANDLE_VALUE || he == NULL) {
@ -137,22 +126,22 @@ static void __kmp_redirect_output(void) {
#else
#define __kmp_stderr (stderr)
#define __kmp_stdout (stdout)
#endif /* KMP_OS_WINDOWS */
void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap) {
void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) {
#if KMP_OS_WINDOWS
if (!__kmp_console_exists) {
__kmp_redirect_output();
}
if (!__kmp_stderr && __kmp_io == kmp_err) {
if (!__kmp_stderr && out_stream == kmp_err) {
return;
}
#ifdef KMP_DEBUG
if (!__kmp_stdout && __kmp_io == kmp_out) {
if (!__kmp_stdout && out_stream == kmp_out) {
return;
}
#endif
#endif /* KMP_OS_WINDOWS */
auto stream = ((out_stream == kmp_out) ? __kmp_stdout : __kmp_stderr);
if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {
@ -174,14 +163,14 @@ void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap) {
"overflow; increase "
"KMP_DEBUG_BUF_CHARS to %d\n",
chars + 1);
WriteFile(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
&count, NULL);
WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
NULL);
__kmp_str_buf_clear(&__kmp_console_buf);
#else
fprintf(__kmp_stderr, "OMP warning: Debugging buffer overflow; "
"increase KMP_DEBUG_BUF_CHARS to %d\n",
fprintf(stream, "OMP warning: Debugging buffer overflow; "
"increase KMP_DEBUG_BUF_CHARS to %d\n",
chars + 1);
fflush(__kmp_stderr);
fflush(stream);
#endif
__kmp_debug_buf_warn_chars = chars + 1;
}
@ -196,15 +185,15 @@ void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap) {
__kmp_str_buf_print(&__kmp_console_buf, "pid=%d: ", (kmp_int32)getpid());
#endif
__kmp_str_buf_vprint(&__kmp_console_buf, format, ap);
WriteFile(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
&count, NULL);
WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
NULL);
__kmp_str_buf_clear(&__kmp_console_buf);
#else
#ifdef KMP_DEBUG_PIDS
fprintf(__kmp_stderr, "pid=%d: ", (kmp_int32)getpid());
fprintf(stream, "pid=%d: ", (kmp_int32)getpid());
#endif
vfprintf(__kmp_stderr, format, ap);
fflush(__kmp_stderr);
vfprintf(stream, format, ap);
fflush(stream);
#endif
}
}
@ -228,3 +217,14 @@ void __kmp_printf_no_lock(char const *format, ...) {
va_end(ap);
}
void __kmp_fprintf(enum kmp_io stream, char const *format, ...) {
va_list ap;
va_start(ap, format);
__kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
__kmp_vprintf(stream, format, ap);
__kmp_release_bootstrap_lock(&__kmp_stdio_lock);
va_end(ap);
}

View File

@ -26,9 +26,10 @@ extern kmp_bootstrap_lock_t __kmp_stdio_lock; /* Control stdio functions */
extern kmp_bootstrap_lock_t
__kmp_console_lock; /* Control console initialization */
extern void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap);
extern void __kmp_vprintf(enum kmp_io stream, char const *format, va_list ap);
extern void __kmp_printf(char const *format, ...);
extern void __kmp_printf_no_lock(char const *format, ...);
extern void __kmp_fprintf(enum kmp_io stream, char const *format, ...);
extern void __kmp_close_console(void);
#ifdef __cplusplus

View File

@ -105,6 +105,7 @@ typedef long double _Quad;
#define KMP_USE_X87CONTROL 0
#if KMP_OS_WINDOWS
#define KMP_END_OF_LINE "\r\n"
typedef char kmp_int8;
typedef unsigned char kmp_uint8;
typedef short kmp_int16;
@ -140,6 +141,7 @@ typedef unsigned __int64 kmp_uintptr_t;
#endif /* KMP_OS_WINDOWS */
#if KMP_OS_UNIX
#define KMP_END_OF_LINE "\n"
typedef char kmp_int8;
typedef unsigned char kmp_uint8;
typedef short kmp_int16;

View File

@ -1092,6 +1092,19 @@ static void __kmp_fork_team_threads(kmp_root_t *root, kmp_team_t *team,
#endif
}
#if OMP_50_ENABLED
if (__kmp_display_affinity && team->t.t_display_affinity != 1) {
for (i = 0; i < team->t.t_nproc; i++) {
kmp_info_t *thr = team->t.t_threads[i];
if (thr->th.th_prev_num_threads != team->t.t_nproc ||
thr->th.th_prev_level != team->t.t_level) {
team->t.t_display_affinity = 1;
break;
}
}
}
#endif
KMP_MB();
}
@ -1382,6 +1395,20 @@ void __kmp_serialized_parallel(ident_t *loc, kmp_int32 global_tid) {
KMP_CHECK_UPDATE(serial_team->t.t_cancel_request, cancel_noreq);
#endif
#if OMP_50_ENABLED
// Perform the display affinity functionality for
// serialized parallel regions
if (__kmp_display_affinity) {
if (this_thr->th.th_prev_level != serial_team->t.t_level ||
this_thr->th.th_prev_num_threads != 1) {
// NULL means use the affinity-format-var ICV
__kmp_aux_display_affinity(global_tid, NULL);
this_thr->th.th_prev_level = serial_team->t.t_level;
this_thr->th.th_prev_num_threads = 1;
}
}
#endif
if (__kmp_env_consistency_check)
__kmp_push_parallel(global_tid, NULL);
#if OMPT_SUPPORT
@ -1948,7 +1975,7 @@ int __kmp_fork_call(ident_t *loc, int gtid,
KA_TRACE(20, ("__kmp_fork_call: T#%d serial exit\n", gtid));
KMP_MB();
return FALSE;
}
} // if (nthreads == 1)
// GEH: only modify the executing flag in the case when not serialized
// serialized case is handled in kmpc_serialized_parallel
@ -3819,6 +3846,8 @@ int __kmp_register_root(int initial_thread) {
#endif /* KMP_AFFINITY_SUPPORTED */
#if OMP_50_ENABLED
root_thread->th.th_def_allocator = __kmp_def_allocator;
root_thread->th.th_prev_level = 0;
root_thread->th.th_prev_num_threads = 1;
#endif
__kmp_root_counter++;
@ -4360,6 +4389,8 @@ kmp_info_t *__kmp_allocate_thread(kmp_root_t *root, kmp_team_t *team,
#endif
#if OMP_50_ENABLED
new_thr->th.th_def_allocator = __kmp_def_allocator;
new_thr->th.th_prev_level = 0;
new_thr->th.th_prev_num_threads = 1;
#endif
TCW_4(new_thr->th.th_in_pool, FALSE);
@ -4548,6 +4579,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = first_place;
th->th.th_last_place = last_place;
th->th.th_new_place = masters_place;
#if OMP_50_ENABLED
if (__kmp_display_affinity && masters_place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
KA_TRACE(100, ("__kmp_partition_places: master: T#%d(%d:%d) place %d "
"partition = [%d,%d]\n",
@ -4581,6 +4618,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = first_place;
th->th.th_last_place = last_place;
th->th.th_new_place = place;
#if OMP_50_ENABLED
if (__kmp_display_affinity && place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
KA_TRACE(100, ("__kmp_partition_places: close: T#%d(%d:%d) place %d "
"partition = [%d,%d]\n",
@ -4602,6 +4645,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = first_place;
th->th.th_last_place = last_place;
th->th.th_new_place = place;
#if OMP_50_ENABLED
if (__kmp_display_affinity && place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
s_count++;
if ((s_count == S) && rem && (gap_ct == gap)) {
@ -4670,6 +4719,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = place;
th->th.th_new_place = place;
#if OMP_50_ENABLED
if (__kmp_display_affinity && place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
s_count = 1;
while (s_count < S) {
if (place == last_place) {
@ -4761,7 +4816,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = first;
th->th.th_new_place = place;
th->th.th_last_place = last;
#if OMP_50_ENABLED
if (__kmp_display_affinity && place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
KA_TRACE(100,
("__kmp_partition_places: spread: T#%d(%d:%d) place %d "
"partition = [%d,%d], spacing = %.4f\n",
@ -4790,6 +4850,12 @@ static void __kmp_partition_places(kmp_team_t *team, int update_master_only) {
th->th.th_first_place = place;
th->th.th_last_place = place;
th->th.th_new_place = place;
#if OMP_50_ENABLED
if (__kmp_display_affinity && place != th->th.th_current_place &&
team->t.t_display_affinity != 1) {
team->t.t_display_affinity = 1;
}
#endif
s_count++;
if ((s_count == S) && rem && (gap_ct == gap)) {
@ -7410,6 +7476,12 @@ void __kmp_cleanup(void) {
__kmp_nested_proc_bind.bind_types = NULL;
__kmp_nested_proc_bind.size = 0;
__kmp_nested_proc_bind.used = 0;
#if OMP_50_ENABLED
if (__kmp_affinity_format) {
KMP_INTERNAL_FREE(__kmp_affinity_format);
__kmp_affinity_format = NULL;
}
#endif
__kmp_i18n_catclose();
@ -7566,6 +7638,339 @@ void __kmp_aux_set_library(enum library_type arg) {
}
}
/* Getting team information common for all team API */
// Returns NULL if not in teams construct
static kmp_team_t *__kmp_aux_get_team_info(int &teams_serialized) {
kmp_info_t *thr = __kmp_entry_thread();
teams_serialized = 0;
if (thr->th.th_teams_microtask) {
kmp_team_t *team = thr->th.th_team;
int tlevel = thr->th.th_teams_level; // the level of the teams construct
int ii = team->t.t_level;
teams_serialized = team->t.t_serialized;
int level = tlevel + 1;
KMP_DEBUG_ASSERT(ii >= tlevel);
while (ii > level) {
for (teams_serialized = team->t.t_serialized;
(teams_serialized > 0) && (ii > level); teams_serialized--, ii--) {
}
if (team->t.t_serialized && (!teams_serialized)) {
team = team->t.t_parent;
continue;
}
if (ii > level) {
team = team->t.t_parent;
ii--;
}
}
return team;
}
return NULL;
}
int __kmp_aux_get_team_num() {
int serialized;
kmp_team_t *team = __kmp_aux_get_team_info(serialized);
if (team) {
if (serialized > 1) {
return 0; // teams region is serialized ( 1 team of 1 thread ).
} else {
return team->t.t_master_tid;
}
}
return 0;
}
int __kmp_aux_get_num_teams() {
int serialized;
kmp_team_t *team = __kmp_aux_get_team_info(serialized);
if (team) {
if (serialized > 1) {
return 1;
} else {
return team->t.t_parent->t.t_nproc;
}
}
return 1;
}
/* ------------------------------------------------------------------------ */
#if OMP_50_ENABLED
/*
* Affinity Format Parser
*
* Field is in form of: %[[[0].]size]type
* % and type are required (%% means print a literal '%')
* type is either single char or long name surrounded by {},
* e.g., N or {num_threads}
* 0 => leading zeros
* . => right justified when size is specified
* by default output is left justified
* size is the *minimum* field length
* All other characters are printed as is
*
* Available field types:
* L {thread_level} - omp_get_level()
* n {thread_num} - omp_get_thread_num()
* h {host} - name of host machine
* P {process_id} - process id (integer)
* T {thread_identifier} - native thread identifier (integer)
* N {num_threads} - omp_get_num_threads()
* A {ancestor_tnum} - omp_get_ancestor_thread_num(omp_get_level()-1)
* a {thread_affinity} - comma separated list of integers or integer ranges
* (values of affinity mask)
*
* Implementation-specific field types can be added
* If a type is unknown, print "undefined"
*/
// Structure holding the short name, long name, and corresponding data type
// for snprintf. A table of these will represent the entire valid keyword
// field types.
typedef struct kmp_affinity_format_field_t {
char short_name; // from spec e.g., L -> thread level
const char *long_name; // from spec thread_level -> thread level
char field_format; // data type for snprintf (typically 'd' or 's'
// for integer or string)
} kmp_affinity_format_field_t;
static const kmp_affinity_format_field_t __kmp_affinity_format_table[] = {
#if KMP_AFFINITY_SUPPORTED
{'A', "thread_affinity", 's'},
#endif
{'t', "team_num", 'd'},
{'T', "num_teams", 'd'},
{'L', "nesting_level", 'd'},
{'n', "thread_num", 'd'},
{'N', "num_threads", 'd'},
{'a', "ancestor_tnum", 'd'},
{'H', "host", 's'},
{'P', "process_id", 'd'},
{'i', "native_thread_id", 'd'}};
// Return the number of characters it takes to hold field
static int __kmp_aux_capture_affinity_field(int gtid, const kmp_info_t *th,
const char **ptr,
kmp_str_buf_t *field_buffer) {
int rc, format_index, field_value;
const char *width_left, *width_right;
bool pad_zeros, right_justify, parse_long_name, found_valid_name;
static const int FORMAT_SIZE = 20;
char format[FORMAT_SIZE] = {0};
char absolute_short_name = 0;
KMP_DEBUG_ASSERT(gtid >= 0);
KMP_DEBUG_ASSERT(th);
KMP_DEBUG_ASSERT(**ptr == '%');
KMP_DEBUG_ASSERT(field_buffer);
__kmp_str_buf_clear(field_buffer);
// Skip the initial %
(*ptr)++;
// Check for %% first
if (**ptr == '%') {
__kmp_str_buf_cat(field_buffer, "%", 1);
(*ptr)++; // skip over the second %
return 1;
}
// Parse field modifiers if they are present
pad_zeros = false;
if (**ptr == '0') {
pad_zeros = true;
(*ptr)++; // skip over 0
}
right_justify = false;
if (**ptr == '.') {
right_justify = true;
(*ptr)++; // skip over .
}
// Parse width of field: [width_left, width_right)
width_left = width_right = NULL;
if (**ptr >= '0' && **ptr <= '9') {
width_left = *ptr;
SKIP_DIGITS(*ptr);
width_right = *ptr;
}
// Create the format for KMP_SNPRINTF based on flags parsed above
format_index = 0;
format[format_index++] = '%';
if (!right_justify)
format[format_index++] = '-';
if (pad_zeros)
format[format_index++] = '0';
if (width_left && width_right) {
int i = 0;
// Only allow 8 digit number widths.
// This also prevents overflowing format variable
while (i < 8 && width_left < width_right) {
format[format_index++] = *width_left;
width_left++;
i++;
}
}
// Parse a name (long or short)
// Canonicalize the name into absolute_short_name
found_valid_name = false;
parse_long_name = (**ptr == '{');
if (parse_long_name)
(*ptr)++; // skip initial left brace
for (size_t i = 0; i < sizeof(__kmp_affinity_format_table) /
sizeof(__kmp_affinity_format_table[0]);
++i) {
char short_name = __kmp_affinity_format_table[i].short_name;
const char *long_name = __kmp_affinity_format_table[i].long_name;
char field_format = __kmp_affinity_format_table[i].field_format;
if (parse_long_name) {
int length = KMP_STRLEN(long_name);
if (strncmp(*ptr, long_name, length) == 0) {
found_valid_name = true;
(*ptr) += length; // skip the long name
}
} else if (**ptr == short_name) {
found_valid_name = true;
(*ptr)++; // skip the short name
}
if (found_valid_name) {
format[format_index++] = field_format;
format[format_index++] = '\0';
absolute_short_name = short_name;
break;
}
}
if (parse_long_name) {
if (**ptr != '}') {
absolute_short_name = 0;
} else {
(*ptr)++; // skip over the right brace
}
}
// Attempt to fill the buffer with the requested
// value using snprintf within __kmp_str_buf_print()
switch (absolute_short_name) {
case 't':
rc = __kmp_str_buf_print(field_buffer, format, __kmp_aux_get_team_num());
break;
case 'T':
rc = __kmp_str_buf_print(field_buffer, format, __kmp_aux_get_num_teams());
break;
case 'L':
rc = __kmp_str_buf_print(field_buffer, format, th->th.th_team->t.t_level);
break;
case 'n':
rc = __kmp_str_buf_print(field_buffer, format, __kmp_tid_from_gtid(gtid));
break;
case 'H': {
static const int BUFFER_SIZE = 256;
char buf[BUFFER_SIZE];
__kmp_expand_host_name(buf, BUFFER_SIZE);
rc = __kmp_str_buf_print(field_buffer, format, buf);
} break;
case 'P':
rc = __kmp_str_buf_print(field_buffer, format, getpid());
break;
case 'i':
rc = __kmp_str_buf_print(field_buffer, format, __kmp_gettid());
break;
case 'N':
rc = __kmp_str_buf_print(field_buffer, format, th->th.th_team->t.t_nproc);
break;
case 'a':
field_value =
__kmp_get_ancestor_thread_num(gtid, th->th.th_team->t.t_level - 1);
rc = __kmp_str_buf_print(field_buffer, format, field_value);
break;
#if KMP_AFFINITY_SUPPORTED
case 'A': {
kmp_str_buf_t buf;
__kmp_str_buf_init(&buf);
__kmp_affinity_str_buf_mask(&buf, th->th.th_affin_mask);
rc = __kmp_str_buf_print(field_buffer, format, buf.str);
__kmp_str_buf_free(&buf);
} break;
#endif
default:
// According to spec, If an implementation does not have info for field
// type, then "undefined" is printed
rc = __kmp_str_buf_print(field_buffer, "%s", "undefined");
// Skip the field
if (parse_long_name) {
SKIP_TOKEN(*ptr);
if (**ptr == '}')
(*ptr)++;
} else {
(*ptr)++;
}
}
KMP_ASSERT(format_index <= FORMAT_SIZE);
return rc;
}
/*
* Return number of characters needed to hold the affinity string
* (not including null byte character)
* The resultant string is printed to buffer, which the caller can then
* handle afterwards
*/
size_t __kmp_aux_capture_affinity(int gtid, const char *format,
kmp_str_buf_t *buffer) {
const char *parse_ptr;
size_t retval;
const kmp_info_t *th;
kmp_str_buf_t field;
KMP_DEBUG_ASSERT(buffer);
KMP_DEBUG_ASSERT(gtid >= 0);
__kmp_str_buf_init(&field);
__kmp_str_buf_clear(buffer);
th = __kmp_threads[gtid];
retval = 0;
// If format is NULL or zero-length string, then we use
// affinity-format-var ICV
parse_ptr = format;
if (parse_ptr == NULL || *parse_ptr == '\0') {
parse_ptr = __kmp_affinity_format;
}
KMP_DEBUG_ASSERT(parse_ptr);
while (*parse_ptr != '\0') {
// Parse a field
if (*parse_ptr == '%') {
// Put field in the buffer
int rc = __kmp_aux_capture_affinity_field(gtid, th, &parse_ptr, &field);
__kmp_str_buf_catbuf(buffer, &field);
retval += rc;
} else {
// Put literal character in buffer
__kmp_str_buf_cat(buffer, parse_ptr, 1);
retval++;
parse_ptr++;
}
}
__kmp_str_buf_free(&field);
return retval;
}
// Displays the affinity string to stdout
void __kmp_aux_display_affinity(int gtid, const char *format) {
kmp_str_buf_t buf;
__kmp_str_buf_init(&buf);
__kmp_aux_capture_affinity(gtid, format, &buf);
__kmp_fprintf(kmp_out, "%s" KMP_END_OF_LINE, buf.str);
__kmp_str_buf_free(&buf);
}
#endif // OMP_50_ENABLED
/* ------------------------------------------------------------------------ */
void __kmp_aux_set_blocktime(int arg, kmp_info_t *thread, int tid) {

View File

@ -11,6 +11,9 @@
#ifndef KMP_SAFE_C_API_H
#define KMP_SAFE_C_API_H
#include "kmp_platform.h"
#include <string.h>
// Replacement for banned C API
// Not every unsafe call listed here is handled now, but keeping everything
@ -57,4 +60,16 @@
#endif // KMP_OS_WINDOWS
// Offer truncated version of strncpy
static inline void __kmp_strncpy_truncate(char *buffer, size_t buf_size,
char const *src, size_t src_size) {
if (src_size >= buf_size) {
src_size = buf_size - 1;
KMP_STRNCPY_S(buffer, buf_size, src, src_size);
buffer[buf_size - 1] = '\0';
} else {
KMP_STRNCPY_S(buffer, buf_size, src, src_size);
}
}
#endif // KMP_SAFE_C_API_H

View File

@ -3252,7 +3252,29 @@ static void __kmp_stg_print_proc_bind(kmp_str_buf_t *buffer, char const *name,
#endif /* OMP_40_ENABLED */
#if OMP_50_ENABLED
static void __kmp_stg_parse_display_affinity(char const *name,
char const *value, void *data) {
__kmp_stg_parse_bool(name, value, &__kmp_display_affinity);
}
static void __kmp_stg_print_display_affinity(kmp_str_buf_t *buffer,
char const *name, void *data) {
__kmp_stg_print_bool(buffer, name, __kmp_display_affinity);
}
static void __kmp_stg_parse_affinity_format(char const *name, char const *value,
void *data) {
size_t length = KMP_STRLEN(value);
__kmp_strncpy_truncate(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE, value,
length);
}
static void __kmp_stg_print_affinity_format(kmp_str_buf_t *buffer,
char const *name, void *data) {
if (__kmp_env_format) {
KMP_STR_BUF_PRINT_NAME_EX(name);
} else {
__kmp_str_buf_print(buffer, " %s='", name);
}
__kmp_str_buf_print(buffer, "%s'\n", __kmp_affinity_format);
}
// OMP_ALLOCATOR sets default allocator
static void __kmp_stg_parse_allocator(char const *name, char const *value,
void *data) {
@ -4879,7 +4901,12 @@ static kmp_setting_t __kmp_stg_table[] = {
#endif
#endif // KMP_AFFINITY_SUPPORTED
#if OMP_50_ENABLED
{"OMP_DISPLAY_AFFINITY", __kmp_stg_parse_display_affinity,
__kmp_stg_print_display_affinity, NULL, 0, 0},
{"OMP_AFFINITY_FORMAT", __kmp_stg_parse_affinity_format,
__kmp_stg_print_affinity_format, NULL, 0, 0},
#endif
{"KMP_INIT_AT_FORK", __kmp_stg_parse_init_at_fork,
__kmp_stg_print_init_at_fork, NULL, 0, 0},
{"KMP_SCHEDULE", __kmp_stg_parse_schedule, __kmp_stg_print_schedule, NULL,
@ -5409,6 +5436,21 @@ void __kmp_env_initialize(char const *string) {
}
#endif /* OMP_40_ENABLED */
#if OMP_50_ENABLED
// Set up the affinity format ICV
// Grab the default affinity format string from the message catalog
kmp_msg_t m =
__kmp_msg_format(kmp_i18n_msg_AffFormatDefault, "%P", "%i", "%n", "%A");
KMP_DEBUG_ASSERT(KMP_STRLEN(m.str) < KMP_AFFINITY_FORMAT_SIZE);
if (__kmp_affinity_format == NULL) {
__kmp_affinity_format =
(char *)KMP_INTERNAL_MALLOC(sizeof(char) * KMP_AFFINITY_FORMAT_SIZE);
}
KMP_STRCPY_S(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE, m.str);
__kmp_str_free(&m.str);
#endif
// Now process all of the settings.
for (i = 0; i < block.count; ++i) {
__kmp_stg_parse(block.vars[i].name, block.vars[i].value);

View File

@ -143,13 +143,28 @@ void __kmp_str_buf_cat(kmp_str_buf_t *buffer, char const *str, int len) {
KMP_STR_BUF_INVARIANT(buffer);
} // __kmp_str_buf_cat
void __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
va_list args) {
void __kmp_str_buf_catbuf(kmp_str_buf_t *dest, const kmp_str_buf_t *src) {
KMP_DEBUG_ASSERT(dest);
KMP_DEBUG_ASSERT(src);
KMP_STR_BUF_INVARIANT(dest);
KMP_STR_BUF_INVARIANT(src);
if (!src->str || !src->used)
return;
__kmp_str_buf_reserve(dest, dest->used + src->used + 1);
KMP_MEMCPY(dest->str + dest->used, src->str, src->used);
dest->str[dest->used + src->used] = 0;
dest->used += src->used;
KMP_STR_BUF_INVARIANT(dest);
} // __kmp_str_buf_catbuf
// Return the number of characters written
int __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
va_list args) {
int rc;
KMP_STR_BUF_INVARIANT(buffer);
for (;;) {
int const free = buffer->size - buffer->used;
int rc;
int size;
// Try to format string.
@ -198,13 +213,17 @@ void __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
KMP_DEBUG_ASSERT(buffer->size > 0);
KMP_STR_BUF_INVARIANT(buffer);
return rc;
} // __kmp_str_buf_vprint
void __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
// Return the number of characters written
int __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...) {
int rc;
va_list args;
va_start(args, format);
__kmp_str_buf_vprint(buffer, format, args);
rc = __kmp_str_buf_vprint(buffer, format, args);
va_end(args);
return rc;
} // __kmp_str_buf_print
/* The function prints specified size to buffer. Size is expressed using biggest

View File

@ -51,9 +51,10 @@ void __kmp_str_buf_reserve(kmp_str_buf_t *buffer, int size);
void __kmp_str_buf_detach(kmp_str_buf_t *buffer);
void __kmp_str_buf_free(kmp_str_buf_t *buffer);
void __kmp_str_buf_cat(kmp_str_buf_t *buffer, char const *str, int len);
void __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
va_list args);
void __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...);
void __kmp_str_buf_catbuf(kmp_str_buf_t *dest, const kmp_str_buf_t *src);
int __kmp_str_buf_vprint(kmp_str_buf_t *buffer, char const *format,
va_list args);
int __kmp_str_buf_print(kmp_str_buf_t *buffer, char const *format, ...);
void __kmp_str_buf_print_size(kmp_str_buf_t *buffer, size_t size);
/* File name parser.

View File

@ -35,6 +35,10 @@
#define omp_set_num_threads ompc_set_num_threads
#define omp_set_dynamic ompc_set_dynamic
#define omp_set_nested ompc_set_nested
#define omp_set_affinity_format ompc_set_affinity_format
#define omp_get_affinity_format ompc_get_affinity_format
#define omp_display_affinity ompc_display_affinity
#define omp_capture_affinity ompc_capture_affinity
#define kmp_set_stacksize kmpc_set_stacksize
#define kmp_set_stacksize_s kmpc_set_stacksize_s
#define kmp_set_blocktime kmpc_set_blocktime
@ -350,6 +354,17 @@ const omp_allocator_t *omp_low_lat_mem_alloc = (const omp_allocator_t *)5;
const omp_allocator_t *omp_cgroup_mem_alloc = (const omp_allocator_t *)6;
const omp_allocator_t *omp_pteam_mem_alloc = (const omp_allocator_t *)7;
const omp_allocator_t *omp_thread_mem_alloc = (const omp_allocator_t *)8;
/* OpenMP 5.0 Affinity Format */
void omp_set_affinity_format(char const *format) { i; }
size_t omp_get_affinity_format(char *buffer, size_t size) {
i;
return 0;
}
void omp_display_affinity(char const *format) { i; }
size_t omp_capture_affinity(char *buffer, size_t buf_size, char const *format) {
i;
return 0;
}
#endif /* OMP_50_ENABLED */
// end of file //

View File

@ -94,6 +94,9 @@ if config.has_ompt:
if 'Linux' in config.operating_system:
config.available_features.add("linux")
if config.operating_system in ['Linux', 'Windows']:
config.available_features.add('affinity')
# to run with icc INTEL_LICENSE_FILE must be set
if 'INTEL_LICENSE_FILE' in os.environ:
config.environment['INTEL_LICENSE_FILE'] = os.environ['INTEL_LICENSE_FILE']