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 DefaultSpecializeDimsRange =
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 ProteusSpecializeDimsRange;
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 ProteusSpecializeDimsRange, 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 ProteusSpecializeDimsRange(ProteusSpecializeDimsRange),
177 ProteusOptLevel(ProteusOptLevel),
178 ProteusCodeGenOptLevel(ProteusCodeGenOptLevel),
179 TunedMaxThreads(TunedMaxThreads), MinBlocksPerSM(MinBlocksPerSM) {}
180
181public:
184 getEnvOrDefaultString("PROTEUS_OPT_PIPELINE"),
185 getCodeGen(getEnvOrDefaultCG("PROTEUS_CODEGEN", CodegenOption::RTC)),
186 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_ARGS", true),
187 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_LAUNCH_BOUNDS", true),
188 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS", true),
189 getEnvOrDefaultBool("PROTEUS_SPECIALIZE_DIMS_RANGE",
190 DefaultSpecializeDimsRange),
191 getEnvOrDefaultChar("PROTEUS_OPT_LEVEL", '3'),
192 getEnvOrDefaultInt("PROTEUS_CODEGEN_OPT_LEVEL", 3));
193 }
194
196 createFromJSONEntry(const llvm::json::Object &Config) {
197 auto Pipeline = Config.getString("Pipeline");
198 std::optional<std::string> ProteusPipeline;
199 if (Pipeline)
200 ProteusPipeline = Pipeline.value().str();
201
204 getCodeGen(
205 strToCG(getDefaultValueFromOptional(Config.getString("CodeGen"),
206 llvm::StringRef("rtc"))
207 .str())),
208 getDefaultValueFromOptional(Config.getBoolean("SpecializeArgs"), true),
209 getDefaultValueFromOptional(Config.getBoolean("LaunchBounds"), true),
210 getDefaultValueFromOptional(Config.getBoolean("SpecializeDims"), true),
211 getDefaultValueFromOptional(Config.getBoolean("SpecializeDimsRange"),
212 DefaultSpecializeDimsRange),
213 getDefaultValueFromOptional(Config.getString("OptLevel"),
214 llvm::StringRef("3"))[0],
215 getDefaultValueFromOptional(Config.getInteger("CodeGenOptLevel"),
216 static_cast<int64_t>(3)),
217 getDefaultValueFromOptional(Config.getInteger("TunedMaxThreads"),
218 static_cast<int64_t>(-1L)),
219 getDefaultValueFromOptional(Config.getInteger("MinBlocksPerSM"),
220 static_cast<int64_t>(0L)));
221 }
222
223 CodegenOption codeGenOption() const { return ProteusCodegen; }
224 bool specializeArgs() const { return ProteusSpecializeArgs; }
225 bool specializeDims() const { return ProteusSpecializeDims; }
226 bool specializeDimsRange() const { return ProteusSpecializeDimsRange; }
227 bool specializeLaunchBounds() const { return ProteusSpecializeLaunchBounds; }
228 char optLevel() const { return ProteusOptLevel; }
229 int codeGenOptLevel() const { return ProteusCodeGenOptLevel; }
230 std::optional<const std::string> optPipeline() const {
231 return ProteusOptPipeline;
232 }
233
234 int minBlocksPerSM(int MaxThreads) const {
235 // NOTE: We only return the tuned value when the current LBMaxThreads is
236 // equal to the tuned one. otherwise we return 0. Not doing so, may result
237 // in violating constraints in cases in which LBMaxThreads >
238 // TunedMaxThreads
239 if (TunedMaxThreads != MaxThreads)
240 return 0;
241 return MinBlocksPerSM;
242 }
243
244 template <typename T> void dump(T &OS) const {
245 if (ProteusOptPipeline)
246 OS << "Pipeline:" << ProteusOptPipeline.value() << " ";
247
248 OS << "CG:" << toString(ProteusCodegen) << " ";
249 OS << "SA:" << ProteusSpecializeArgs << " ";
250 OS << "LB:" << ProteusSpecializeLaunchBounds << " ";
251 OS << "SD:" << ProteusSpecializeDims << " ";
252 OS << "SDR:" << ProteusSpecializeDimsRange << " ";
253 OS << "OL:" << ProteusOptLevel << " ";
254 OS << "CGL:" << ProteusCodeGenOptLevel << " ";
255 OS << "TMT:" << TunedMaxThreads << " ";
256 OS << "BPSM:" << MinBlocksPerSM << " ";
257 }
258};
259
261parseJSONConfig(std::optional<std::string> JSONFn) {
263 if (!JSONFn)
264 return TunedConfigs;
265
266 auto JSONRoot = [&JSONFn]() -> std::optional<llvm::json::Object> {
268 llvm::MemoryBuffer::getFile(JSONFn.value(), /* isText */ true,
269 /* RequiresNullTerminator */ true);
270 if (!JSONBuf)
271 PROTEUS_FATAL_ERROR("Error when opening json file: " +
272 JSONBuf.getError().message() + "\n");
273
274 llvm::json::Value JsonInfo =
275 llvm::cantFail(llvm::json::parse(JSONBuf.get()->getBuffer()),
276 "Cannot convert buffer to json value");
277
278 if (auto *Obj = JsonInfo.getAsObject())
279 return *Obj;
280 return std::nullopt;
281 }();
282
283 if (!JSONRoot)
284 PROTEUS_FATAL_ERROR("Top-level JSON is not an object.\n");
285
286 for (auto &KV : JSONRoot.value()) {
287 auto KernelName = KV.first;
288 if (const auto *Options = KV.second.getAsObject()) {
289 TunedConfigs.try_emplace(
291 }
292 }
293 return TunedConfigs;
294}
295
296class Config {
297public:
298 static Config &get() {
299 static Config Conf;
300 return Conf;
301 }
315 std::optional<const std::string> ProteusCacheDir;
316
318
319 if (TunedConfigs.empty())
320 return GlobalCodeGenConfig;
321
322 if (auto It = TunedConfigs.find(KName); It != TunedConfigs.end())
323 return It->second;
324
325 return GlobalCodeGenConfig;
326 }
327
328 void dump(llvm::raw_ostream &OS) const {
329 auto PrintOut = [](llvm::StringRef ID,
333 OS << "ID:" << ID << " ";
334 KConfig.dump(OS);
335 return S;
336 };
337
338 OS << "PROTEUS_USE_STORED_CACHE " << ProteusUseStoredCache << "\n";
339 OS << "PROTEUS_CACHE_DIR " << Config::get().ProteusCacheDir << "\n";
340
341 OS << PrintOut("Default", GlobalCodeGenConfig) << "\n";
342 for (auto &KV : TunedConfigs) {
343 OS << PrintOut(KV.getKey(), KV.second) << "\n";
344 }
345 }
346
347private:
348 Config()
349 : GlobalCodeGenConfig(CodeGenerationConfig::createFromEnv()),
351 parseJSONConfig(getEnvOrDefaultString("PROTEUS_TUNED_KERNELS"))),
352 ProteusCacheDir(getEnvOrDefaultString("PROTEUS_CACHE_DIR")) {
354 getEnvOrDefaultBool("PROTEUS_USE_STORED_CACHE", true);
355 ProteusDisable = getEnvOrDefaultBool("PROTEUS_DISABLE", false);
356 ProteusDumpLLVMIR = getEnvOrDefaultBool("PROTEUS_DUMP_LLVM_IR", false);
358 getEnvOrDefaultBool("PROTEUS_RELINK_GLOBALS_BY_COPY", false);
360 getEnvOrDefaultBool("PROTEUS_ASYNC_COMPILATION", false);
362 getEnvOrDefaultBool("PROTEUS_ASYNC_TEST_BLOCKING", false);
363 ProteusAsyncThreads = getEnvOrDefaultInt("PROTEUS_ASYNC_THREADS", 1);
364 ProteusKernelClone = getEnvOrDefaultKC("PROTEUS_KERNEL_CLONE",
366 ProteusEnableTimers = getEnvOrDefaultBool("PROTEUS_ENABLE_TIMERS", false);
367 ProteusTraceOutput = getEnvOrDefaultInt("PROTEUS_TRACE_OUTPUT", 0);
368 ProteusDebugOutput = getEnvOrDefaultBool("PROTEUS_DEBUG_OUTPUT", false);
369 }
370};
371} // namespace proteus
372
373#endif
const void const char * VarName
Definition CompilerInterfaceDevice.cpp:21
void char * KernelName
Definition CompilerInterfaceDevice.cpp:52
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:7
Definition Config.hpp:130
void dump(T &OS) const
Definition Config.hpp:244
int minBlocksPerSM(int MaxThreads) const
Definition Config.hpp:234
bool specializeArgs() const
Definition Config.hpp:224
bool specializeDimsRange() const
Definition Config.hpp:226
static CodeGenerationConfig createFromJSONEntry(const llvm::json::Object &Config)
Definition Config.hpp:196
bool specializeLaunchBounds() const
Definition Config.hpp:227
std::optional< const std::string > optPipeline() const
Definition Config.hpp:230
static CodeGenerationConfig createFromEnv()
Definition Config.hpp:182
bool specializeDims() const
Definition Config.hpp:225
char optLevel() const
Definition Config.hpp:228
CodegenOption codeGenOption() const
Definition Config.hpp:223
int codeGenOptLevel() const
Definition Config.hpp:229
Definition Config.hpp:296
int ProteusTraceOutput
Definition Config.hpp:313
bool ProteusDisable
Definition Config.hpp:305
static Config & get()
Definition Config.hpp:298
bool ProteusRelinkGlobalsByCopy
Definition Config.hpp:307
const llvm::StringMap< const CodeGenerationConfig > TunedConfigs
Definition Config.hpp:303
bool ProteusDumpLLVMIR
Definition Config.hpp:306
bool ProteusDebugOutput
Definition Config.hpp:314
const CodeGenerationConfig GlobalCodeGenConfig
Definition Config.hpp:302
bool ProteusUseStoredCache
Definition Config.hpp:304
int ProteusAsyncThreads
Definition Config.hpp:309
KernelCloneOption ProteusKernelClone
Definition Config.hpp:311
void dump(llvm::raw_ostream &OS) const
Definition Config.hpp:328
const CodeGenerationConfig & getCGConfig(llvm::StringRef KName="") const
Definition Config.hpp:317
std::optional< const std::string > ProteusCacheDir
Definition Config.hpp:315
bool ProteusEnableTimers
Definition Config.hpp:312
bool ProteusAsyncTestBlocking
Definition Config.hpp:310
bool ProteusAsyncCompilation
Definition Config.hpp:308
static llvm::raw_ostream & outs(const std::string &Name)
Definition Logger.hpp:25
Definition StorageCache.cpp:24
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:261
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