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
17 #include "CPUID.hpp"
18 #include "Configurator.hpp"
19 #include "Debug.hpp"
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", 0xFFFFFFFFFFFFFFFFu);
96 if(config.affinityMask == 0)
97 {
98 warn("Affinity mask is empty, using all-cores affinity\n");
99 config.affinityMask = 0xFFFFFFFFFFFFFFFFu;
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 // Profiling flags.
113 config.enableSpirvProfiling = ini.getBoolean("Profiler", "EnableSpirvProfiling");
114 config.spvProfilingReportPeriodMs = ini.getInteger<uint64_t>("Profiler", "SpirvProfilingReportPeriodMs");
115 config.spvProfilingReportDir = ini.getValue("Profiler", "SpirvProfilingReportDir");
116
117 return config;
118 }
119
getConfiguration()120 const Configuration &getConfiguration()
121 {
122 static Configuration config = readConfigurationFromFile();
123 return config;
124 }
125
getSchedulerConfiguration(const Configuration & config)126 marl::Scheduler::Config getSchedulerConfiguration(const Configuration &config)
127 {
128 uint32_t threadCount = (config.threadCount == 0) ? std::min<size_t>(marl::Thread::numLogicalCPUs(), 16)
129 : config.threadCount;
130 auto affinity = getAffinityFromMask(config.affinityMask);
131 auto affinityPolicy = getAffinityPolicy(std::move(affinity), config.affinityPolicy);
132
133 marl::Scheduler::Config cfg;
134 cfg.setWorkerThreadCount(threadCount);
135 cfg.setWorkerThreadAffinityPolicy(affinityPolicy);
136 cfg.setWorkerThreadInitializer([](int) {
137 sw::CPUID::setFlushToZero(true);
138 sw::CPUID::setDenormalsAreZero(true);
139 });
140 return cfg;
141 }
142
143 } // namespace sw