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;
}