summaryrefslogtreecommitdiffstats
path: root/openmp/runtime/src/kmp_runtime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'openmp/runtime/src/kmp_runtime.cpp')
-rw-r--r--openmp/runtime/src/kmp_runtime.cpp409
1 files changed, 407 insertions, 2 deletions
diff --git a/openmp/runtime/src/kmp_runtime.cpp b/openmp/runtime/src/kmp_runtime.cpp
index 5fb6e2623ee..f0b81dd50c9 100644
--- a/openmp/runtime/src/kmp_runtime.cpp
+++ b/openmp/runtime/src/kmp_runtime.cpp
@@ -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) {
OpenPOWER on IntegriCloud