From 310579b9a76016e83370fa3fcbe6f5f1a59f101f Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 1 Jul 2024 17:33:43 -0400 Subject: [PATCH] Load options from environment variables Some common VTK-m options such as the device and log level could be specified on the command line but not through environment variables. It is not always possible to set VTK-m command line options, so environment variables are added. Also added documentation to the user's guide about what options are available and how to set them. --- docs/changelog/env-options.md | 9 ++++ docs/users-guide/initialization.rst | 38 +++++++++++++++ vtkm/cont/Initialize.cxx | 72 +++++++++++++++++++++-------- vtkm/cont/Logging.cxx | 19 ++++++-- vtkm/cont/Logging.h | 5 +- 5 files changed, 119 insertions(+), 24 deletions(-) create mode 100644 docs/changelog/env-options.md diff --git a/docs/changelog/env-options.md b/docs/changelog/env-options.md new file mode 100644 index 000000000..857d8446b --- /dev/null +++ b/docs/changelog/env-options.md @@ -0,0 +1,9 @@ +## Load options from environment variables + +Some common VTK-m options such as the device and log level could be +specified on the command line but not through environment variables. It is +not always possible to set VTK-m command line options, so environment +variables are added. + +Also added documentation to the user's guide about what options are +available and how to set them. diff --git a/docs/users-guide/initialization.rst b/docs/users-guide/initialization.rst index 16fd8fc60..ae02d1f69 100644 --- a/docs/users-guide/initialization.rst +++ b/docs/users-guide/initialization.rst @@ -19,6 +19,44 @@ But it can also optionally take the ``argc`` and ``argv`` arguments to the ``mai |VTKm| accepts arguments that, for example, configure the compute device to use or establish logging levels. Any arguments that are handled by |VTKm| are removed from the ``argc``/``argv`` list so that your program can then respond to the remaining arguments. +Many options can also be set with environment variables. +If both the environment variable and command line argument are provided, the command line argument is used. +The following table lists the currently supported options. + +.. list-table:: |VTKm| command line arguments and environment variable options. + :widths: 23 22 15 40 + :header-rows: 1 + + * - Command Line Argument + - Environment Variable + - Default Value + - Description + * - ``--vtkm-help`` + - + - + - Causes the program to print information about |VTKm| command line arguments and then exits the program. + * - ``--vtkm-log-level`` + - ``VTKM_LOG_LEVEL`` + - ``WARNING`` + - Specifies the logging level. + Valid values are ``INFO``, ``WARNING``, ``ERROR``, ``FATAL``, and ``OFF``. + This can also be set to a numeric value for the logging level. + * - ``--vtkm-device`` + - ``VTKM_DEVICE`` + - + - Force |VTKm| to use the specified device. + If not specified or ``Any`` given, then any available device may be used. + * - ``--vtkm-num-threads`` + - ``VTKM_NUM_THREADS`` + - + - Set the number of threads to use on a multi-core device. + If not specified, the device will use the cores available in the system. + * - ``--vtkm-device-instance`` + - ``VTKM_DEVICE_INSTANCE`` + - + - Selects the device to use when more than one device device of a given type is available. + The device is specified with a numbered index. + :func:`vtkm::cont::Initialize` returns a :struct:`vtkm::cont::InitializeResult` structure. This structure contains information about the supported arguments and options selected during initialization. diff --git a/vtkm/cont/Initialize.cxx b/vtkm/cont/Initialize.cxx index bee25c5ec..cdbb29d70 100644 --- a/vtkm/cont/Initialize.cxx +++ b/vtkm/cont/Initialize.cxx @@ -17,6 +17,7 @@ #include +#include #include #include @@ -123,7 +124,7 @@ InitializeResult Initialize(int& argc, char* argv[], InitializeOptions opts) } else { - vtkm::cont::InitLogging(argc, argv, loggingFlag); + vtkm::cont::InitLogging(argc, argv, loggingFlag, "VTKM_LOG_LEVEL"); } if (!vtkmdiy::mpi::environment::initialized()) { @@ -225,37 +226,70 @@ InitializeResult Initialize(int& argc, char* argv[], InitializeOptions opts) vtkm::cont::DeviceAdapterTagAny{}, runtimeDeviceOptions, argc, argv); } + // Check for device on command line. if (options[opt::OptionIndex::DEVICE]) { const char* arg = options[opt::OptionIndex::DEVICE].arg; - auto id = vtkm::cont::make_DeviceAdapterId(arg); - if (id != vtkm::cont::DeviceAdapterTagAny{}) + config.Device = vtkm::cont::make_DeviceAdapterId(arg); + } + // If not on command line, check for device in environment variable. + if (config.Device == vtkm::cont::DeviceAdapterTagUndefined{}) + { + const char* deviceEnv = std::getenv("VTKM_DEVICE"); + if (deviceEnv != nullptr) { - vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(id); + auto id = vtkm::cont::make_DeviceAdapterId(std::getenv("VTKM_DEVICE")); + if (VtkmDeviceArg::DeviceIsAvailable(id)) + { + config.Device = id; + } + else + { + // Got invalid device. Log an error, but continue to do the default action for + // the device (i.e., ignore the environment variable setting). + VTKM_LOG_S(vtkm::cont::LogLevel::Error, + "Invalid device `" + << deviceEnv + << "` specified in VTKM_DEVICE environment variable. Ignoring."); + VTKM_LOG_S(vtkm::cont::LogLevel::Error, + "Valid devices are: " << VtkmDeviceArg::GetValidDeviceNames()); + } + } + } + // If still not defined, check to see if "any" device should be added. + if ((config.Device == vtkm::cont::DeviceAdapterTagUndefined{}) && + (opts & InitializeOptions::DefaultAnyDevice) != InitializeOptions::None) + { + config.Device = vtkm::cont::DeviceAdapterTagAny{}; + } + // Set the state for the device selected. + if (config.Device == vtkm::cont::DeviceAdapterTagUndefined{}) + { + if ((opts & InitializeOptions::RequireDevice) != InitializeOptions::None) + { + auto devices = VtkmDeviceArg::GetValidDeviceNames(); + VTKM_LOG_S(vtkm::cont::LogLevel::Fatal, "Device not given on command line."); + std::cerr << "Target device must be specified via --vtkm-device.\n" + "Valid devices: " + << devices << std::endl; + if ((opts & InitializeOptions::AddHelp) != InitializeOptions::None) + { + std::cerr << config.Usage; + } + exit(1); } else { - vtkm::cont::GetRuntimeDeviceTracker().Reset(); + // No device specified. Do nothing and let VTK-m decide what it is going to do. } - config.Device = id; } - else if ((opts & InitializeOptions::DefaultAnyDevice) != InitializeOptions::None) + else if (config.Device == vtkm::cont::DeviceAdapterTagAny{}) { vtkm::cont::GetRuntimeDeviceTracker().Reset(); - config.Device = vtkm::cont::DeviceAdapterTagAny{}; } - else if ((opts & InitializeOptions::RequireDevice) != InitializeOptions::None) + else { - auto devices = VtkmDeviceArg::GetValidDeviceNames(); - VTKM_LOG_S(vtkm::cont::LogLevel::Error, "Device not given on command line."); - std::cerr << "Target device must be specified via --vtkm-device.\n" - "Valid devices: " - << devices << std::endl; - if ((opts & InitializeOptions::AddHelp) != InitializeOptions::None) - { - std::cerr << config.Usage; - } - exit(1); + vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(config.Device); } diff --git a/vtkm/cont/Logging.cxx b/vtkm/cont/Logging.cxx index e4d8510ab..51f541825 100644 --- a/vtkm/cont/Logging.cxx +++ b/vtkm/cont/Logging.cxx @@ -30,7 +30,7 @@ #endif // VTKM_ENABLE_LOGGING -#include +#include #include #include #include @@ -108,7 +108,10 @@ namespace cont { VTKM_CONT -void InitLogging(int& argc, char* argv[], const std::string& loggingFlag) +void InitLogging(int& argc, + char* argv[], + const std::string& loggingFlag, + const std::string& loggingEnv) { SetLogLevelName(vtkm::cont::LogLevel::Off, "Off"); SetLogLevelName(vtkm::cont::LogLevel::Fatal, "FATL"); @@ -130,8 +133,16 @@ void InitLogging(int& argc, char* argv[], const std::string& loggingFlag) loguru::set_verbosity_to_name_callback(&verbosityToNameCallback); loguru::set_name_to_verbosity_callback(&nameToVerbosityCallback); - // Set the default log level to warning - SetStderrLogLevel(vtkm::cont::LogLevel::Warn); + const char* envLevel = std::getenv(loggingEnv.c_str()); + if (envLevel != nullptr) + { + SetStderrLogLevel(envLevel); + } + else + { + // Set the default log level to warning + SetStderrLogLevel(vtkm::cont::LogLevel::Warn); + } loguru::init(argc, argv, loggingFlag.c_str()); } #else // VTKM_ENABLE_LOGGING diff --git a/vtkm/cont/Logging.h b/vtkm/cont/Logging.h index a251cde14..617e00d51 100644 --- a/vtkm/cont/Logging.h +++ b/vtkm/cont/Logging.h @@ -371,7 +371,10 @@ enum class LogLevel */ VTKM_CONT_EXPORT VTKM_CONT -void InitLogging(int& argc, char* argv[], const std::string& loggingFlag = "--vtkm-log-level"); +void InitLogging(int& argc, + char* argv[], + const std::string& loggingFlag = "--vtkm-log-level", + const std::string& loggingEnv = "VTKM_LOG_LEVEL"); VTKM_CONT_EXPORT VTKM_CONT void InitLogging();