LLVM: lib/XRay/Profile.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

14

19#include

20

21using namespace llvm;

23

25

26

27 for (const auto &Block : O) {

29 auto &B = Blocks.back();

32 PathData.second});

33 }

34}

35

38 *this = std::move(P);

39 return *this;

40}

41

42namespace {

43

44struct BlockHeader {

48};

49}

50

53 BlockHeader H;

55 H.Size = Extractor.getU32(&Offset);

56 if (Offset == CurrentOffset)

58 Twine("Error parsing block header size at offset '") +

59 Twine(CurrentOffset) + "'",

60 std::make_error_code(std::errc::invalid_argument));

61 CurrentOffset = Offset;

62 H.Number = Extractor.getU32(&Offset);

63 if (Offset == CurrentOffset)

65 Twine("Error parsing block header number at offset '") +

66 Twine(CurrentOffset) + "'",

67 std::make_error_code(std::errc::invalid_argument));

68 CurrentOffset = Offset;

69 H.Thread = Extractor.getU64(&Offset);

70 if (Offset == CurrentOffset)

72 Twine("Error parsing block header thread id at offset '") +

73 Twine(CurrentOffset) + "'",

74 std::make_error_code(std::errc::invalid_argument));

75 return H;

76}

77

80

81 std::vectorProfile::FuncID Path;

82 auto CurrentOffset = Offset;

83 int32_t FuncId;

84 do {

85 FuncId = Extractor.getSigned(&Offset, 4);

86 if (CurrentOffset == Offset)

88 Twine("Error parsing path at offset '") + Twine(CurrentOffset) + "'",

89 std::make_error_code(std::errc::invalid_argument));

90 CurrentOffset = Offset;

91 Path.push_back(FuncId);

92 } while (FuncId != 0);

93 return std::move(Path);

94}

95

98

99

100

102 auto CurrentOffset = Offset;

103 D.CallCount = Extractor.getU64(&Offset);

104 if (CurrentOffset == Offset)

106 Twine("Error parsing call counts at offset '") + Twine(CurrentOffset) +

107 "'",

108 std::make_error_code(std::errc::invalid_argument));

109 CurrentOffset = Offset;

110 D.CumulativeLocalTime = Extractor.getU64(&Offset);

111 if (CurrentOffset == Offset)

113 Twine("Error parsing cumulative local time at offset '") +

114 Twine(CurrentOffset) + "'",

115 std::make_error_code(std::errc::invalid_argument));

116 return D;

117}

118

120 if (B.PathData.empty())

122 "Block may not have empty path data.",

123 std::make_error_code(std::errc::invalid_argument));

124

125 Blocks.emplace_back(std::move(B));

127}

128

130 auto It = PathIDMap.find(P);

131 if (It == PathIDMap.end())

134 std::make_error_code(std::errc::invalid_argument));

135 std::vectorProfile::FuncID Path;

137 Path.push_back(Node->Func);

138 return std::move(Path);

139}

140

142 if (P.empty())

143 return 0;

144

145 auto RootToLeafPath = reverse(P);

146

147

148 auto It = RootToLeafPath.begin();

149 auto PathRoot = *It++;

150 auto RootIt =

151 find_if(Roots, [PathRoot](TrieNode *N) { return N->Func == PathRoot; });

152

153

154 TrieNode *Node = nullptr;

155 if (RootIt == Roots.end()) {

156 NodeStorage.emplace_back();

157 Node = &NodeStorage.back();

158 Node->Func = PathRoot;

159 Roots.push_back(Node);

160 } else {

161 Node = *RootIt;

162 }

163

164

165 while (It != RootToLeafPath.end()) {

166 auto NodeFuncID = *It++;

167 auto CalleeIt = find_if(Node->Callees, [NodeFuncID](TrieNode *N) {

168 return N->Func == NodeFuncID;

169 });

170 if (CalleeIt == Node->Callees.end()) {

171 NodeStorage.emplace_back();

172 auto NewNode = &NodeStorage.back();

173 NewNode->Func = NodeFuncID;

174 NewNode->Caller = Node;

175 Node->Callees.push_back(NewNode);

176 Node = NewNode;

177 } else {

178 Node = *CalleeIt;

179 }

180 }

181

182

184 if (Node->ID == 0) {

185 Node->ID = NextID++;

186 PathIDMap.insert({Node->ID, Node});

187 }

188 return Node->ID;

189}

190

194 using PathDataMapPtr = std::unique_ptr;

197 ThreadProfileIndexMap ThreadProfileIndex;

198

199 for (const auto &P : {std::ref(L), std::ref(R)})

200 for (const auto &Block : P.get()) {

201 ThreadProfileIndexMap::iterator It;

202 std::tie(It, std::ignore) = ThreadProfileIndex.insert(

203 {Block.Thread, std::make_unique()});

204 for (const auto &PathAndData : Block.PathData) {

205 auto &PathID = PathAndData.first;

206 auto &Data = PathAndData.second;

207 auto NewPathID =

209 PathDataMap::iterator PathDataIt;

210 bool Inserted;

211 std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID, Data});

212 if (!Inserted) {

213 auto &ExistingData = PathDataIt->second;

214 ExistingData.CallCount += Data.CallCount;

215 ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;

216 }

217 }

218 }

219

220 for (const auto &IndexedThreadBlock : ThreadProfileIndex) {

221 PathDataVector PathAndData;

222 PathAndData.reserve(IndexedThreadBlock.second->size());

223 copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));

225 Merged.addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));

226 }

227 return Merged;

228}

229

233 PathDataMap PathData;

235 for (const auto &P : {std::ref(L), std::ref(R)})

236 for (const auto &Block : P.get())

237 for (const auto &PathAndData : Block.PathData) {

238 auto &PathId = PathAndData.first;

239 auto &Data = PathAndData.second;

240 auto NewPathID =

242 PathDataMap::iterator PathDataIt;

243 bool Inserted;

244 std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID, Data});

245 if (!Inserted) {

246 auto &ExistingData = PathDataIt->second;

247 ExistingData.CallCount += Data.CallCount;

248 ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;

249 }

250 }

251

252

253 PathDataVector Block;

254 Block.reserve(PathData.size());

255 copy(PathData, std::back_inserter(Block));

257 return Merged;

258}

259

262 if (!FdOrErr)

264

268 Twine("Cannot get filesize of '") + Filename + "'", EC);

269

270 std::error_code EC;

273 EC);

275 if (EC)

277 Twine("Cannot mmap profile '") + Filename + "'", EC);

279

283

284

285 while (Offset != MappedFile.size()) {

287 if (!HeaderOrError)

288 return HeaderOrError.takeError();

289

290

291

292 const auto &Header = HeaderOrError.get();

293

294

296 if (!PathOrError)

297 return PathOrError.takeError();

298 const auto &Path = PathOrError.get();

299

300

302 if (!DataOrError)

303 return DataOrError.takeError();

304 auto &Data = DataOrError.get();

305

306 if (auto E =

307 P.addBlock(Profile::Block{Profile::ThreadID{Header.Thread},

308 {{P.internPath(Path), std::move(Data)}}}))

309 return std::move(E);

310 }

311

312 return P;

313}

314

315namespace {

316

317struct StackEntry {

318 uint64_t Timestamp;

319 Profile::FuncID FuncId;

320};

321

322}

323

326

327

328

329

330

333 ThreadPathData;

334

335

336 for (const auto &E : T) {

337 auto &TSD = ThreadStacks[E.TId];

338 switch (E.Type) {

341

342

343 TSD.push_back({E.TSC, E.FuncId});

344 break;

345

348

349

350

351

352

353 while (!TSD.empty()) {

354 auto Top = TSD.back();

358 std::mem_fn(&StackEntry::FuncId));

359 auto InternedPath = P.internPath(Path);

360 auto &TPD = ThreadPathData[E.TId][InternedPath];

361 ++TPD.CallCount;

362 TPD.CumulativeLocalTime += FunctionLocalTime;

363 TSD.pop_back();

364

365

366

367 if (Top.FuncId == E.FuncId)

368 break;

369

370

371

372 }

373

374 break;

375

378

379

380 break;

381 }

382 }

383

384

385

386 for (const auto &ThreadPaths : ThreadPathData) {

387 const auto &TID = ThreadPaths.first;

388 const auto &PathsData = ThreadPaths.second;

389 if (auto E = P.addBlock({

390 TID,

391 std::vector<std::pair<Profile::PathID, Profile::Data>>(

392 PathsData.begin(), PathsData.end()),

393 }))

394 return std::move(E);

395 }

396

397 return P;

398}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static Expected< BlockHeader > readBlockHeader(DataExtractor &Extractor, uint64_t &Offset)

Definition Profile.cpp:51

static Expected< Profile::Data > readData(DataExtractor &Extractor, uint64_t &Offset)

Definition Profile.cpp:96

static Expected< std::vector< Profile::FuncID > > readPath(DataExtractor &Extractor, uint64_t &Offset)

Definition Profile.cpp:78

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

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.

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).

Definition Profile.cpp:141

LLVM_ABI Expected< std::vector< FuncID > > expandPath(PathID P) const

Provides a sequence of function IDs from a previously interned PathID.

Definition Profile.cpp:129

LLVM_ABI Error addBlock(Block &&B)

Appends a fully-formed Block instance into the Profile.

Definition Profile.cpp:119

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...

Definition Profile.cpp:230

LLVM_ABI Expected< Profile > profileFromTrace(const Trace &T)

This function takes a Trace and creates a Profile instance from it.

Definition Profile.cpp:324

LLVM_ABI Expected< Profile > loadProfile(StringRef Filename)

This function will attempt to load an XRay Profiling Mode profile from the provided |Filename|.

Definition Profile.cpp:260

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...

Definition Profile.cpp:191

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)

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

void cantFail(Error Err, const char *Msg=nullptr)

Report a fatal error if Err is a failure value.

FunctionAddr VTableAddr uintptr_t uintptr_t Data

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