// 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 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::max()) { return marl::Thread::Affinity::all(); } ASSERT(affinityMask != 0); marl::containers::vector 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 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("Processor", "ThreadCount", 0); config.affinityMask = ini.getInteger("Processor", "AffinityMask", 0xFFFFFFFFFFFFFFFFu); if(config.affinityMask == 0) { warn("Affinity mask is empty, using all-cores affinity\n"); config.affinityMask = 0xFFFFFFFFFFFFFFFFu; } std::string affinityPolicy = toLowerStr(ini.getValue("Processor", "AffinityPolicy", "any")); if(affinityPolicy == "one") { config.affinityPolicy = Configuration::AffinityPolicy::OneOf; } else { // Default. config.affinityPolicy = Configuration::AffinityPolicy::AnyOf; } // Profiling flags. config.enableSpirvProfiling = ini.getBoolean("Profiler", "EnableSpirvProfiling"); config.spvProfilingReportPeriodMs = ini.getInteger("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(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