LLVM 24.0.0git
InstrumentorConfigFile.cpp
Go to the documentation of this file.
1//===-- InstrumentorConfigFile.cpp ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The implementation of the utilities for the Instrumentor JSON configuration
10// file.
11//
12//===----------------------------------------------------------------------===//
13
15
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/StringSet.h"
20#include "llvm/IR/LLVMContext.h"
22#include "llvm/Support/JSON.h"
24#include "llvm/Support/Path.h"
27
28#include <string>
29
30using namespace llvm;
31
34 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
35 : FS.getBufferForFile(Filename);
36 if (std::error_code EC = BufferOrErr.getError())
37 return errorCodeToError(EC);
38 return std::move(BufferOrErr.get());
39}
40
41namespace llvm {
42namespace instrumentor {
43
45 LLVMContext &Ctx) {
46 if (OutputFile.empty())
47 return;
48
49 std::error_code EC;
50 raw_fd_stream OS(OutputFile, EC);
51 if (EC) {
53 Twine("failed to open instrumentor configuration file for writing: ") +
54 EC.message(),
55 DS_Warning));
56 return;
57 }
58
59 json::OStream J(OS, 2);
60 J.objectBegin();
61
62 J.attributeBegin("configuration");
63 J.objectBegin();
64 for (auto *BaseCO : IConf.BaseConfigurationOptions) {
65 switch (BaseCO->Kind) {
67 J.attribute(BaseCO->Name, BaseCO->getString());
68 break;
70 J.attribute(BaseCO->Name, BaseCO->getBool());
71 break;
73 J.attributeArray(BaseCO->Name, [&] {
74 for (StringRef Value : BaseCO->getStringList())
75 J.value(Value);
76 });
77 break;
78 }
79 if (!BaseCO->Description.empty())
80 J.attribute(std::string(BaseCO->Name) + ".description",
81 BaseCO->Description);
82 }
83 J.objectEnd();
84 J.attributeEnd();
85
86 for (unsigned KindVal = 0; KindVal <= InstrumentationLocation::Last;
87 ++KindVal) {
88 auto Kind = InstrumentationLocation::KindTy(KindVal);
89
90 auto &KindChoices = IConf.IChoices[Kind];
91 if (KindChoices.empty())
92 continue;
93
95 J.objectBegin();
96 for (auto &[Name, Choice] : KindChoices) {
97 J.attributeBegin(Name);
98 J.objectBegin();
99 J.attribute("enabled", Choice->Enabled);
100 J.attribute("filter", Choice->Filter);
101 J.attribute("filter.description",
102 "Static property filter to exclude instrumentation.");
103 for (auto &ArgIt : Choice->IRTArgs) {
104 J.attribute(ArgIt.Name, ArgIt.Enabled);
105 if ((ArgIt.Flags & IRTArg::REPLACABLE) ||
106 (ArgIt.Flags & IRTArg::REPLACABLE_CUSTOM))
107 J.attribute(std::string(ArgIt.Name) + ".replace", true);
108 if (!ArgIt.Description.empty())
109 J.attribute(std::string(ArgIt.Name) + ".description",
110 ArgIt.Description);
111 }
112 J.objectEnd();
113 J.attributeEnd();
114 }
115 J.objectEnd();
116 J.attributeEnd();
117 }
118
119 J.objectEnd();
120}
121
122template <typename Map>
123static StringRef closestOption(const Map &Options, StringRef Missing) {
124 uint32_t MaxEdit = 5;
125 StringRef Closest;
126 for (const auto &Key : Options.keys()) {
127 auto EditDist = Missing.edit_distance_insensitive(Key, true, MaxEdit);
128 if (EditDist < MaxEdit) {
129 Closest = Key;
130 MaxEdit = EditDist;
131 }
132 }
133 return Closest;
134}
135
137 LLVMContext &Ctx, vfs::FileSystem &FS) {
138 if (InputFile.empty())
139 return true;
140
141 auto BufferOrErr = setupMemoryBuffer(InputFile, FS);
142 if (Error E = BufferOrErr.takeError()) {
144 Twine("failed to open instrumentor configuration file for reading: ") +
145 toString(std::move(E)),
146 DS_Warning));
147 return false;
148 }
149 auto Buffer = std::move(BufferOrErr.get());
150 json::Path::Root NullRoot;
151 auto Parsed = json::parse(Buffer->getBuffer());
152 if (!Parsed) {
154 Twine("failed to parse instrumentor configuration file: ") +
155 toString(Parsed.takeError()),
156 DS_Warning));
157 return false;
158 }
159 auto *Config = Parsed->getAsObject();
160 if (!Config) {
162 "failed to parse instrumentor configuration file, expected an object "
163 "'{ ... }'",
164 DS_Warning));
165 return false;
166 }
167
169 for (auto *BO : IConf.BaseConfigurationOptions)
170 BCOMap[BO->Name] = BO;
171
173 for (auto &It : *Config) {
174 auto *Obj = It.second.getAsObject();
175 if (!Obj) {
177 "malformed JSON configuration, expected an object", DS_Warning));
178 continue;
179 }
180 if (It.first == "configuration") {
181 for (auto &ObjIt : *Obj) {
182 if (auto *BO = BCOMap.lookup(ObjIt.first)) {
183 switch (BO->Kind) {
185 if (auto V = ObjIt.second.getAsString()) {
186 BO->setString(IConf.SS.save(*V));
187 } else {
189 Twine("configuration key '") + StringRef(ObjIt.first) +
190 Twine("' expects a string, value ignored"),
191 DS_Warning));
192 }
193 break;
195 if (auto V = ObjIt.second.getAsBoolean())
196 BO->setBool(*V);
197 else {
199 Twine("configuration key '") + StringRef(ObjIt.first) +
200 Twine("' expects a boolean, value ignored"),
201 DS_Warning));
202 }
203 break;
205 auto *Values = ObjIt.second.getAsArray();
206 if (!Values) {
208 Twine("configuration key '") + StringRef(ObjIt.first) +
209 Twine("' expects an array of strings, value ignored"),
210 DS_Warning));
211 break;
212 }
213
215 bool AllStrings = true;
216 for (const json::Value &Value : *Values) {
217 auto String = Value.getAsString();
218 if (!String) {
219 AllStrings = false;
220 break;
221 }
222 Strings.push_back(IConf.SS.save(*String));
223 }
224 if (AllStrings)
225 BO->setStringList(Strings);
226 else
228 Twine("configuration key '") + StringRef(ObjIt.first) +
229 Twine("' expects an array of strings, value ignored"),
230 DS_Warning));
231 break;
232 }
233 }
234 } else if (!StringRef(ObjIt.first).ends_with(".description")) {
235 std::string Diag = "configuration key '" + ObjIt.first.str() +
236 "' not found and ignored";
237 StringRef Closest = closestOption(BCOMap, ObjIt.first);
238 if (!Closest.empty())
239 Diag += "; did you mean '" + Closest.str() + "'?";
240 Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
241 }
242 }
243 continue;
244 }
245
246 auto &IChoiceMap =
248 for (auto &ObjIt : *Obj) {
249 auto *InnerObj = ObjIt.second.getAsObject();
250 if (!InnerObj) {
252 "malformed JSON configuration, expected an object", DS_Warning));
253 continue;
254 }
255 auto *IO = IChoiceMap.lookup(ObjIt.first);
256 if (!IO) {
257 std::string Diag =
258 "malformed JSON configuration, expected an object matching "
259 "an instrumentor choice, got '" +
260 ObjIt.first.str() + "'";
261 StringRef Closest = closestOption(IChoiceMap, ObjIt.first);
262 if (!Closest.empty())
263 Diag += "; did you mean '" + Closest.str() + "'?";
264 Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
265 continue;
266 }
267 SeenIOs.insert(IO);
269 StringRef FilterStr;
270 StringSet<> IOOpts;
271 IOOpts.insert("enabled");
272 IOOpts.insert("filter");
273 for (auto &IRArg : IO->IRTArgs)
274 IOOpts.insert(IRArg.Name);
275 for (auto &InnerObjIt : *InnerObj) {
276 auto Name = StringRef(InnerObjIt.first);
277 if (Name == "filter") {
278 if (auto V = InnerObjIt.second.getAsString())
279 FilterStr = IConf.SS.save(*V);
280 } else if (Name.consume_back(".replace")) {
281 ReplaceMap[Name] = InnerObjIt.second.getAsBoolean().value_or(false);
282 } else {
283 ValueMap[Name] = InnerObjIt.second.getAsBoolean().value_or(false);
284 }
285 if (!IOOpts.contains(Name)) {
286 std::string Diag = "unrecognized JSON property '" + Name.str() +
287 "' in configuration for '" + IO->getName().str() +
288 "'";
289 StringRef Closest = closestOption(IOOpts, Name);
290 if (!Closest.empty())
291 Diag += "; did you mean '" + Closest.str() + "'?";
292 Ctx.diagnose(DiagnosticInfoInstrumentation(Diag, DS_Warning));
293 }
294 }
295 IO->Enabled = ValueMap["enabled"];
296 IO->Filter = FilterStr;
297 for (auto &IRArg : IO->IRTArgs) {
298 IRArg.Enabled = ValueMap[IRArg.Name];
299 if (!ReplaceMap.lookup(IRArg.Name)) {
300 IRArg.Flags &= ~IRTArg::REPLACABLE;
301 IRArg.Flags &= ~IRTArg::REPLACABLE_CUSTOM;
302 }
303 }
304 }
305 }
306
307 for (auto &IChoiceMap : IConf.IChoices)
308 for (auto &It : IChoiceMap)
309 if (!SeenIOs.count(It.second))
310 It.second->Enabled = false;
311
312 return true;
313}
314
316 LLVMContext &Ctx, vfs::FileSystem &FS) {
317 if (InputFile.empty())
318 return true;
319
320 auto BufferOrErr = setupMemoryBuffer(InputFile, FS);
321 if (Error E = BufferOrErr.takeError()) {
323 Twine("failed to open instrumentor configuration paths file for "
324 "reading: ") +
325 toString(std::move(E)),
326 DS_Warning));
327 return false;
328 }
329
330 StringRef InputFilePath(sys::path::parent_path(InputFile));
331
332 auto Buffer = std::move(BufferOrErr.get());
333 StringRef Content = Buffer->getBuffer();
334 StringRef EOL = Content.detectEOL();
335 do {
336 auto [LHS, RHS] = Content.split(EOL);
337 std::string ConfigPath = LHS.trim().str();
338 if (!sys::path::is_absolute(ConfigPath)) {
339 SmallString<128> InputFilePathStringVec(InputFilePath);
340 sys::path::append(InputFilePathStringVec, ConfigPath);
341 ConfigPath = InputFilePathStringVec.c_str();
342 }
343 Configs.push_back(ConfigPath);
344 Content = RHS.trim();
345 } while (!Content.empty());
346
347 return true;
348}
349
350} // end namespace instrumentor
351} // end namespace llvm
This file defines the StringMap class.
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
This file supports working with JSON data.
static LVOptions Options
Definition LVOptions.cpp:25
static constexpr StringLiteral Filename
StringSet - A set-like wrapper for the StringMap.
Defines the virtual file system interface vfs::FileSystem.
Diagnostic information for IR instrumentation reporting.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:71
static ErrorOr< std::unique_ptr< MemoryBuffer > > getSTDIN()
Read all of stdin into a file buffer, and return it.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
const char * c_str()
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:129
ValueTy lookup(StringRef Key) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
Definition StringMap.h:250
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
StringRef detectEOL() const
Detect the line ending style of the string.
Definition StringRef.h:866
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition StringRef.h:850
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition StringRef.h:270
StringRef save(const char *S)
Definition StringSaver.h:31
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition StringSet.h:25
bool contains(StringRef key) const
Check if the set contains the given key.
Definition StringSet.h:60
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition StringSet.h:39
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
See the file comment.
Definition ValueMap.h:84
LLVM Value Representation.
Definition Value.h:75
void push_back(const DataType &value)
json::OStream allows writing well-formed JSON without materializing all structures as json::Value ahe...
Definition JSON.h:983
LLVM_ABI void attributeBegin(llvm::StringRef Key)
Definition JSON.cpp:883
void attribute(llvm::StringRef Key, const Value &Contents)
Emit an attribute whose value is self-contained (number, vector<int> etc).
Definition JSON.h:1038
LLVM_ABI void objectBegin()
Definition JSON.cpp:864
void attributeArray(llvm::StringRef Key, Block Contents)
Emit an attribute whose value is an array with elements from the Block.
Definition JSON.h:1042
LLVM_ABI void attributeEnd()
Definition JSON.cpp:903
LLVM_ABI void objectEnd()
Definition JSON.cpp:872
The root is the trivial Path to the root value.
Definition JSON.h:700
A Value is an JSON value of unknown type.
Definition JSON.h:291
A raw_ostream of a file for reading/writing/seeking.
The virtual file system interface.
LLVM_ABI void writeConfigToJSON(InstrumentationConfig &IConf, StringRef OutputFile, LLVMContext &Ctx)
Write the configuration in /p IConf to the file with path OutputFile.
static StringRef closestOption(const Map &Options, StringRef Missing)
LLVM_ABI bool readConfigPathsFile(StringRef InputFile, cl::list< std::string > &Configs, LLVMContext &Ctx, vfs::FileSystem &FS)
Read the configuration paths from the file with path InputFile into Configs.
LLVM_ABI bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile, LLVMContext &Ctx, vfs::FileSystem &FS)
Read the configuration from the file with path InputFile into /p IConf.
LLVM_ABI llvm::Expected< Value > parse(llvm::StringRef JSON)
Parses the provided JSON source, or returns a ParseError.
Definition JSON.cpp:681
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:478
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition Path.cpp:688
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:467
This is an optimization pass for GlobalISel generic memory operations.
static Expected< std::unique_ptr< MemoryBuffer > > setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS)
RelativeUniformCounterPtr Values
Definition InstrProf.h:91
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
unsigned Flags
The flags that describe the properties of the argument.
The class that contains the configuration for the instrumentor.
EnumeratedArray< MapVector< StringRef, InstrumentationOpportunity * >, InstrumentationLocation::KindTy > IChoices
The map registered instrumentation opportunities.
SmallVector< BaseConfigurationOption * > BaseConfigurationOptions
The list of enabled base configuration options.
static KindTy getKindFromStr(StringRef S)
Return the location kind described by a string.
static StringRef getKindStr(KindTy Kind)
Return the string representation given a location kind.
KindTy
The supported location kinds, which are composed of a opportunity type and position.