Add affinity options to the configuration. Default behavior is unaffected by these changes. Bug: b/216019572 Change-Id: Ie464d1d63a02c25f8aff327437e1a578dd42f889 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/61888 Reviewed-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Daniele Vettorel <dvet@google.com> Commit-Queue: Daniele Vettorel <dvet@google.com>
diff --git a/src/System/BUILD.gn b/src/System/BUILD.gn index b48c927..6f61d9f 100644 --- a/src/System/BUILD.gn +++ b/src/System/BUILD.gn
@@ -55,6 +55,11 @@ } include_dirs = [ ".." ] + + deps = [ + "../../third_party/marl:Marl", + ] + public_deps = [ ":System_headers", ]
diff --git a/src/System/Configurator.cpp b/src/System/Configurator.cpp index 57214a4..dfe615b 100644 --- a/src/System/Configurator.cpp +++ b/src/System/Configurator.cpp
@@ -18,7 +18,6 @@ #include <algorithm> #include <fstream> #include <istream> -#include <sstream> namespace { inline std::string trimSpaces(const std::string &str) @@ -177,25 +176,6 @@ sections[sectionName].keyValuePairs[keyName] = value; } -int Configurator::getInteger(const std::string §ionName, const std::string &keyName, int defaultValue) const -{ - auto strValue = getValueIfExists(sectionName, keyName); - if(!strValue) - { - return defaultValue; - } - - std::stringstream ss{ *strValue }; - if(strValue->find("0x") != std::string::npos) - { - ss >> std::hex; - } - - int val = 0; - ss >> val; - return val; -} - bool Configurator::getBoolean(const std::string §ionName, const std::string &keyName, bool defaultValue) const { auto strValue = getValueIfExists(sectionName, keyName);
diff --git a/src/System/Configurator.hpp b/src/System/Configurator.hpp index 6c1aa77..1989781 100644 --- a/src/System/Configurator.hpp +++ b/src/System/Configurator.hpp
@@ -16,6 +16,7 @@ #define sw_Configurator_hpp #include <optional> +#include <sstream> #include <string> #include <unordered_map> @@ -32,7 +33,8 @@ void writeFile(const std::string &filePath, const std::string &title = "Configuration File"); - int getInteger(const std::string §ionName, const std::string &keyName, int defaultValue = 0) const; + template<typename T> + int getInteger(const std::string §ionName, const std::string &keyName, T defaultValue = 0) const; bool getBoolean(const std::string §ionName, const std::string &keyName, bool defaultValue = false) const; double getFloat(const std::string §ionName, const std::string &keyName, double defaultValue = 0.0) const; @@ -51,6 +53,24 @@ std::unordered_map<std::string, Section> sections; }; +template<typename T> +int Configurator::getInteger(const std::string §ionName, const std::string &keyName, T defaultValue) const +{ + static_assert(std::is_integral_v<T>, "getInteger must be used with integral types"); + + auto strValue = getValueIfExists(sectionName, keyName); + if(!strValue) + return defaultValue; + + std::stringstream ss{ *strValue }; + if(strValue->find("0x") != std::string::npos) + ss >> std::hex; + + T val = 0; + ss >> val; + return val; +} + } // namespace sw #endif // sw_Configurator_hpp
diff --git a/src/System/SwiftConfig.cpp b/src/System/SwiftConfig.cpp index 81ba15b..46e3ae8 100644 --- a/src/System/SwiftConfig.cpp +++ b/src/System/SwiftConfig.cpp
@@ -13,14 +13,99 @@ // limitations under the License. #include "SwiftConfig.hpp" +#include "CPUID.hpp" #include "Configurator.hpp" +#include "Debug.hpp" + +#include "marl/scheduler.h" + +#include <algorithm> + +namespace { + +std::string toLowerStr(const std::string &str) +{ + std::string lower = str; + std::transform(lower.begin(), lower.end(), lower.begin(), + [](unsigned char c) { return std::tolower(c); }); + return lower; +} + +marl::Thread::Core getCoreFromIndex(uint8_t coreIndex) +{ + marl::Thread::Core core = {}; +#if defined(_WIN32) + // We only support one processor group on Windows + // when an explicit affinity mask is used. + core.windows.group = 0; + core.windows.index = coreIndex; +#else + core.pthread.index = coreIndex; +#endif + return core; +} + +marl::Thread::Affinity getAffinityFromMask(uint64_t affinityMask) +{ + if(affinityMask == std::numeric_limits<uint64_t>::max()) + { + return marl::Thread::Affinity::all(); + } + + ASSERT(affinityMask != 0); + marl::containers::vector<marl::Thread::Core, 32> cores; + uint8_t coreIndex = 0; + while(affinityMask) + { + if(affinityMask & 1) + { + cores.push_back(getCoreFromIndex(coreIndex)); + } + ++coreIndex; + affinityMask >>= 1; + } + + return marl::Thread::Affinity(cores, marl::Allocator::Default); +} + +std::shared_ptr<marl::Thread::Affinity::Policy> getAffinityPolicy(marl::Thread::Affinity &&affinity, sw::Configuration::AffinityPolicy affinityPolicy) +{ + switch(affinityPolicy) + { + case sw::Configuration::AffinityPolicy::AnyOf: + return marl::Thread::Affinity::Policy::anyOf(std::move(affinity)); + case sw::Configuration::AffinityPolicy::OneOf: + return marl::Thread::Affinity::Policy::oneOf(std::move(affinity)); + default: + UNREACHABLE("unknown affinity policy"); + } + return nullptr; +} +} // namespace namespace sw { + Configuration readConfigurationFromFile() { Configurator ini("SwiftShader.ini"); Configuration config{}; - config.threadCount = ini.getInteger("Processor", "ThreadCount", 0); + config.threadCount = ini.getInteger<uint32_t>("Processor", "ThreadCount", 0); + config.affinityMask = ini.getInteger<uint64_t>("Processor", "AffinityMask", 0xffffffffffffffff); + if(config.affinityMask == 0) + { + warn("Affinity mask is empty, using all-cores affinity\n"); + config.affinityMask = 0xffffffffffffffff; + } + std::string affinityPolicy = toLowerStr(ini.getValue("Processor", "AffinityPolicy", "any")); + if(affinityPolicy == "one") + { + config.affinityPolicy = Configuration::AffinityPolicy::OneOf; + } + else + { + // Default. + config.affinityPolicy = Configuration::AffinityPolicy::AnyOf; + } return config; } @@ -30,4 +115,21 @@ static Configuration config = readConfigurationFromFile(); return config; } + +marl::Scheduler::Config getSchedulerConfiguration(const Configuration &config) +{ + uint32_t threadCount = (config.threadCount == 0) ? std::min<size_t>(marl::Thread::numLogicalCPUs(), 16) + : config.threadCount; + auto affinity = getAffinityFromMask(config.affinityMask); + auto affinityPolicy = getAffinityPolicy(std::move(affinity), config.affinityPolicy); + + marl::Scheduler::Config cfg; + cfg.setWorkerThreadCount(threadCount); + cfg.setWorkerThreadAffinityPolicy(affinityPolicy); + cfg.setWorkerThreadInitializer([](int) { + sw::CPUID::setFlushToZero(true); + sw::CPUID::setDenormalsAreZero(true); + }); + return cfg; +} } // namespace sw \ No newline at end of file
diff --git a/src/System/SwiftConfig.hpp b/src/System/SwiftConfig.hpp index b5b61a7..32ba2b4 100644 --- a/src/System/SwiftConfig.hpp +++ b/src/System/SwiftConfig.hpp
@@ -15,14 +15,35 @@ #ifndef sw_SwiftConfig_hpp #define sw_SwiftConfig_hpp +#include <stdint.h> + +#include "marl/scheduler.h" + namespace sw { struct Configuration { - int threadCount; + enum class AffinityPolicy : int + { + // A thread has affinity with any core in the affinity mask. + AnyOf = 0, + // A thread has affinity with a single core in the affinity mask. + OneOf = 1, + }; + + // Number of threads used by the scheduler. A thread count of 0 is + // interpreted as min(cpu_cores_available, 16). + uint32_t threadCount = 0; + + // Core affinity and affinity policy used by the scheduler. + uint64_t affinityMask = 0xffffffffffffffff; + AffinityPolicy affinityPolicy = AffinityPolicy::AnyOf; }; // Get the configuration as parsed from a configuration file. const Configuration &getConfiguration(); + +// Get the scheduler configuration given a configuration. +marl::Scheduler::Config getSchedulerConfiguration(const Configuration &config); } // namespace sw #endif \ No newline at end of file
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp index 17b73ac..a3c3c5a 100644 --- a/src/Vulkan/libVulkan.cpp +++ b/src/Vulkan/libVulkan.cpp
@@ -137,20 +137,12 @@ static Scheduler scheduler; // TODO(b/208256248): Avoid exit-time destructor. - const sw::Configuration &config = sw::getConfiguration(); - int threadCount = config.threadCount; - marl::lock lock(scheduler.mutex); auto sptr = scheduler.weakptr.lock(); if(!sptr) { - marl::Scheduler::Config cfg; - cfg.setWorkerThreadCount(threadCount == 0 ? std::min<size_t>(marl::Thread::numLogicalCPUs(), 16) - : threadCount); - cfg.setWorkerThreadInitializer([](int) { - sw::CPUID::setFlushToZero(true); - sw::CPUID::setDenormalsAreZero(true); - }); + const sw::Configuration &config = sw::getConfiguration(); + marl::Scheduler::Config cfg = sw::getSchedulerConfiguration(config); sptr = std::make_shared<marl::Scheduler>(cfg); scheduler.weakptr = sptr; }