Proteus
Programmable JIT compilation and optimization for C/C++ using LLVM
Loading...
Searching...
No Matches
Config.hpp
Go to the documentation of this file.
1#ifndef PROTEUS_CONFIG_HPP
2#define PROTEUS_CONFIG_HPP
3
4#include "proteus/Error.h"
5#include "proteus/Logger.hpp"
6
7#include "llvm/ADT/StringMap.h"
8#include <llvm/Support/JSON.h>
9#include <llvm/Support/MemoryBuffer.h>
10
11#include <string>
12namespace proteus {
13
14enum class CodegenOption {
15 RTC,
16 Serial,
18};
19
25
26inline std::string toString(CodegenOption Option) {
27 switch (Option) {
29 return "RTC";
31 return "Serial";
33 return "Parallel";
34 default:
35 return "Unknown";
36 }
37}
38
39inline std::string toString(KernelCloneOption Option) {
40 switch (Option) {
42 return "link-clone-prune";
44 return "link-clone-light";
46 return "cross-clone";
47 default:
48 return "Unknown";
49 }
50}
51
52inline std::optional<std::string> getEnvOrDefaultString(const char *VarName) {
53
54 const char *EnvValue = std::getenv(VarName);
55 if (!EnvValue)
56 return std::nullopt;
57
58 return std::string(EnvValue);
59}
60
61inline char getEnvOrDefaultChar(const char *VarName, char Default) {
62
63 const char *EnvValue = std::getenv(VarName);
64 return EnvValue ? EnvValue[0] : Default;
65}
66
67inline bool getEnvOrDefaultBool(const char *VarName, bool Default) {
68
69 const char *EnvValue = std::getenv(VarName);
70 return EnvValue ? static_cast<bool>(std::stoi(EnvValue)) : Default;
71}
72
73inline int getEnvOrDefaultInt(const char *VarName, int Default) {
74
75 const char *EnvValue = std::getenv(VarName);
76 return EnvValue ? std::stoi(EnvValue) : Default;
77}
78
79inline CodegenOption strToCG(std::string CGstr) {
80 std::transform(CGstr.begin(), CGstr.end(), CGstr.begin(), ::tolower);
81 if (CGstr == "rtc")
82 return CodegenOption::RTC;
83 if (CGstr == "serial")
85 if (CGstr == "parallel")
87
88 reportFatalError("Unknown codegen option: " + CGstr);
89}
90
93
94 const char *EnvValue = std::getenv(VarName);
95 if (!EnvValue)
96 return Default;
97
98 return strToCG(EnvValue);
99}
100
101template <typename T>
103 if (JSONValue)
104 return JSONValue.value();
105 return Default;
106}
107
110
111 const char *EnvValue = std::getenv(VarName);
112 if (!EnvValue)
113 return Default;
114
115 std::string EnvValueStr{EnvValue};
116 std::transform(EnvValueStr.begin(), EnvValueStr.end(), EnvValueStr.begin(),
117 ::tolower);
118 if (EnvValueStr == "link-clone-prune")
120 if (EnvValueStr == "link-clone-light")
122 if (EnvValueStr == "cross-clone")
124
125 Logger::outs("proteus") << "Unknown kernel clone option " << EnvValueStr
126 << ", using default: " << toString(Default) << "\n";
127 return Default;
128}
129
131 static constexpr bool DefaultSpecializeDimsRange =
132#if PROTEUS_ENABLE_CUDA
133 // Disable SpecializeDimsRange on CUDA builds: empirically causes worse
134 // optimization, so default to false.
135 false;
136#else
137 true;
138#endif
139
140 static CodegenOption getCodeGen(CodegenOption ProteusCodegen) {
141 constexpr bool SupportOnlyRTC =
142#if defined(PROTEUS_ENABLE_CUDA)
143 true;
144#else
145 false;
146#endif
147 if (SupportOnlyRTC && ProteusCodegen != CodegenOption::RTC) {
148 Logger::outs("proteus") << "Warning: Proteus supports only RTC in the "
149 "current build system configuration, "
150 "defaulting Codegen to RTC\n";
151 ProteusCodegen = CodegenOption::RTC;
152 }
153 return ProteusCodegen;
154 }
155
156 std::optional<const std::string> ProteusOptPipeline;
157 CodegenOption ProteusCodegen;
158 bool ProteusSpecializeArgs;
159 bool ProteusSpecializeLaunchBounds;
160 bool ProteusSpecializeDims;
161 bool ProteusSpecializeDimsRange;
162 char ProteusOptLevel;
163 int ProteusCodeGenOptLevel;
164 int TunedMaxThreads;
165 int MinBlocksPerSM;
166
167 CodeGenerationConfig(std::optional<const std::string> ProteusOptPipeline,
168 CodegenOption ProteusCodegen, bool ProteusSpecializeArgs,
169 bool ProteusSpecializeLaunchBounds,
170 bool ProteusSpecializeDims,
171 bool ProteusSpecializeDimsRange, char ProteusOptLevel,
172 int ProteusCodeGenOptLevel, int TunedMaxThreads = -1,
173 int MinBlocksPerSM = 0)
174 : ProteusOptPipeline(ProteusOptPipeline), ProteusCodegen(ProteusCodegen),
175 ProteusSpecializeArgs(ProteusSpecializeArgs),
176 ProteusSpecializeLaunchBounds(ProteusSpecializeLaunchBounds),
177 ProteusSpecializeDims(ProteusSpecializeDims),
178 ProteusSpecializeDimsRange(ProteusSpecializeDimsRange),
179 ProteusOptLevel(ProteusOptLevel),
180 ProteusCodeGenOptLevel(ProteusCodeGenOptLevel),
181 TunedMaxThreads(TunedMaxThreads), MinBlocksPerSM(MinBlocksPerSM) {}
182
183public:
186 getEnvOrDefaultString("PROTEUS_OPT_PIPELINE"),
187 getCodeGen(getEnvOrDefaultCG("PROTEUS_CODEGEN", CodegenOption::RTC)),
188 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_ARGS", true),
189 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_LAUNCH_BOUNDS", true),
190 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS", true),
191 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS_RANGE",
192 DefaultSpecializeDimsRange),
193 getEnvOrDefaultChar("PROTEUS_OPT_LEVEL", '3'),
194 getEnvOrDefaultInt("PROTEUS_CODEGEN_OPT_LEVEL", 3));
195 }
196
198 createFromJSONEntry(const llvm::json::Object &Config) {
199 auto Pipeline = Config.getString("Pipeline");
200 std::optional<std::string> ProteusPipeline;
201 if (Pipeline)
202 ProteusPipeline = Pipeline.value().str();
203
206 getCodeGen(
207 strToCG(getDefaultValueFromOptional(Config.getString("CodeGen"),
208 llvm::StringRef("rtc"))
209 .str())),
210 getDefaultValueFromOptional(Config.getBoolean("SpecializeArgs"), true),
211 getDefaultValueFromOptional(Config.getBoolean("LaunchBounds"), true),
212 getDefaultValueFromOptional(Config.getBoolean("SpecializeDims"), true),
213 getDefaultValueFromOptional(Config.getBoolean("SpecializeDimsRange"),
214 DefaultSpecializeDimsRange),
215 getDefaultValueFromOptional(Config.getString("OptLevel"),
216 llvm::StringRef("3"))[0],
217 getDefaultValueFromOptional(Config.getInteger("CodeGenOptLevel"),
218 static_cast<int64_t>(3)),
219 getDefaultValueFromOptional(Config.getInteger("TunedMaxThreads"),
220 static_cast<int64_t>(-1L)),
221 getDefaultValueFromOptional(Config.getInteger("MinBlocksPerSM"),
222 static_cast<int64_t>(0L)));
223 }
224
225 CodegenOption codeGenOption() const { return ProteusCodegen; }
226 bool specializeArgs() const { return ProteusSpecializeArgs; }
227 bool specializeDims() const { return ProteusSpecializeDims; }
228 bool specializeDimsRange() const { return ProteusSpecializeDimsRange; }
229 bool specializeLaunchBounds() const { return ProteusSpecializeLaunchBounds; }
230 char optLevel() const { return ProteusOptLevel; }
231 int codeGenOptLevel() const { return ProteusCodeGenOptLevel; }
232 std::optional<const std::string> optPipeline() const {
233 return ProteusOptPipeline;
234 }
235
236 int minBlocksPerSM(int MaxThreads) const {
237 // NOTE: We only return the tuned value when the current LBMaxThreads is
238 // equal to the tuned one. otherwise we return 0. Not doing so, may result
239 // in violating constraints in cases in which LBMaxThreads >
240 // TunedMaxThreads
241 if (TunedMaxThreads != MaxThreads)
242 return 0;
243 return MinBlocksPerSM;
244 }
245
246 template <typename T> void dump(T &OS) const {
247 if (ProteusOptPipeline)
248 OS << "Pipeline:" << ProteusOptPipeline.value() << " ";
249
250 OS << "CG:" << toString(ProteusCodegen) << " ";
251 OS << "SA:" << ProteusSpecializeArgs << " ";
252 OS << "LB:" << ProteusSpecializeLaunchBounds << " ";
253 OS << "SD:" << ProteusSpecializeDims << " ";
254 OS << "SDR:" << ProteusSpecializeDimsRange << " ";
255 OS << "OL:" << ProteusOptLevel << " ";
256 OS << "CGL:" << ProteusCodeGenOptLevel << " ";
257 OS << "TMT:" << TunedMaxThreads << " ";
258 OS << "BPSM:" << MinBlocksPerSM << " ";
259 }
260};
261
263parseJSONConfig(std::optional<std::string> JSONFn) {
265 if (!JSONFn)
266 return TunedConfigs;
267
268 auto JSONRoot = [&JSONFn]() -> std::optional<llvm::json::Object> {
270 llvm::MemoryBuffer::getFile(JSONFn.value(), /* isText */ true,
271 /* RequiresNullTerminator */ true);
272 if (!JSONBuf)
273 reportFatalError("Error when opening json file: " +
274 JSONBuf.getError().message() + "\n");
275
276 llvm::json::Value JsonInfo =
277 llvm::cantFail(llvm::json::parse(JSONBuf.get()->getBuffer()),
278 "Cannot convert buffer to json value");
279
280 if (auto *Obj = JsonInfo.getAsObject())
281 return *Obj;
282 return std::nullopt;
283 }();
284
285 if (!JSONRoot)
286 reportFatalError("Top-level JSON is not an object.\n");
287
288 for (auto &KV : JSONRoot.value()) {
289 auto KernelName = KV.first;
290 if (const auto *Options = KV.second.getAsObject()) {
291 TunedConfigs.try_emplace(
293 }
294 }
295 return TunedConfigs;
296}
297
298class Config {
299public:
300 static Config &get() {
301 static Config Conf;
302 return Conf;
303 }
317 std::optional<const std::string> ProteusCacheDir;
321
323
324 if (TunedConfigs.empty())
325 return GlobalCodeGenConfig;
326
327 if (auto It = TunedConfigs.find(KName); It != TunedConfigs.end())
328 return It->second;
329
330 return GlobalCodeGenConfig;
331 }
332
333 void dump(llvm::raw_ostream &OS) const {
334 auto PrintOut = [](llvm::StringRef ID,
338 OS << "ID:" << ID << " ";
339 KConfig.dump(OS);
340 return S;
341 };
342
343 OS << "PROTEUS_USE_STORED_CACHE " << ProteusUseStoredCache << "\n";
344 OS << "PROTEUS_CACHE_DIR " << Config::get().ProteusCacheDir << "\n";
345
346 OS << PrintOut("Default", GlobalCodeGenConfig) << "\n";
347 for (auto &KV : TunedConfigs) {
348 OS << PrintOut(KV.getKey(), KV.second) << "\n";
349 }
350 }
351
352private:
353 Config()
354 : GlobalCodeGenConfig(CodeGenerationConfig::createFromEnv()),
356 parseJSONConfig(getEnvOrDefaultString("PROTEUS_TUNED_KERNELS"))),
357 ProteusCacheDir(getEnvOrDefaultString("PROTEUS_CACHE_DIR")) {
359 getEnvOrDefaultBool("PROTEUS_USE_STORED_CACHE", true);
360 ProteusDisable = getEnvOrDefaultBool("PROTEUS_DISABLE", false);
361 ProteusDumpLLVMIR = getEnvOrDefaultBool("PROTEUS_DUMP_LLVM_IR", false);
363 getEnvOrDefaultBool("PROTEUS_RELINK_GLOBALS_BY_COPY", false);
365 getEnvOrDefaultBool("PROTEUS_ASYNC_COMPILATION", false);
367 getEnvOrDefaultBool("PROTEUS_ASYNC_TEST_BLOCKING", false);
368 ProteusAsyncThreads = getEnvOrDefaultInt("PROTEUS_ASYNC_THREADS", 1);
369 ProteusKernelClone = getEnvOrDefaultKC("PROTEUS_KERNEL_CLONE",
371 ProteusEnableTimers = getEnvOrDefaultBool("PROTEUS_ENABLE_TIMERS", false);
372 ProteusTraceOutput = getEnvOrDefaultInt("PROTEUS_TRACE_OUTPUT", 0);
373 ProteusDebugOutput = getEnvOrDefaultBool("PROTEUS_DEBUG_OUTPUT", false);
375 getEnvOrDefaultString("PROTEUS_OBJECT_CACHE_CHAIN").value_or("storage");
377 getEnvOrDefaultBool("PROTEUS_ENABLE_TIME_TRACE", false);
379 getEnvOrDefaultString("PROTEUS_TIME_TRACE_FILE").value_or("");
380 }
381};
382} // namespace proteus
383
384#endif
const void const char * VarName
Definition CompilerInterfaceDevice.cpp:21
void char * KernelName
Definition CompilerInterfaceDevice.cpp:52
Definition Config.hpp:130
void dump(T &OS) const
Definition Config.hpp:246
int minBlocksPerSM(int MaxThreads) const
Definition Config.hpp:236
bool specializeArgs() const
Definition Config.hpp:226
bool specializeDimsRange() const
Definition Config.hpp:228
static CodeGenerationConfig createFromJSONEntry(const llvm::json::Object &Config)
Definition Config.hpp:198
bool specializeLaunchBounds() const
Definition Config.hpp:229
std::optional< const std::string > optPipeline() const
Definition Config.hpp:232
static CodeGenerationConfig createFromEnv()
Definition Config.hpp:184
bool specializeDims() const
Definition Config.hpp:227
char optLevel() const
Definition Config.hpp:230
CodegenOption codeGenOption() const
Definition Config.hpp:225
int codeGenOptLevel() const
Definition Config.hpp:231
Definition Config.hpp:298
int ProteusTraceOutput
Definition Config.hpp:315
bool ProteusDisable
Definition Config.hpp:307
static Config & get()
Definition Config.hpp:300
std::string ProteusObjectCacheChain
Definition Config.hpp:318
bool ProteusRelinkGlobalsByCopy
Definition Config.hpp:309
const llvm::StringMap< const CodeGenerationConfig > TunedConfigs
Definition Config.hpp:305
bool ProteusDumpLLVMIR
Definition Config.hpp:308
bool ProteusDebugOutput
Definition Config.hpp:316
const CodeGenerationConfig GlobalCodeGenConfig
Definition Config.hpp:304
bool ProteusUseStoredCache
Definition Config.hpp:306
int ProteusAsyncThreads
Definition Config.hpp:311
KernelCloneOption ProteusKernelClone
Definition Config.hpp:313
void dump(llvm::raw_ostream &OS) const
Definition Config.hpp:333
const CodeGenerationConfig & getCGConfig(llvm::StringRef KName="") const
Definition Config.hpp:322
std::optional< const std::string > ProteusCacheDir
Definition Config.hpp:317
bool ProteusEnableTimers
Definition Config.hpp:314
bool ProteusAsyncTestBlocking
Definition Config.hpp:312
bool ProteusEnableTimeTrace
Definition Config.hpp:319
bool ProteusAsyncCompilation
Definition Config.hpp:310
std::string ProteusTimeTraceFile
Definition Config.hpp:320
static llvm::raw_ostream & outs(const std::string &Name)
Definition Logger.hpp:25
Definition ObjectCacheChain.cpp:26
int getEnvOrDefaultInt(const char *VarName, int Default)
Definition Config.hpp:73
std::optional< std::string > getEnvOrDefaultString(const char *VarName)
Definition Config.hpp:52
void reportFatalError(const llvm::Twine &Reason, const char *FILE, unsigned Line)
Definition Error.cpp:14
T getRuntimeConstantValue(void *Arg)
Definition CompilerInterfaceRuntimeConstantInfo.h:113
CodegenOption
Definition Config.hpp:14
CodegenOption getEnvOrDefaultCG(const char *VarName, CodegenOption Default)
Definition Config.hpp:91
KernelCloneOption
Definition Config.hpp:20
std::string toString(CodegenOption Option)
Definition Config.hpp:26
KernelCloneOption getEnvOrDefaultKC(const char *VarName, KernelCloneOption Default)
Definition Config.hpp:108
llvm::StringMap< const CodeGenerationConfig > parseJSONConfig(std::optional< std::string > JSONFn)
Definition Config.hpp:263
T getDefaultValueFromOptional(std::optional< T > JSONValue, T Default)
Definition Config.hpp:102
char getEnvOrDefaultChar(const char *VarName, char Default)
Definition Config.hpp:61
CodegenOption strToCG(std::string CGstr)
Definition Config.hpp:79
bool getEnvOrDefaultBool(const char *VarName, bool Default)
Definition Config.hpp:67