28 for (
const auto &
Block :
O) {
30 auto &
B = Blocks.back();
51 static Expected<BlockHeader> readBlockHeader(DataExtractor &Extractor,
55 H.Size = Extractor.getU32(&
Offset);
56 if (
Offset == CurrentOffset)
57 return make_error<StringError>(
58 Twine(
"Error parsing block header size at offset '") +
59 Twine(CurrentOffset) +
"'",
62 H.Number = Extractor.getU32(&
Offset);
63 if (
Offset == CurrentOffset)
64 return make_error<StringError>(
65 Twine(
"Error parsing block header number at offset '") +
66 Twine(CurrentOffset) +
"'",
69 H.Thread = Extractor.getU64(&
Offset);
70 if (
Offset == CurrentOffset)
71 return make_error<StringError>(
72 Twine(
"Error parsing block header thread id at offset '") +
73 Twine(CurrentOffset) +
"'",
78 static Expected<std::vector<Profile::FuncID>> readPath(DataExtractor &Extractor,
81 std::vector<Profile::FuncID>
Path;
82 auto CurrentOffset =
Offset;
85 FuncId = Extractor.getSigned(&Offset, 4);
86 if (CurrentOffset == Offset)
87 return make_error<StringError>(
88 Twine(
"Error parsing path at offset '") + Twine(CurrentOffset) +
"'",
96 static Expected<Profile::Data> readData(DataExtractor &Extractor,
102 auto CurrentOffset =
Offset;
103 D.CallCount = Extractor.getU64(&Offset);
104 if (CurrentOffset == Offset)
105 return make_error<StringError>(
106 Twine(
"Error parsing call counts at offset '") + Twine(CurrentOffset) +
110 D.CumulativeLocalTime = Extractor.getU64(&Offset);
111 if (CurrentOffset == Offset)
112 return make_error<StringError>(
113 Twine(
"Error parsing cumulative local time at offset '") +
114 Twine(CurrentOffset) +
"'",
122 if (
B.PathData.empty())
123 return make_error<StringError>(
124 "Block may not have empty path data.",
132 auto It = PathIDMap.
find(
P);
133 if (It == PathIDMap.
end())
134 return make_error<StringError>(
137 std::vector<Profile::FuncID> Path;
139 Path.push_back(
Node->Func);
150 auto It = RootToLeafPath.begin();
151 auto PathRoot = *It++;
153 find_if(Roots, [PathRoot](TrieNode *
N) {
return N->Func == PathRoot; });
156 TrieNode *
Node =
nullptr;
157 if (RootIt == Roots.end()) {
158 NodeStorage.emplace_back();
159 Node = &NodeStorage.back();
160 Node->Func = PathRoot;
161 Roots.push_back(
Node);
167 while (It != RootToLeafPath.end()) {
168 auto NodeFuncID = *It++;
169 auto CalleeIt =
find_if(
Node->Callees, [NodeFuncID](TrieNode *
N) {
170 return N->Func == NodeFuncID;
172 if (CalleeIt ==
Node->Callees.end()) {
173 NodeStorage.emplace_back();
174 auto NewNode = &NodeStorage.back();
175 NewNode->Func = NodeFuncID;
176 NewNode->Caller =
Node;
177 Node->Callees.push_back(NewNode);
196 using PathDataMapPtr = std::unique_ptr<PathDataMap>;
199 ThreadProfileIndexMap ThreadProfileIndex;
201 for (
const auto &
P : {std::ref(L), std::ref(R)})
202 for (
const auto &Block :
P.get()) {
203 ThreadProfileIndexMap::iterator It;
204 std::tie(It, std::ignore) = ThreadProfileIndex.
insert(
205 {Block.Thread, PathDataMapPtr{
new PathDataMap()}});
206 for (
const auto &PathAndData : Block.PathData) {
207 auto &PathID = PathAndData.first;
208 auto &
Data = PathAndData.second;
211 PathDataMap::iterator PathDataIt;
213 std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID,
Data});
215 auto &ExistingData = PathDataIt->second;
216 ExistingData.CallCount +=
Data.CallCount;
217 ExistingData.CumulativeLocalTime +=
Data.CumulativeLocalTime;
222 for (
const auto &IndexedThreadBlock : ThreadProfileIndex) {
223 PathDataVector PathAndData;
224 PathAndData.reserve(IndexedThreadBlock.second->size());
225 copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));
227 Merged.
addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));
235 PathDataMap PathData;
237 for (
const auto &
P : {std::ref(L), std::ref(R)})
238 for (
const auto &Block :
P.get())
239 for (
const auto &PathAndData : Block.PathData) {
240 auto &PathId = PathAndData.first;
241 auto &
Data = PathAndData.second;
244 PathDataMap::iterator PathDataIt;
246 std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID,
Data});
248 auto &ExistingData = PathDataIt->second;
249 ExistingData.CallCount +=
Data.CallCount;
250 ExistingData.CumulativeLocalTime +=
Data.CumulativeLocalTime;
255 PathDataVector Block;
256 Block.reserve(PathData.size());
257 copy(PathData, std::back_inserter(Block));
269 return make_error<StringError>(
270 Twine(
"Cannot get filesize of '") + Filename +
"'", EC);
278 return make_error<StringError>(
279 Twine(
"Cannot mmap profile '") + Filename +
"'", EC);
287 while (Offset != MappedFile.
size()) {
288 auto HeaderOrError = readBlockHeader(Extractor, Offset);
290 return HeaderOrError.takeError();
294 const auto &Header = HeaderOrError.get();
297 auto PathOrError = readPath(Extractor, Offset);
299 return PathOrError.takeError();
300 const auto &Path = PathOrError.get();
303 auto DataOrError = readData(Extractor, Offset);
305 return DataOrError.takeError();
306 auto &
Data = DataOrError.get();
310 {{P.internPath(Path), std::move(Data)}}}))
338 for (
const auto &
E :
T) {
339 auto &TSD = ThreadStacks[
E.TId];
341 case RecordTypes::ENTER:
342 case RecordTypes::ENTER_ARG:
345 TSD.push_back({
E.TSC,
E.FuncId});
348 case RecordTypes::EXIT:
349 case RecordTypes::TAIL_EXIT:
355 while (!TSD.empty()) {
356 auto Top = TSD.back();
361 auto InternedPath =
P.internPath(Path);
362 auto &TPD = ThreadPathData[
E.TId][InternedPath];
364 TPD.CumulativeLocalTime += FunctionLocalTime;
369 if (Top.FuncId ==
E.FuncId)
378 case RecordTypes::CUSTOM_EVENT:
379 case RecordTypes::TYPED_EVENT:
388 for (
const auto &ThreadPaths : ThreadPathData) {
389 const auto &TID = ThreadPaths.first;
390 const auto &PathsData = ThreadPaths.second;
391 if (
auto E =
P.addBlock({
393 std::vector<std::pair<Profile::PathID, Profile::Data>>(
394 PathsData.begin(), PathsData.end()),