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 <string>
5
6#include "proteus/Error.h"
7#include "proteus/Logger.hpp"
8#include "llvm/ADT/StringMap.h"
9#include <llvm/Support/JSON.h>
10#include <llvm/Support/MemoryBuffer.h>
11
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 PROTEUS_FATAL_ERROR("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 DefaultSpecializeDimsAssume =
132#if PROTEUS_ENABLE_CUDA
133 false;
134#else
135 true;
136#endif
137
138 static CodegenOption getCodeGen(CodegenOption ProteusCodegen) {
139 constexpr bool SupportOnlyRTC =
140#if defined(PROTEUS_ENABLE_CUDA)
141 true;
142#else
143 false;
144#endif
145 if (SupportOnlyRTC && ProteusCodegen != CodegenOption::RTC) {
146 Logger::outs("proteus") << "Warning: Proteus supports only RTC in the "
147 "current build system configuration, "
148 "defaulting Codegen to RTC\n";
149 ProteusCodegen = CodegenOption::RTC;
150 }
151 return ProteusCodegen;
152 }
153
154 std::optional<const std::string> ProteusOptPipeline;
155 CodegenOption ProteusCodegen;
156 bool ProteusSpecializeArgs;
157 bool ProteusSpecializeLaunchBounds;
158 bool ProteusSpecializeDims;
159 bool ProteusSpecializeDimsAssume;
160 char ProteusOptLevel;
161 int ProteusCodeGenOptLevel;
162 int TunedMaxThreads;
163 int MinBlocksPerSM;
164
165 CodeGenerationConfig(std::optional<const std::string> ProteusOptPipeline,
166 CodegenOption ProteusCodegen, bool ProteusSpecializeArgs,
167 bool ProteusSpecializeLaunchBounds,
168 bool ProteusSpecializeDims,
169 bool ProteusSpecializeDimsAssume, char ProteusOptLevel,
170 int ProteusCodeGenOptLevel, int TunedMaxThreads = -1,
171 int MinBlocksPerSM = 0)
172 : ProteusOptPipeline(ProteusOptPipeline), ProteusCodegen(ProteusCodegen),
173 ProteusSpecializeArgs(ProteusSpecializeArgs),
174 ProteusSpecializeLaunchBounds(ProteusSpecializeLaunchBounds),
175 ProteusSpecializeDims(ProteusSpecializeDims),
176 ProteusSpecializeDimsAssume(ProteusSpecializeDimsAssume),
177 ProteusOptLevel(ProteusOptLevel),
178 ProteusCodeGenOptLevel(ProteusCodeGenOptLevel),
179 TunedMaxThreads(TunedMaxThreads), MinBlocksPerSM(MinBlocksPerSM) {}
180
181public:
183 constexpr bool DefaultSpecializeDimsAssume =
184#if PROTEUS_ENABLE_CUDA
185 false;
186#else
187 true;
188#endif
190 getEnvOrDefaultString("PROTEUS_OPT_PIPELINE"),
191 getCodeGen(getEnvOrDefaultCG("PROTEUS_CODEGEN", CodegenOption::RTC)),
192 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_ARGS", true),
193 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_LAUNCH_BOUNDS", true),
194 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS", true),
195 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS_ASSUME",
196 DefaultSpecializeDimsAssume),
197 getEnvOrDefaultChar("PROTEUS_OPT_LEVEL", '3'),
198 getEnvOrDefaultInt("PROTEUS_CODEGEN_OPT_LEVEL", 3));
199 }
200
202 createFromJSONEntry(const llvm::json::Object &Config) {
203 auto Pipeline = Config.getString("Pipeline");
204 std::optional<std::string> ProteusPipeline;
205 if (Pipeline)
206 ProteusPipeline = Pipeline.value().str();
207
210 getCodeGen(
211 strToCG(getDefaultValueFromOptional(Config.getString("CodeGen"),
212 llvm::StringRef("rtc"))
213 .str())),
214 getDefaultValueFromOptional(Config.getBoolean("SpecializeArgs"), true),
215 getDefaultValueFromOptional(Config.getBoolean("LaunchBounds"), true),
216 getDefaultValueFromOptional(Config.getBoolean("SpecializeDims"), true),
217 getDefaultValueFromOptional(Config.getBoolean("SpecializeDimsAssume"),
218 DefaultSpecializeDimsAssume),
219 getDefaultValueFromOptional(Config.getString("OptLevel"),
220 llvm::StringRef("3"))[0],
221 getDefaultValueFromOptional(Config.getInteger("CodeGenOptLevel"),
222 static_cast<int64_t>(3)),
223 getDefaultValueFromOptional(Config.getInteger("TunedMaxThreads"),
224 static_cast<int64_t>(-1L)),
225 getDefaultValueFromOptional(Config.getInteger("MinBlocksPerSM"),
226 static_cast<int64_t>(0L)));
227 }
228
229 CodegenOption codeGenOption() const { return ProteusCodegen; }
230 bool specializeArgs() const { return ProteusSpecializeArgs; }
231 bool specializeDims() const { return ProteusSpecializeDims; }
232 bool specializeDimsAssume() const { return ProteusSpecializeDimsAssume; }
233 bool specializeLaunchBounds() const { return ProteusSpecializeLaunchBounds; }
234 char optLevel() const { return ProteusOptLevel; }
235 int codeGenOptLevel() const { return ProteusCodeGenOptLevel; }
236 std::optional<const std::string> optPipeline() const {
237 return ProteusOptPipeline;
238 }
239
240 int minBlocksPerSM(int MaxThreads) const {
241 // NOTE: We only return the tuned value when the current LBMaxThreads is
242 // equal to the tuned one. otherwise we return 0. Not doing so, may result
243 // in violating constraints in cases in which LBMaxThreads >
244 // TunedMaxThreads
245 if (TunedMaxThreads != MaxThreads)
246 return 0;
247 return MinBlocksPerSM;
248 }
249
250 template <typename T> void dump(T &OS) const {
251 if (ProteusOptPipeline)
252 OS << "Pipeline:" << ProteusOptPipeline.value() << " ";
253
254 OS << "CG:" << toString(ProteusCodegen) << " ";
255 OS << "SA:" << ProteusSpecializeArgs << " ";
256 OS << "LB:" << ProteusSpecializeLaunchBounds << " ";
257 OS << "SD:" << ProteusSpecializeDims << " ";
258 OS << "SDA:" << ProteusSpecializeDimsAssume << " ";
259 OS << "OL:" << ProteusOptLevel << " ";
260 OS << "CGL:" << ProteusCodeGenOptLevel << " ";
261 OS << "TMT:" << TunedMaxThreads << " ";
262 OS << "BPSM:" << MinBlocksPerSM << " ";
263 }
264};
265
267parseJSONConfig(std::optional<std::string> JSONFn) {
269 if (!JSONFn)
270 return TunedConfigs;
271
272 auto JSONRoot = [&JSONFn]() -> std::optional<llvm::json::Object> {
274 llvm::MemoryBuffer::getFile(JSONFn.value(), /* isText */ true,
275 /* RequiresNullTerminator */ true);
276 if (!JSONBuf)
277 PROTEUS_FATAL_ERROR("Error when opening json file: " +
278 JSONBuf.getError().message() + "\n");
279
280 llvm::json::Value JsonInfo =
281 llvm::cantFail(llvm::json::parse(JSONBuf.get()->getBuffer()),
282 "Cannot convert buffer to json value");
283
284 if (auto *Obj = JsonInfo.getAsObject())
285 return *Obj;
286 return std::nullopt;
287 }();
288
289 if (!JSONRoot)
290 PROTEUS_FATAL_ERROR("Top-level JSON is not an object.\n");
291
292 for (auto &KV : JSONRoot.value()) {
293 auto KernelName = KV.first;
294 if (const auto *Options = KV.second.getAsObject()) {
295 TunedConfigs.try_emplace(
297 }
298 }
299 return TunedConfigs;
300}
301
302class Config {
303public:
304 static Config &get() {
305 static Config Conf;
306 return Conf;
307 }
321 std::optional<const std::string> ProteusCacheDir;
322
324
325 if (TunedConfigs.empty())
326 return GlobalCodeGenConfig;
327
328 if (auto It = TunedConfigs.find(KName); It != TunedConfigs.end())
329 return It->second;
330
331 return GlobalCodeGenConfig;
332 }
333
334 void dump(llvm::raw_ostream &OS) const {
335 auto PrintOut = [](llvm::StringRef ID,
339 OS << "ID:" << ID << " ";
340 KConfig.dump(OS);
341 return S;
342 };
343
344 OS << "PROTEUS_USE_STORED_CACHE " << ProteusUseStoredCache << "\n";
345 OS << "PROTEUS_CACHE_DIR " << Config::get().ProteusCacheDir << "\n";
346
347 OS << PrintOut("Default", GlobalCodeGenConfig) << "\n";
348 for (auto &KV : TunedConfigs) {
349 OS << PrintOut(KV.getKey(), KV.second) << "\n";
350 }
351 }
352
353private:
354 Config()
355 : GlobalCodeGenConfig(CodeGenerationConfig::createFromEnv()),
357 parseJSONConfig(getEnvOrDefaultString("PROTEUS_TUNED_KERNELS"))),
358 ProteusCacheDir(getEnvOrDefaultString("PROTEUS_CACHE_DIR")) {
360 getEnvOrDefaultBool("PROTEUS_USE_STORED_CACHE", true);
361 ProteusDisable = getEnvOrDefaultBool("PROTEUS_DISABLE", false);
362 ProteusDumpLLVMIR = getEnvOrDefaultBool("PROTEUS_DUMP_LLVM_IR", false);
364 getEnvOrDefaultBool("PROTEUS_RELINK_GLOBALS_BY_COPY", false);
366 getEnvOrDefaultBool("PROTEUS_ASYNC_COMPILATION", false);
368 getEnvOrDefaultBool("PROTEUS_ASYNC_TEST_BLOCKING", false);
369 ProteusAsyncThreads = getEnvOrDefaultInt("PROTEUS_ASYNC_THREADS", 1);
370 ProteusKernelClone = getEnvOrDefaultKC("PROTEUS_KERNEL_CLONE",
372 ProteusEnableTimers = getEnvOrDefaultBool("PROTEUS_ENABLE_TIMERS", false);
373 ProteusTraceOutput = getEnvOrDefaultInt("PROTEUS_TRACE_OUTPUT", 0);
374 ProteusDebugOutput = getEnvOrDefaultBool("PROTEUS_DEBUG_OUTPUT", false);
375 }
376};
377} // namespace proteus
378
379#endif
const char * VarName
Definition CompilerInterfaceDevice.cpp:20
void char * KernelName
Definition CompilerInterfaceDevice.cpp:50
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:7
Definition Config.hpp:130
void dump(T &OS) const
Definition Config.hpp:250
int minBlocksPerSM(int MaxThreads) const
Definition Config.hpp:240
bool specializeArgs() const
Definition Config.hpp:230
static CodeGenerationConfig createFromJSONEntry(const llvm::json::Object &Config)
Definition Config.hpp:202
bool specializeLaunchBounds() const
Definition Config.hpp:233
bool specializeDimsAssume() const
Definition Config.hpp:232
std::optional< const std::string > optPipeline() const
Definition Config.hpp:236
static CodeGenerationConfig createFromEnv()
Definition Config.hpp:182
bool specializeDims() const
Definition Config.hpp:231
char optLevel() const
Definition Config.hpp:234
CodegenOption codeGenOption() const
Definition Config.hpp:229
int codeGenOptLevel() const
Definition Config.hpp:235
Definition Config.hpp:302
int ProteusTraceOutput
Definition Config.hpp:319
bool ProteusDisable
Definition Config.hpp:311
static Config & get()
Definition Config.hpp:304
bool ProteusRelinkGlobalsByCopy
Definition Config.hpp:313
const llvm::StringMap< const CodeGenerationConfig > TunedConfigs
Definition Config.hpp:309
bool ProteusDumpLLVMIR
Definition Config.hpp:312
bool ProteusDebugOutput
Definition Config.hpp:320
const CodeGenerationConfig GlobalCodeGenConfig
Definition Config.hpp:308
bool ProteusUseStoredCache
Definition Config.hpp:310
int ProteusAsyncThreads
Definition Config.hpp:315
KernelCloneOption ProteusKernelClone
Definition Config.hpp:317
void dump(llvm::raw_ostream &OS) const
Definition Config.hpp:334
const CodeGenerationConfig & getCGConfig(llvm::StringRef KName="") const
Definition Config.hpp:323
std::optional< const std::string > ProteusCacheDir
Definition Config.hpp:321
bool ProteusEnableTimers
Definition Config.hpp:318
bool ProteusAsyncTestBlocking
Definition Config.hpp:316
bool ProteusAsyncCompilation
Definition Config.hpp:314
static llvm::raw_ostream & outs(const std::string &Name)
Definition Logger.hpp:25
Definition BuiltinsCUDA.cpp:4
int getEnvOrDefaultInt(const char *VarName, int Default)
Definition Config.hpp:73
std::optional< std::string > getEnvOrDefaultString(const char *VarName)
Definition Config.hpp:52
T getRuntimeConstantValue(void *Arg)
Definition CompilerInterfaceRuntimeConstantInfo.h:114
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:267
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