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