| // Copyright 2022 The SwiftShader Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // 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{}; |
| |
| // Processor flags. |
| 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; |
| } |
| |
| // Debug flags. |
| config.asmEmitDir = ini.getValue("Debug", "AsmEmitDir"); |
| if(config.asmEmitDir.size() > 0 && *config.asmEmitDir.rend() != '/') |
| { |
| config.asmEmitDir.push_back('/'); |
| } |
| |
| // Profiling flags. |
| config.enableSpirvProfiling = ini.getBoolean("Profiler", "EnableSpirvProfiling"); |
| config.spvProfilingReportPeriodMs = ini.getInteger<uint64_t>("Profiler", "SpirvProfilingReportPeriodMs"); |
| config.spvProfilingReportDir = ini.getValue("Profiler", "SpirvProfilingReportDir"); |
| |
| return config; |
| } |
| |
| const Configuration &getConfiguration() |
| { |
| 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; |
| } |
| |
| rr::DebugConfig getReactorDebugConfig(const Configuration &config) |
| { |
| rr::DebugConfig debugCfg; |
| debugCfg.asmEmitDir = config.asmEmitDir; |
| return debugCfg; |
| } |
| } // namespace sw |