blob: 9e00a5d07f0cceee738dabd3279ba3fa8f525647 [file] [log] [blame]
// 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", 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<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;
}
} // namespace sw