27 for (
const auto &
Block : O) {
29 auto &
B = Blocks.back();
50static Expected<BlockHeader> readBlockHeader(DataExtractor &Extractor,
54 H.Size = Extractor.getU32(&
Offset);
55 if (
Offset == CurrentOffset)
56 return make_error<StringError>(
57 Twine(
"Error parsing block header size at offset '") +
58 Twine(CurrentOffset) +
"'",
59 std::make_error_code(std::errc::invalid_argument));
61 H.Number = Extractor.getU32(&
Offset);
62 if (
Offset == CurrentOffset)
63 return make_error<StringError>(
64 Twine(
"Error parsing block header number at offset '") +
65 Twine(CurrentOffset) +
"'",
66 std::make_error_code(std::errc::invalid_argument));
68 H.Thread = Extractor.getU64(&
Offset);
69 if (
Offset == CurrentOffset)
70 return make_error<StringError>(
71 Twine(
"Error parsing block header thread id at offset '") +
72 Twine(CurrentOffset) +
"'",
73 std::make_error_code(std::errc::invalid_argument));
77static Expected<std::vector<Profile::FuncID>> readPath(DataExtractor &Extractor,
80 std::vector<Profile::FuncID>
Path;
81 auto CurrentOffset =
Offset;
85 if (CurrentOffset ==
Offset)
86 return make_error<StringError>(
87 Twine(
"Error parsing path at offset '") + Twine(CurrentOffset) +
"'",
88 std::make_error_code(std::errc::invalid_argument));
92 return std::move(Path);
95static Expected<Profile::Data> readData(DataExtractor &Extractor,
101 auto CurrentOffset =
Offset;
102 D.CallCount = Extractor.getU64(&
Offset);
103 if (CurrentOffset ==
Offset)
104 return make_error<StringError>(
105 Twine(
"Error parsing call counts at offset '") + Twine(CurrentOffset) +
107 std::make_error_code(std::errc::invalid_argument));
109 D.CumulativeLocalTime = Extractor.getU64(&
Offset);
110 if (CurrentOffset ==
Offset)
111 return make_error<StringError>(
112 Twine(
"Error parsing cumulative local time at offset '") +
113 Twine(CurrentOffset) +
"'",
114 std::make_error_code(std::errc::invalid_argument));
121 if (
B.PathData.empty())
122 return make_error<StringError>(
123 "Block may not have empty path data.",
124 std::make_error_code(std::errc::invalid_argument));
126 Blocks.emplace_back(std::move(
B));
131 auto It = PathIDMap.find(
P);
132 if (It == PathIDMap.end())
133 return make_error<StringError>(
135 std::make_error_code(std::errc::invalid_argument));
136 std::vector<Profile::FuncID> Path;
138 Path.push_back(
Node->Func);
139 return std::move(Path);
149 auto It = RootToLeafPath.begin();
150 auto PathRoot = *It++;
152 find_if(Roots, [PathRoot](TrieNode *
N) {
return N->Func == PathRoot; });
155 TrieNode *
Node =
nullptr;
156 if (RootIt == Roots.
end()) {
157 NodeStorage.emplace_back();
158 Node = &NodeStorage.back();
159 Node->Func = PathRoot;
166 while (It != RootToLeafPath.end()) {
167 auto NodeFuncID = *It++;
168 auto CalleeIt =
find_if(
Node->Callees, [NodeFuncID](TrieNode *
N) {
169 return N->Func == NodeFuncID;
171 if (CalleeIt ==
Node->Callees.end()) {
172 NodeStorage.emplace_back();
173 auto NewNode = &NodeStorage.back();
174 NewNode->Func = NodeFuncID;
175 NewNode->Caller =
Node;
176 Node->Callees.push_back(NewNode);
195 using PathDataMapPtr = std::unique_ptr<PathDataMap>;
198 ThreadProfileIndexMap ThreadProfileIndex;
200 for (
const auto &
P : {std::ref(L), std::ref(R)})
201 for (
const auto &
Block :
P.get()) {
202 ThreadProfileIndexMap::iterator It;
203 std::tie(It, std::ignore) = ThreadProfileIndex.
insert(
204 {
Block.Thread, std::make_unique<PathDataMap>()});
205 for (
const auto &PathAndData :
Block.PathData) {
206 auto &PathID = PathAndData.first;
207 auto &
Data = PathAndData.second;
210 PathDataMap::iterator PathDataIt;
212 std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID,
Data});
214 auto &ExistingData = PathDataIt->second;
215 ExistingData.CallCount +=
Data.CallCount;
216 ExistingData.CumulativeLocalTime +=
Data.CumulativeLocalTime;
221 for (
const auto &IndexedThreadBlock : ThreadProfileIndex) {
222 PathDataVector PathAndData;
223 PathAndData.reserve(IndexedThreadBlock.second->size());
224 copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));
226 Merged.
addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));
234 PathDataMap PathData;
236 for (
const auto &
P : {std::ref(L), std::ref(R)})
237 for (
const auto &
Block :
P.get())
238 for (
const auto &PathAndData :
Block.PathData) {
239 auto &PathId = PathAndData.first;
240 auto &
Data = PathAndData.second;
243 PathDataMap::iterator PathDataIt;
245 std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID,
Data});
247 auto &ExistingData = PathDataIt->second;
248 ExistingData.CallCount +=
Data.CallCount;
249 ExistingData.CumulativeLocalTime +=
Data.CumulativeLocalTime;
254 PathDataVector
Block;
255 Block.reserve(PathData.size());
256 copy(PathData, std::back_inserter(
Block));
268 return make_error<StringError>(
269 Twine(
"Cannot get filesize of '") + Filename +
"'", EC);
277 return make_error<StringError>(
278 Twine(
"Cannot mmap profile '") + Filename +
"'", EC);
287 auto HeaderOrError = readBlockHeader(Extractor,
Offset);
289 return HeaderOrError.takeError();
293 const auto &Header = HeaderOrError.get();
296 auto PathOrError = readPath(Extractor,
Offset);
298 return PathOrError.takeError();
299 const auto &Path = PathOrError.get();
302 auto DataOrError = readData(Extractor,
Offset);
304 return DataOrError.takeError();
305 auto &
Data = DataOrError.get();
309 {{P.internPath(Path), std::move(Data)}}}))
337 for (
const auto &
E :
T) {
338 auto &TSD = ThreadStacks[
E.TId];
340 case RecordTypes::ENTER:
341 case RecordTypes::ENTER_ARG:
344 TSD.push_back({
E.TSC,
E.FuncId});
347 case RecordTypes::EXIT:
348 case RecordTypes::TAIL_EXIT:
354 while (!TSD.empty()) {
355 auto Top = TSD.back();
359 std::mem_fn(&StackEntry::FuncId));
360 auto InternedPath =
P.internPath(Path);
361 auto &TPD = ThreadPathData[
E.TId][InternedPath];
363 TPD.CumulativeLocalTime += FunctionLocalTime;
368 if (Top.FuncId ==
E.FuncId)
377 case RecordTypes::CUSTOM_EVENT:
378 case RecordTypes::TYPED_EVENT:
387 for (
const auto &ThreadPaths : ThreadPathData) {
388 const auto &TID = ThreadPaths.first;
389 const auto &PathsData = ThreadPaths.second;
390 if (
auto E =
P.addBlock({
392 std::vector<std::pair<Profile::PathID, Profile::Data>>(
393 PathsData.begin(), PathsData.end()),
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class represents a memory mapped file.
LLVM_ABI size_t size() const
@ readonly
May only access map via const_data as read only.
LLVM_ABI char * data() const
Profile instances are thread-compatible.
Profile & operator=(Profile &&O) noexcept
LLVM_ABI PathID internPath(ArrayRef< FuncID > P)
The stack represented in |P| must be in stack order (leaf to root).
LLVM_ABI Expected< std::vector< FuncID > > expandPath(PathID P) const
Provides a sequence of function IDs from a previously interned PathID.
LLVM_ABI Error addBlock(Block &&B)
Appends a fully-formed Block instance into the Profile.
A Trace object represents the records that have been loaded from XRay log files generated by instrume...
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
LLVM_ABI Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code file_size(const Twine &Path, uint64_t &Result)
Get file size.
LLVM_ABI Profile mergeProfilesByStack(const Profile &L, const Profile &R)
This algorithm will merge two Profile instances into a single Profile instance, aggregating blocks by...
LLVM_ABI Expected< Profile > profileFromTrace(const Trace &T)
This function takes a Trace and creates a Profile instance from it.
LLVM_ABI Expected< Profile > loadProfile(StringRef Filename)
This function will attempt to load an XRay Profiling Mode profile from the provided |Filename|.
LLVM_ABI Profile mergeProfilesByThread(const Profile &L, const Profile &R)
This algorithm will merge two Profile instances into a single Profile instance, aggregating blocks by...
This is an optimization pass for GlobalISel generic memory operations.
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
auto reverse(ContainerTy &&C)
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
constexpr T AbsoluteDifference(U X, V Y)
Subtract two unsigned integers, X and Y, of type T and return the absolute value of the result.
OutputIt copy(R &&Range, OutputIt Out)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
std::vector< std::pair< PathID, Data > > PathData