1 // Copyright 2022 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "SwiftConfig.hpp"
16 #include "CPUID.hpp"
17 #include "Configurator.hpp"
18 #include "Debug.hpp"
19
20 #include "marl/scheduler.h"
21
22 #include <algorithm>
23
24 namespace {
25
toLowerStr(const std::string & str)26 std::string toLowerStr(const std::string &str)
27 {
28 std::string lower = str;
29 std::transform(lower.begin(), lower.end(), lower.begin(),
30 [](unsigned char c) { return std::tolower(c); });
31 return lower;
32 }
33
getCoreFromIndex(uint8_t coreIndex)34 marl::Thread::Core getCoreFromIndex(uint8_t coreIndex)
35 {
36 marl::Thread::Core core = {};
37 #if defined(_WIN32)
38 // We only support one processor group on Windows
39 // when an explicit affinity mask is used.
40 core.windows.group = 0;
41 core.windows.index = coreIndex;
42 #else
43 core.pthread.index = coreIndex;
44 #endif
45 return core;
46 }
47
getAffinityFromMask(uint64_t affinityMask)48 marl::Thread::Affinity getAffinityFromMask(uint64_t affinityMask)
49 {
50 if(affinityMask == std::numeric_limits<uint64_t>::max())
51 {
52 return marl::Thread::Affinity::all();
53 }
54
55 ASSERT(affinityMask != 0);
56 marl::containers::vector<marl::Thread::Core, 32> cores;
57 uint8_t coreIndex = 0;
58 while(affinityMask)
59 {
60 if(affinityMask & 1)
61 {
62 cores.push_back(getCoreFromIndex(coreIndex));
63 }
64 ++coreIndex;
65 affinityMask >>= 1;
66 }
67
68 return marl::Thread::Affinity(cores, marl::Allocator::Default);
69 }
70
getAffinityPolicy(marl::Thread::Affinity && affinity,sw::Configuration::AffinityPolicy affinityPolicy)71 std::shared_ptr<marl::Thread::Affinity::Policy> getAffinityPolicy(marl::Thread::Affinity &&affinity, sw::Configuration::AffinityPolicy affinityPolicy)
72 {
73 switch(affinityPolicy)
74 {
75 case sw::Configuration::AffinityPolicy::AnyOf:
76 return marl::Thread::Affinity::Policy::anyOf(std::move(affinity));
77 case sw::Configuration::AffinityPolicy::OneOf:
78 return marl::Thread::Affinity::Policy::oneOf(std::move(affinity));
79 default:
80 UNREACHABLE("unknown affinity policy");
81 }
82 return nullptr;
83 }
84 } // namespace
85
86 namespace sw {
87
readConfigurationFromFile()88 Configuration readConfigurationFromFile()
89 {
90 Configurator ini("SwiftShader.ini");
91 Configuration config{};
92
93 // Processor flags.
94 config.threadCount = ini.getInteger<uint32_t>("Processor", "ThreadCount", 0);
95 config.affinityMask = ini.getInteger<uint64_t>("Processor", "AffinityMask", 0xffffffffffffffff);
96 if(config.affinityMask == 0)
97 {
98 warn("Affinity mask is empty, using all-cores affinity\n");
99 config.affinityMask = 0xffffffffffffffff;
100 }
101 std::string affinityPolicy = toLowerStr(ini.getValue("Processor", "AffinityPolicy", "any"));
102 if(affinityPolicy == "one")
103 {
104 config.affinityPolicy = Configuration::AffinityPolicy::OneOf;
105 }
106 else
107 {
108 // Default.
109 config.affinityPolicy = Configuration::AffinityPolicy::AnyOf;
110 }
111
112 // Debug flags.
113 config.asmEmitDir = ini.getValue("Debug", "AsmEmitDir");
114 if(config.asmEmitDir.size() > 0 && *config.asmEmitDir.rend() != '/')
115 {
116 config.asmEmitDir.push_back('/');
117 }
118
119 // Profiling flags.
120 config.enableSpirvProfiling = ini.getBoolean("Profiler", "EnableSpirvProfiling");
121 config.spvProfilingReportPeriodMs = ini.getInteger<uint64_t>("Profiler", "SpirvProfilingReportPeriodMs");
122 config.spvProfilingReportDir = ini.getValue("Profiler", "SpirvProfilingReportDir");
123
124 return config;
125 }
126
getConfiguration()127 const Configuration &getConfiguration()
128 {
129 static Configuration config = readConfigurationFromFile();
130 return config;
131 }
132
getSchedulerConfiguration(const Configuration & config)133 marl::Scheduler::Config getSchedulerConfiguration(const Configuration &config)
134 {
135 uint32_t threadCount = (config.threadCount == 0) ? std::min<size_t>(marl::Thread::numLogicalCPUs(), 16)
136 : config.threadCount;
137 auto affinity = getAffinityFromMask(config.affinityMask);
138 auto affinityPolicy = getAffinityPolicy(std::move(affinity), config.affinityPolicy);
139
140 marl::Scheduler::Config cfg;
141 cfg.setWorkerThreadCount(threadCount);
142 cfg.setWorkerThreadAffinityPolicy(affinityPolicy);
143 cfg.setWorkerThreadInitializer([](int) {
144 sw::CPUID::setFlushToZero(true);
145 sw::CPUID::setDenormalsAreZero(true);
146 });
147 return cfg;
148 }
149
getReactorDebugConfig(const Configuration & config)150 rr::DebugConfig getReactorDebugConfig(const Configuration &config)
151 {
152 rr::DebugConfig debugCfg;
153 debugCfg.asmEmitDir = config.asmEmitDir;
154 return debugCfg;
155 }
156 } // namespace sw