/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2014 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. * Copyright (c) 2010-2014 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014 Hochschule Esslingen. All rights reserved. * Copyright (c) 2015-2023 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2015 Mellanox Technologies, Inc. * All rights reserved. * Copyright (c) 2017 IBM Corporation. All rights reserved. * Copyright (c) 2018-2022 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved. * Copyright (c) 2022 Computer Architecture and VLSI Systems (CARV) * Laboratory, ICS Forth. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #include #include "opal/constants.h" #include "opal/datatype/opal_datatype.h" #include "opal/mca/base/mca_base_var.h" #include "opal/mca/shmem/base/base.h" #include "opal/mca/threads/mutex.h" #include "opal/mca/threads/threads.h" #include "opal/runtime/opal.h" #include "opal/runtime/opal_params_core.h" #include "opal/util/opal_environ.h" #include "opal/util/printf.h" #include "opal/util/show_help.h" #include "opal/util/timings.h" #include "opal/util/argv.h" char *opal_signal_string = NULL; char *opal_stacktrace_output_filename = NULL; char *opal_net_private_ipv4 = NULL; char *opal_set_max_sys_limits = NULL; char *opal_var_dump_color[OPAL_VAR_DUMP_COLOR_KEY_COUNT] = {NULL}; #if OPAL_ENABLE_TIMING char *opal_timing_sync_file = NULL; char *opal_timing_output = NULL; bool opal_timing_overhead = true; #endif bool opal_built_with_cuda_support = OPAL_INT_TO_BOOL(OPAL_CUDA_SUPPORT); bool opal_cuda_runtime_initialized = false; bool opal_cuda_support = false; bool opal_warn_on_missing_libcuda = true; bool opal_built_with_rocm_support = OPAL_INT_TO_BOOL(OPAL_ROCM_SUPPORT); bool opal_rocm_runtime_initialized = false; /** * Globals imported from the OMPI layer. */ int opal_leave_pinned = -1; bool opal_leave_pinned_pipeline = false; bool opal_abort_print_stack = false; int opal_abort_delay = 0; int opal_max_thread_in_progress = 1; static bool opal_register_util_done = false; static char *opal_var_dump_color_string = NULL; static char *opal_var_dump_color_keys[OPAL_VAR_DUMP_COLOR_KEY_COUNT+1] = { [OPAL_VAR_DUMP_COLOR_VAR_NAME] = "name", [OPAL_VAR_DUMP_COLOR_VAR_VALUE] = "value", [OPAL_VAR_DUMP_COLOR_VALID_VALUES] = "valid_values", [OPAL_VAR_DUMP_COLOR_KEY_COUNT] = NULL }; /** * Local functions */ static int parse_color_string(char *color_string, char **key_names, int key_count, char **values_out); static void opal_deregister_util_params(void) { for (int i = 0; i < OPAL_VAR_DUMP_COLOR_KEY_COUNT; i++) { free(opal_var_dump_color[i]); opal_var_dump_color[i] = NULL; } /* The MCA variable system will be torn down shortly so reset the registered * flag. */ opal_register_util_done = false; } int opal_register_util_params(void) { int ret; char *string = NULL, *tmp = NULL; if (opal_register_util_done) { return OPAL_SUCCESS; } opal_register_util_done = true; /* * This string is going to be used in opal/util/stacktrace.c */ { int j; int signals[] = { #ifdef SIGABRT SIGABRT, #endif #ifdef SIGBUS SIGBUS, #endif #ifdef SIGFPE SIGFPE, #endif #ifdef SIGSEGV SIGSEGV, #endif -1}; for (j = 0; signals[j] != -1; ++j) { if (j == 0) { ret = opal_asprintf(&string, "%d", signals[j]); } else { ret = opal_asprintf(&tmp, "%s,%d", string, signals[j]); free(string); string = tmp; } if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } } opal_signal_string = string; ret = mca_base_var_register( "opal", "opal", NULL, "signal", "Comma-delimited list of integer signal numbers to Open MPI to attempt to intercept. " "Upon receipt of the intercepted signal, Open MPI will display a stack trace and " "abort. Open MPI will *not* replace signals if handlers are already installed by the " "time MPI_INIT is invoked. Optionally append \":complain\" to any signal number in " "the comma-delimited list to make Open MPI complain if it detects another signal " "handler (and therefore does not insert its own).", MCA_BASE_VAR_TYPE_STRING, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_LOCAL, &opal_signal_string); free(string); if (0 > ret) { return ret; } } /* * Where should the stack trace output be directed * This string is going to be used in opal/util/stacktrace.c */ string = strdup("stderr"); opal_stacktrace_output_filename = string; ret = mca_base_var_register( "opal", "opal", NULL, "stacktrace_output", "Specifies where the stack trace output stream goes. " "Accepts one of the following: none (disabled), stderr (default), stdout, file[:filename]. " " " "If 'filename' is not specified, a default filename of 'stacktrace' is used. " "The 'filename' is appended with either '.PID' or '.RANK.PID', if RANK is available. " "The 'filename' can be an absolute path or a relative path to the current working " "directory.", MCA_BASE_VAR_TYPE_STRING, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_LOCAL, &opal_stacktrace_output_filename); free(string); if (0 > ret) { return ret; } #if OPAL_ENABLE_DEBUG opal_debug_threads = false; ret = mca_base_var_register("opal", "opal", "debug", "threads", "Debug thread usage within OPAL. Reports out " "when threads are acquired and released.", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_8, MCA_BASE_VAR_SCOPE_LOCAL, &opal_debug_threads); if (0 > ret) { return ret; } #endif /* RFC1918 defines - 10.0.0./8 - 172.16.0.0/12 - 192.168.0.0/16 RFC3330 also mentions - 169.254.0.0/16 for DHCP onlink iff there's no DHCP server */ opal_net_private_ipv4 = "10.0.0.0/8;172.16.0.0/12;192.168.0.0/16;169.254.0.0/16"; ret = mca_base_var_register( "opal", "opal", "net", "private_ipv4", "Semicolon-delimited list of CIDR notation entries specifying what networks are considered " "\"private\" (default value based on RFC1918 and RFC3330)", MCA_BASE_VAR_TYPE_STRING, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_ALL_EQ, &opal_net_private_ipv4); if (0 > ret) { return ret; } opal_set_max_sys_limits = NULL; ret = mca_base_var_register( "opal", "opal", NULL, "set_max_sys_limits", "Set the specified system-imposed limits to the specified value, including \"unlimited\"." "Supported params: core, filesize, maxmem, openfiles, stacksize, maxchildren", MCA_BASE_VAR_TYPE_STRING, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_ALL_EQ, &opal_set_max_sys_limits); if (0 > ret) { return ret; } /* Var-dump color */ string = opal_argv_join_range(opal_var_dump_color_keys, 0, OPAL_VAR_DUMP_COLOR_KEY_COUNT, ','); if (NULL == string) { return OPAL_ERR_OUT_OF_RESOURCE; } ret = opal_asprintf(&tmp, "The colors to use when dumping MCA vars with color " "(e.g. ompi_info). The format is a comma-delimited key=value list, where the " "key is the attribute whose color to adjust, and the value is the ANSI color " "code (see the ANSI X3.64 CSI SGR sequence). Available keys: %s.", string); free(string); string = tmp; if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } /* Basic color options: 30=black, 31=red, 32=green, * 33=yellow, 34=blue, 35=magenta, 36=cyan, 37=white * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors */ opal_var_dump_color_string = "name=34,value=32,valid_values=36"; ret = mca_base_var_register("opal", "opal", NULL, "var_dump_color", string, MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, OPAL_INFO_LVL_2, MCA_BASE_VAR_SCOPE_READONLY, &opal_var_dump_color_string); free(string); if (0 > ret) { return ret; } ret = parse_color_string(opal_var_dump_color_string, opal_var_dump_color_keys, OPAL_VAR_DUMP_COLOR_KEY_COUNT, opal_var_dump_color); if (OPAL_SUCCESS != ret) { return ret; } /* CUDA support */ ret = mca_base_var_register("opal", "opal", NULL, "built_with_cuda_support", "Whether CUDA GPU buffer support is built into library or not", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_DEFAULT_ONLY, OPAL_INFO_LVL_4, MCA_BASE_VAR_SCOPE_CONSTANT, &opal_built_with_cuda_support); if (0 > ret) { return ret; } /* Current default is to enable CUDA support if it is built into library */ opal_cuda_support = opal_built_with_cuda_support; ret = mca_base_var_register("opal", "opal", NULL, "cuda_support", "Whether CUDA GPU buffer support is enabled or not", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_ALL_EQ, &opal_cuda_support); if (0 > ret) { return ret; } opal_warn_on_missing_libcuda = true; ret = mca_base_var_register( "opal", "opal", NULL, "warn_on_missing_libcuda", "Whether to print a message when CUDA support is enabled but libcuda is not found", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_ALL_EQ, &opal_warn_on_missing_libcuda); if (0 > ret) { return ret; } /* Leave pinned parameter */ opal_leave_pinned = -1; ret = mca_base_var_register( "ompi", "mpi", NULL, "leave_pinned", "Whether to use the \"leave pinned\" protocol or not. Enabling this setting can help " "bandwidth performance when repeatedly sending and receiving large messages with the same " "buffers over RDMA-based networks (false = do not use \"leave pinned\" protocol, true = " "use \"leave pinned\" protocol, auto = allow network to choose at runtime).", MCA_BASE_VAR_TYPE_INT, &mca_base_var_enum_auto_bool, 0, 0, OPAL_INFO_LVL_9, MCA_BASE_VAR_SCOPE_READONLY, &opal_leave_pinned); mca_base_var_register_synonym(ret, "opal", "opal", NULL, "leave_pinned", MCA_BASE_VAR_SYN_FLAG_DEPRECATED); opal_leave_pinned_pipeline = false; ret = mca_base_var_register("ompi", "mpi", NULL, "leave_pinned_pipeline", "Whether to use the \"leave pinned pipeline\" protocol or not.", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, 0, OPAL_INFO_LVL_9, MCA_BASE_VAR_SCOPE_READONLY, &opal_leave_pinned_pipeline); mca_base_var_register_synonym(ret, "opal", "opal", NULL, "leave_pinned_pipeline", MCA_BASE_VAR_SYN_FLAG_DEPRECATED); if (opal_leave_pinned > 0 && opal_leave_pinned_pipeline) { opal_leave_pinned_pipeline = 0; opal_show_help("help-opal-runtime.txt", "mpi-params:leave-pinned-and-pipeline-selected", true); } opal_warn_on_fork = true; (void) mca_base_var_register("ompi", "mpi", NULL, "warn_on_fork", "If nonzero, issue a warning if program forks under conditions " "that could cause system errors", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, 0, OPAL_INFO_LVL_9, MCA_BASE_VAR_SCOPE_READONLY, &opal_warn_on_fork); opal_abort_delay = 0; ret = mca_base_var_register( "opal", "opal", NULL, "abort_delay", "If nonzero, print out an identifying message when abort operation is invoked (hostname, " "PID of the process that called abort) and delay for that many seconds before exiting (a " "negative delay value means to never abort). This allows attaching of a debugger before " "quitting the job.", MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5, MCA_BASE_VAR_SCOPE_READONLY, &opal_abort_delay); if (0 > ret) { return ret; } opal_abort_print_stack = false; ret = mca_base_var_register("opal", "opal", NULL, "abort_print_stack", "If nonzero, print out a stack trace when abort is invoked", MCA_BASE_VAR_TYPE_BOOL, NULL, 0, /* If we do not have stack trace capability, make this a constant MCA variable */ #if OPAL_WANT_PRETTY_PRINT_STACKTRACE 0, OPAL_INFO_LVL_5, MCA_BASE_VAR_SCOPE_READONLY, #else MCA_BASE_VAR_FLAG_DEFAULT_ONLY, OPAL_INFO_LVL_5, MCA_BASE_VAR_SCOPE_CONSTANT, #endif &opal_abort_print_stack); if (0 > ret) { return ret; } /* register the envar-forwarding params */ (void) mca_base_var_register("opal", "mca", "base", "env_list", "Set SHELL env variables", MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_READONLY, &mca_base_env_list); mca_base_env_list_sep = MCA_BASE_ENV_LIST_SEP_DEFAULT; (void) mca_base_var_register("opal", "mca", "base", "env_list_delimiter", "Set SHELL env variables delimiter. Default: semicolon ';'", MCA_BASE_VAR_TYPE_STRING, NULL, 0, 0, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_READONLY, &mca_base_env_list_sep); /* Set OMPI_MCA_mca_base_env_list variable, it might not be set before * if mca variable was taken from amca conf file. Need to set it * here because mca_base_var_process_env_list is called from schizo_ompi.c * only when this env variable was set. */ if (NULL != mca_base_env_list) { char *name = NULL; (void) mca_base_var_env_name("mca_base_env_list", &name); if (NULL != name) { opal_setenv(name, mca_base_env_list, false, &environ); free(name); } } /* Register internal MCA variable mca_base_env_list_internal. It can be set only during * parsing of amca conf file and contains SHELL env variables specified via -x there. * Its format is the same as for mca_base_env_list. */ (void) mca_base_var_register("opal", "mca", "base", "env_list_internal", "Store SHELL env variables from amca conf file", MCA_BASE_VAR_TYPE_STRING, NULL, 0, MCA_BASE_VAR_FLAG_INTERNAL, OPAL_INFO_LVL_3, MCA_BASE_VAR_SCOPE_READONLY, &mca_base_env_list_internal); /* Number of threads allowed in opal_progress. This might increase multithreaded performance. */ (void) mca_base_var_register("opal", "opal", NULL, "max_thread_in_progress", "Number of thread allowed in opal_progress. Default: 1", MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_8, MCA_BASE_VAR_SCOPE_READONLY, &opal_max_thread_in_progress); opal_finalize_register_cleanup(opal_deregister_util_params); return OPAL_SUCCESS; } /* Parses a color 'string' and extracts the 'code' for each 'key' * The string is in the format of 'key1=code1:key2=code2:...' * Example: opal_var_dump_color MCA parameter * * color_string: The string containing the key=code sequences to parse * key_names: The keys to extract (e.g. key1, key2) * key_count: The length of key_names * values_out: The extracted values for the keys, 1-1 with key_names * ATTENTION: Make sure it's at least as large as key_names... */ static int parse_color_string(char *color_string, char **key_names, int key_count, char **values_out) { char **tokens = NULL, **kv = NULL; int return_code = OPAL_SUCCESS; for (int k = 0; k < key_count; k++) { values_out[k] = NULL; } if (NULL != color_string) { tokens = opal_argv_split(color_string, ','); if (NULL == tokens) { return_code = OPAL_ERR_OUT_OF_RESOURCE; goto end; } } for (int i = 0; tokens && tokens[i] != NULL; i++) { kv = opal_argv_split(tokens[i], '='); if (NULL == kv) { return_code = OPAL_ERR_OUT_OF_RESOURCE; goto end; } // Expected format of token: key=code if (opal_argv_count(kv) != 2) { opal_show_help("help-opal-runtime.txt", "mpi-params:var_dump_color:format-error", true, tokens[i]); goto skip_token; } bool key_found = false; // Look for key name and store value in respective position for (int k = 0; k < key_count; ++k) { if (strcasecmp(key_names[k], kv[0]) == 0) { int ret = opal_asprintf(&values_out[k], "\033[%sm", kv[1]); if (ret < 0) { return_code = OPAL_ERR_OUT_OF_RESOURCE; goto end; } key_found = true; break; } } if (!key_found) { char *valid_keys = opal_argv_join_range(key_names, 0, key_count, ','); if (NULL == valid_keys) { return_code = OPAL_ERR_OUT_OF_RESOURCE; goto end; } opal_show_help("help-opal-runtime.txt", "mpi-params:var_dump_color:unknown-key", true, kv[0], tokens[i], valid_keys); free(valid_keys); } skip_token: opal_argv_free(kv); kv = NULL; } // Set values for keys not in the MCA parameter to "" for (int k = 0; k < key_count; k++) { if (NULL == values_out[k]) { values_out[k] = strdup(""); // needs to be free-able if (NULL == values_out[k]) { return_code = OPAL_ERR_OUT_OF_RESOURCE; goto end; } } } end: opal_argv_free(tokens); opal_argv_free(kv); if (return_code != OPAL_SUCCESS) { for (int k = 0; k < key_count; k++) { free(values_out[k]); values_out[k] = NULL; } } return return_code; }