diff options
Diffstat (limited to 'openmp/runtime/src/kmp_runtime.cpp')
-rw-r--r-- | openmp/runtime/src/kmp_runtime.cpp | 409 |
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) { |