CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
273 lines
10 KiB
C++
273 lines
10 KiB
C++
// Copyright Advanced Micro Devices, Inc., or its affiliates.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <catch2/matchers/catch_matchers_string.hpp>
|
|
#include <omp.h>
|
|
#include <thread>
|
|
|
|
#include "SimpleTest.hpp"
|
|
#include "common/SourceMatcher.hpp"
|
|
#include <rocRoller/Utilities/Settings_fwd.hpp>
|
|
|
|
using namespace rocRoller;
|
|
using namespace Catch::Matchers;
|
|
|
|
namespace SettingsTest
|
|
{
|
|
class EnvSettingsTest : public SimpleTest
|
|
{
|
|
public:
|
|
EnvSettingsTest()
|
|
: SimpleTest()
|
|
{
|
|
for(auto const& setting : SettingsOptionBase::instances())
|
|
{
|
|
std::optional<std::string> val;
|
|
if(auto ptr = getenv(setting->name.c_str()))
|
|
{
|
|
val = ptr;
|
|
}
|
|
m_envVars[setting->name] = val;
|
|
}
|
|
|
|
// This is not a setting option, but affects the env
|
|
if(auto ptr = getenv(Settings::BitfieldName.c_str()))
|
|
{
|
|
m_envVars[Settings::BitfieldName] = ptr;
|
|
}
|
|
else
|
|
{
|
|
m_envVars[Settings::BitfieldName] = std::nullopt;
|
|
}
|
|
|
|
setenv(Settings::BitfieldName.c_str(), "0xFFFFFFFF", 1);
|
|
setenv(Settings::LogConsole.name.c_str(), "0", 1);
|
|
setenv(Settings::AssemblyFile.name.c_str(), "assemblyFileTest.s", 1);
|
|
setenv(Settings::RandomSeed.name.c_str(), "31415", 1);
|
|
setenv(Settings::Scheduler.name.c_str(), "invalidScheduler", 1);
|
|
}
|
|
|
|
~EnvSettingsTest() override
|
|
{
|
|
for(auto entry : m_envVars)
|
|
{
|
|
if(entry.second.has_value())
|
|
{
|
|
setenv(entry.first.c_str(), entry.second.value().c_str(), 1);
|
|
}
|
|
else
|
|
{
|
|
unsetenv(entry.first.c_str());
|
|
}
|
|
}
|
|
|
|
Settings::reset();
|
|
}
|
|
|
|
private:
|
|
std::map<std::string, std::optional<std::string>> m_envVars;
|
|
};
|
|
|
|
TEST_CASE("Basic settings behavior", "[settings]")
|
|
{
|
|
SimpleTest t;
|
|
|
|
SECTION("Default values")
|
|
{
|
|
if(std::getenv(Settings::SaveAssembly.name.c_str()))
|
|
SKIP("Skipping due to environment variable being set.");
|
|
|
|
auto settings = Settings::getInstance();
|
|
|
|
CHECK(settings->get(Settings::LogConsole) == Settings::LogConsole.defaultValue);
|
|
CHECK(settings->get(Settings::SaveAssembly) == Settings::SaveAssembly.defaultValue);
|
|
CHECK_THAT(settings->get(Settings::AssemblyFile),
|
|
Equals(Settings::AssemblyFile.defaultValue));
|
|
CHECK(settings->get(Settings::BreakOnThrow) == Settings::BreakOnThrow.defaultValue);
|
|
CHECK_THAT(settings->get(Settings::LogFile), Equals(Settings::LogFile.defaultValue));
|
|
CHECK(settings->get(Settings::LogLvl) == Settings::LogLvl.defaultValue);
|
|
CHECK(settings->get(Settings::RandomSeed) == Settings::RandomSeed.defaultValue);
|
|
CHECK(settings->get(Settings::Scheduler) == Settings::Scheduler.defaultValue);
|
|
}
|
|
|
|
SECTION("Log levels")
|
|
{
|
|
std::ostringstream out;
|
|
out << LogLevel::None << std::endl;
|
|
out << LogLevel::Error << std::endl;
|
|
out << LogLevel::Warning << std::endl;
|
|
out << LogLevel::Terse << std::endl;
|
|
out << LogLevel::Verbose << std::endl;
|
|
out << LogLevel::Debug << std::endl;
|
|
out << LogLevel::Count << std::endl;
|
|
|
|
std::string stringify = "";
|
|
stringify += toString(LogLevel::None) + '\n';
|
|
stringify += toString(LogLevel::Error) + '\n';
|
|
stringify += toString(LogLevel::Warning) + '\n';
|
|
stringify += toString(LogLevel::Terse) + '\n';
|
|
stringify += toString(LogLevel::Verbose) + '\n';
|
|
stringify += toString(LogLevel::Debug) + '\n';
|
|
stringify += toString(LogLevel::Count) + '\n';
|
|
|
|
std::string expected = R"(
|
|
None
|
|
Error
|
|
Warning
|
|
Terse
|
|
Verbose
|
|
Debug
|
|
Count
|
|
)";
|
|
|
|
CHECK_THAT(NormalizedSource(expected), Equals(NormalizedSource(out.str())));
|
|
CHECK_THAT(NormalizedSource(expected), Equals(NormalizedSource(stringify)));
|
|
|
|
CHECK(fromString<LogLevel>("None") == LogLevel::None);
|
|
CHECK(fromString<LogLevel>("Error") == LogLevel::Error);
|
|
CHECK(fromString<LogLevel>("Warning") == LogLevel::Warning);
|
|
CHECK(fromString<LogLevel>("Terse") == LogLevel::Terse);
|
|
CHECK(fromString<LogLevel>("Verbose") == LogLevel::Verbose);
|
|
CHECK(fromString<LogLevel>("Debug") == LogLevel::Debug);
|
|
CHECK_THROWS(fromString<LogLevel>("Count"));
|
|
}
|
|
|
|
SECTION("Invalid settings are not allowed")
|
|
{
|
|
auto settings = Settings::getInstance();
|
|
|
|
settings->set(Settings::Scheduler, Scheduling::SchedulerProcedure::Cooperative);
|
|
CHECK_THROWS_AS(settings->set(Settings::Scheduler, "invalidValue"), FatalError);
|
|
CHECK(settings->get(Settings::Scheduler)
|
|
== Scheduling::SchedulerProcedure::Cooperative);
|
|
|
|
CHECK_THROWS_AS(settings->set(Settings::LogConsole, "invalidValue"), FatalError);
|
|
|
|
Settings::reset();
|
|
}
|
|
|
|
SECTION("Settings should be helpful")
|
|
{
|
|
SimpleTest t;
|
|
auto settings = Settings::getInstance();
|
|
std::string help = settings->help();
|
|
CHECK_THAT(help, ContainsSubstring("default"));
|
|
CHECK_THAT(help, ContainsSubstring("bit"));
|
|
}
|
|
|
|
SECTION("Settings should be thread-safe")
|
|
{
|
|
auto settings = Settings::getInstance();
|
|
|
|
unsigned int numCores = std::thread::hardware_concurrency();
|
|
CHECK(numCores > 2);
|
|
const unsigned int numTestThreads = (numCores > 8) ? 8 : numCores;
|
|
|
|
auto minIters = 1000;
|
|
auto durationSeconds = 2;
|
|
auto end
|
|
= std::chrono::high_resolution_clock::now() + std::chrono::seconds(durationSeconds);
|
|
|
|
size_t numUnexpectedLogLevels = 0;
|
|
size_t numIters = 0;
|
|
|
|
#pragma omp parallel num_threads(numTestThreads) reduction(+ : numUnexpectedLogLevels) \
|
|
reduction(+ : numIters)
|
|
{
|
|
size_t iters = 0;
|
|
int tid = omp_get_thread_num();
|
|
while(std::chrono::high_resolution_clock::now() < end || iters <= minIters)
|
|
{
|
|
iters++;
|
|
if(tid % 2 == 0)
|
|
{
|
|
auto logLevel = settings->get(Settings::LogLvl);
|
|
auto isNoneOrError
|
|
= (logLevel == LogLevel::None) || (logLevel == LogLevel::Error);
|
|
if(!isNoneOrError)
|
|
++numUnexpectedLogLevels;
|
|
}
|
|
else
|
|
{
|
|
auto setError = (rand() % 2) == 0;
|
|
settings->set(Settings::LogLvl,
|
|
setError ? LogLevel::Error : LogLevel::None);
|
|
}
|
|
usleep(rand() % 100);
|
|
}
|
|
numIters += iters;
|
|
}
|
|
CHECK(numUnexpectedLogLevels == 0);
|
|
CHECK(numIters >= numTestThreads * minIters);
|
|
}
|
|
|
|
Settings::reset();
|
|
}
|
|
|
|
TEST_CASE("Settings with associated envvars", "[settings]")
|
|
{
|
|
EnvSettingsTest t;
|
|
|
|
SECTION("No infinite recursion")
|
|
{
|
|
// Settings ctor should not get from env,
|
|
// otherwise it may throw without a prior settings instance
|
|
// and infinitely recurse
|
|
Settings::reset();
|
|
// unsetenv bitfield revert BreakOnThrow to false (default value)
|
|
unsetenv(Settings::BitfieldName.c_str());
|
|
auto settings = Settings::getInstance();
|
|
CHECK_THROWS_AS(settings->get(Settings::Scheduler), FatalError);
|
|
|
|
Settings::reset();
|
|
}
|
|
|
|
SECTION("Environment variables take precedence")
|
|
{
|
|
Settings::reset();
|
|
auto settings = Settings::getInstance();
|
|
|
|
// Env Var takes precedence over bitfield
|
|
CHECK_FALSE(settings->get(Settings::LogConsole));
|
|
|
|
// bitfield takes precedence over default value
|
|
CHECK(settings->get(Settings::SaveAssembly));
|
|
|
|
Settings::reset();
|
|
}
|
|
|
|
SECTION("Set and get from envvars-backed settings")
|
|
{
|
|
Settings::reset();
|
|
auto settings = Settings::getInstance();
|
|
CHECK_FALSE(settings->get(Settings::LogConsole));
|
|
CHECK(Settings::Get(Settings::SaveAssembly));
|
|
CHECK_THAT(settings->get(Settings::AssemblyFile), Equals("assemblyFileTest.s"));
|
|
CHECK(Settings::Get(Settings::RandomSeed) == 31415);
|
|
|
|
// Set settings in memory
|
|
settings->set(Settings::LogConsole, true);
|
|
settings->set(Settings::AssemblyFile, "differentFile.s");
|
|
CHECK(settings->get(Settings::LogConsole));
|
|
CHECK_THAT(settings->get(Settings::AssemblyFile), Equals("differentFile.s"));
|
|
|
|
// Values set in memory should not persist
|
|
Settings::reset();
|
|
settings = Settings::getInstance();
|
|
|
|
CHECK_FALSE(settings->get(Settings::LogConsole));
|
|
CHECK(Settings::Get(Settings::SaveAssembly));
|
|
CHECK_THAT(settings->get(Settings::AssemblyFile), Equals("assemblyFileTest.s"));
|
|
CHECK(Settings::Get(Settings::RandomSeed) == 31415);
|
|
|
|
// set BreakOnThrow to false (previously true via bitfield)
|
|
settings->set(Settings::BreakOnThrow, false);
|
|
// Fatal error reading unparseable env var
|
|
CHECK_THROWS_AS(settings->get(Settings::Scheduler), FatalError);
|
|
|
|
Settings::reset();
|
|
}
|
|
}
|
|
}
|