From 370b893d5cdc6beb7bd0ea4aa1e74922b30d5233 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 8 Feb 2022 13:56:42 -0800 Subject: [PATCH] Break uuid_utils header into subcomponents --- .../uitsl/utility/generate_random_uuid.hpp | 35 ++++++ .../uitsl/utility/get_exec_instance_uuid.hpp | 101 +++++++++++++++ .../uitsl/utility/get_proc_instance_uuid.hpp | 18 +++ .../utility/get_thread_instance_uuid.hpp | 18 +++ include/uitsl/utility/uuid_utils.hpp | 116 +----------------- 5 files changed, 176 insertions(+), 112 deletions(-) create mode 100644 include/uitsl/utility/generate_random_uuid.hpp create mode 100644 include/uitsl/utility/get_exec_instance_uuid.hpp create mode 100644 include/uitsl/utility/get_proc_instance_uuid.hpp create mode 100644 include/uitsl/utility/get_thread_instance_uuid.hpp diff --git a/include/uitsl/utility/generate_random_uuid.hpp b/include/uitsl/utility/generate_random_uuid.hpp new file mode 100644 index 0000000000..9aa3ab5c3a --- /dev/null +++ b/include/uitsl/utility/generate_random_uuid.hpp @@ -0,0 +1,35 @@ +#pragma once +#ifndef UITSL_UTILITY_GENERATE_RANDOM_UUID_HPP_INCLUDE +#define UITSL_UTILITY_GENERATE_RANDOM_UUID_HPP_INCLUDE + +#include +#include +#include +#include + +#include "../../../third-party/stduuid/include/uuid.h" + +namespace uitsl { + +uuids::uuid generate_random_uuid() { + thread_local auto random_generator = [](){ + // workaround for error encountered when multiprocesses share same node + // > terminate called after throwing an instance of 'std::runtime_error' + // > what(): random_device: rdseed failed + // see https://github.com/xdspacelab/openvslam/issues/319#issuecomment-630225541 + // see https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device + std::random_device rd("rdrand"); + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + return std::mt19937(seq); + }(); + thread_local uuids::uuid_random_generator uuid_generator( random_generator ); + + return uuid_generator(); + +} + +} // namespace uitsl + +#endif // #ifndef UITSL_UTILITY_GENERATE_RANDOM_UUID_HPP_INCLUDE diff --git a/include/uitsl/utility/get_exec_instance_uuid.hpp b/include/uitsl/utility/get_exec_instance_uuid.hpp new file mode 100644 index 0000000000..0263551bbc --- /dev/null +++ b/include/uitsl/utility/get_exec_instance_uuid.hpp @@ -0,0 +1,101 @@ +#pragma once +#ifndef UITSL_UTILITY_GET_EXEC_INSTANCE_UUID_HPP_INCLUDE +#define UITSL_UTILITY_GET_EXEC_INSTANCE_UUID_HPP_INCLUDE + +#include +#include +#include +#include +#include + +#include "../../../third-party/Empirical/include/emp/base/always_assert.hpp" +#include "../../../third-party/Empirical/include/emp/base/error.hpp" +#include "../../../third-party/Empirical/include/emp/tools/keyname_utils.hpp" +#include "../../../third-party/Empirical/include/emp/tools/keyname_utils.hpp" +#include "../../../third-party/Empirical/include/emp/tools/string_utils.hpp" +#include "../../../third-party/stduuid/include/uuid.h" + +#include "../mpi/comm_utils.hpp" +#include "../mpi/mpi_init_utils.hpp" +#include "../polyfill/filesystem.hpp" + +#include "generate_random_uuid.hpp" + +namespace uitsl { + +uuids::uuid get_exec_instance_uuid() { + + static auto uuid = [](){ + + uuids::uuid res; + + // try to set up res uuid using a series of fallback options... + // 1. if not multiprocess, can use random uuid generation + if ( !uitsl::is_multiprocess() ) res = uitsl::generate_random_uuid(); + // 2. if user provided UITSL_EXEC_INSTANCE_UUID, verify it and then use it + else if ( const char* seed = std::getenv("UITSL_EXEC_INSTANCE_UUID") ) { + auto parsed = uuids::uuid::from_string(seed); + emp_always_assert( + parsed.has_value(), + "UITSL_EXEC_INSTANCE_UUID must be a valid uuid", seed + ); + emp_always_assert( + !parsed->is_nil(), + "UITSL_EXEC_INSTANCE_UUID must be a non-nil uuid", seed, *parsed + ); + res = *parsed; + // 3. if PMIX_NAMESPACE is available, use that to make uuid + } else if ( const char* seed = std::getenv("PMIX_NAMESPACE") ) { + // is PMIX_NAMESPACE actually a good uuid seed? not sure + // note: PMIX_NAMESPACE only seems to be provided by OpenMPI + res = uuids::uuid_name_generator{ uuids::uuid{} }(seed); + // 4. no good options left, fail + } else emp_error( + "Need env var UITSL_EXEC_INSTANCE_UUID or PMIX_NAMESPACE " + "for get_multiprocess_exec_instance_uuid.\n" + "Hint: call " + "`export UITSL_EXEC_INSTANCE_UUID=\"$(cat /proc/sys/kernel/random/uuid)\"" + " _each time_ prior to launching with mpiexec." + ); + + // do a quick (non-exhaustive) check for obvious user misuse + // i.e., that uuid is actually unique + const auto reservation_path = std::filesystem::temp_directory_path() + / emp::keyname::pack({ + {"a", "uitsl_exec_instance_uuid"}, + {"rank",emp::to_string( uitsl::get_proc_id() )}, + {"uid", uuids::to_string( res )}, + }); + emp_always_assert( + !std::filesystem::exists( reservation_path ), + reservation_path, + uitsl::is_multiprocess(), + std::getenv("UITSL_EXEC_INSTANCE_UUID"), + std::getenv("PMIX_NAMESPACE") + ); + + // touch reservation_path + // adapted from https://stackoverflow.com/a/54451555 + std::ofstream output(reservation_path); + + return res; + + }(); + + return uuid; + +} + +uuids::uuid get_proc_instance_uuid() { + static auto uuid = uitsl::generate_random_uuid(); + return uuid; +} + +uuids::uuid get_thread_instance_uuid() { + thread_local auto uuid = uitsl::generate_random_uuid(); + return uuid; +} + +} // namespace uitsl + +#endif // #ifndef UITSL_UTILITY_GET_EXEC_INSTANCE_UUID_HPP_INCLUDE diff --git a/include/uitsl/utility/get_proc_instance_uuid.hpp b/include/uitsl/utility/get_proc_instance_uuid.hpp new file mode 100644 index 0000000000..6827463d8d --- /dev/null +++ b/include/uitsl/utility/get_proc_instance_uuid.hpp @@ -0,0 +1,18 @@ +#pragma once +#ifndef UITSL_UTILITY_GET_PROC_INSTANCE_UUID_HPP_INCLUDE +#define UITSL_UTILITY_GET_PROC_INSTANCE_UUID_HPP_INCLUDE + +#include "../../../third-party/stduuid/include/uuid.h" + +#include "generate_random_uuid.hpp" + +namespace uitsl { + +uuids::uuid get_proc_instance_uuid() { + static auto uuid = uitsl::generate_random_uuid(); + return uuid; +} + +} // namespace uitsl + +#endif // #ifndef UITSL_UTILITY_GET_PROC_INSTANCE_UUID_HPP_INCLUDE diff --git a/include/uitsl/utility/get_thread_instance_uuid.hpp b/include/uitsl/utility/get_thread_instance_uuid.hpp new file mode 100644 index 0000000000..c1b32375f5 --- /dev/null +++ b/include/uitsl/utility/get_thread_instance_uuid.hpp @@ -0,0 +1,18 @@ +#pragma once +#ifndef UITSL_UTILITY_GET_THREAD_INSTANCE_UUID_HPP_INCLUDE +#define UITSL_UTILITY_GET_THREAD_INSTANCE_UUID_HPP_INCLUDE + +#include "../../../third-party/stduuid/include/uuid.h" + +#include "generate_random_uuid.hpp" + +namespace uitsl { + +uuids::uuid get_thread_instance_uuid() { + thread_local auto uuid = uitsl::generate_random_uuid(); + return uuid; +} + +} // namespace uitsl + +#endif // #ifndef UITSL_UTILITY_GET_THREAD_INSTANCE_UUID_HPP_INCLUDE diff --git a/include/uitsl/utility/uuid_utils.hpp b/include/uitsl/utility/uuid_utils.hpp index 8aec694501..04f396518a 100644 --- a/include/uitsl/utility/uuid_utils.hpp +++ b/include/uitsl/utility/uuid_utils.hpp @@ -2,117 +2,9 @@ #ifndef UITSL_UTILITY_UUID_UTILS_HPP_INCLUDE #define UITSL_UTILITY_UUID_UTILS_HPP_INCLUDE -#include -#include -#include -#include -#include -#include - -#include "../../../third-party/Empirical/include/emp/base/always_assert.hpp" -#include "../../../third-party/Empirical/include/emp/base/error.hpp" -#include "../../../third-party/Empirical/include/emp/tools/keyname_utils.hpp" -#include "../../../third-party/Empirical/include/emp/tools/keyname_utils.hpp" -#include "../../../third-party/Empirical/include/emp/tools/string_utils.hpp" -#include "../../../third-party/stduuid/include/uuid.h" - -#include "../mpi/comm_utils.hpp" -#include "../mpi/mpi_init_utils.hpp" -#include "../polyfill/filesystem.hpp" - -namespace uitsl { - -uuids::uuid generate_random_uuid() { - thread_local auto random_generator = [](){ - // workaround for error encountered when multiprocesses share same node - // > terminate called after throwing an instance of 'std::runtime_error' - // > what(): random_device: rdseed failed - // see https://github.com/xdspacelab/openvslam/issues/319#issuecomment-630225541 - // see https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device - std::random_device rd("rdrand"); - auto seed_data = std::array {}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - return std::mt19937(seq); - }(); - thread_local uuids::uuid_random_generator uuid_generator( random_generator ); - - return uuid_generator(); -} - -uuids::uuid get_exec_instance_uuid() { - - static auto uuid = [](){ - - uuids::uuid res; - - // try to set up res uuid using a series of fallback options... - // 1. if not multiprocess, can use random uuid generation - if ( !uitsl::is_multiprocess() ) res = uitsl::generate_random_uuid(); - // 2. if user provided UITSL_EXEC_INSTANCE_UUID, verify it and then use it - else if ( const char* seed = std::getenv("UITSL_EXEC_INSTANCE_UUID") ) { - auto parsed = uuids::uuid::from_string(seed); - emp_always_assert( - parsed.has_value(), - "UITSL_EXEC_INSTANCE_UUID must be a valid uuid", seed - ); - emp_always_assert( - !parsed->is_nil(), - "UITSL_EXEC_INSTANCE_UUID must be a non-nil uuid", seed, *parsed - ); - res = *parsed; - // 3. if PMIX_NAMESPACE is available, use that to make uuid - } else if ( const char* seed = std::getenv("PMIX_NAMESPACE") ) { - // is PMIX_NAMESPACE actually a good uuid seed? not sure - // note: PMIX_NAMESPACE only seems to be provided by OpenMPI - res = uuids::uuid_name_generator{ uuids::uuid{} }(seed); - // 4. no good options left, fail - } else emp_error( - "Need env var UITSL_EXEC_INSTANCE_UUID or PMIX_NAMESPACE " - "for get_multiprocess_exec_instance_uuid.\n" - "Hint: call " - "`export UITSL_EXEC_INSTANCE_UUID=\"$(cat /proc/sys/kernel/random/uuid)\"" - " _each time_ prior to launching with mpiexec." - ); - - // do a quick (non-exhaustive) check for obvious user misuse - // i.e., that uuid is actually unique - const auto reservation_path = std::filesystem::temp_directory_path() - / emp::keyname::pack({ - {"a", "uitsl_exec_instance_uuid"}, - {"rank",emp::to_string( uitsl::get_proc_id() )}, - {"uid", uuids::to_string( res )}, - }); - emp_always_assert( - !std::filesystem::exists( reservation_path ), - reservation_path, - uitsl::is_multiprocess(), - std::getenv("UITSL_EXEC_INSTANCE_UUID"), - std::getenv("PMIX_NAMESPACE") - ); - - // touch reservation_path - // adapted from https://stackoverflow.com/a/54451555 - std::ofstream output(reservation_path); - - return res; - - }(); - - return uuid; - -} - -uuids::uuid get_proc_instance_uuid() { - static auto uuid = uitsl::generate_random_uuid(); - return uuid; -} - -uuids::uuid get_thread_instance_uuid() { - thread_local auto uuid = uitsl::generate_random_uuid(); - return uuid; -} - -} // namespace uitsl +#include "generate_random_uuid.hpp" +#include "get_exec_instance_uuid.hpp" +#include "get_proc_instance_uuid.hpp" +#include "get_thread_instance_uuid.hpp" #endif // #ifndef UITSL_UTILITY_UUID_UTILS_HPP_INCLUDE