1 | //===- xray-fdr-dump.cpp: XRay FDR Trace Dump Tool ------------------------===// |
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 | // Implements the FDR trace dumping tool, using the libraries for handling FDR |
10 | // mode traces specifically. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | #include "xray-registry.h" |
14 | #include "llvm/Support/CommandLine.h" |
15 | #include "llvm/Support/FileSystem.h" |
16 | #include "llvm/XRay/BlockIndexer.h" |
17 | #include "llvm/XRay/BlockPrinter.h" |
18 | #include "llvm/XRay/BlockVerifier.h" |
19 | #include "llvm/XRay/FDRRecordConsumer.h" |
20 | #include "llvm/XRay/FDRRecordProducer.h" |
21 | #include "llvm/XRay/FDRRecords.h" |
22 | #include "llvm/XRay/FileHeaderReader.h" |
23 | #include "llvm/XRay/RecordPrinter.h" |
24 | |
25 | using namespace llvm; |
26 | using namespace xray; |
27 | |
28 | static cl::SubCommand Dump("fdr-dump" , "FDR Trace Dump" ); |
29 | static cl::opt<std::string> DumpInput(cl::Positional, |
30 | cl::desc("<xray fdr mode log>" ), |
31 | cl::Required, cl::sub(Dump)); |
32 | static cl::opt<bool> DumpVerify("verify" , |
33 | cl::desc("verify structure of the log" ), |
34 | cl::init(Val: false), cl::sub(Dump)); |
35 | |
36 | static CommandRegistration Unused(&Dump, []() -> Error { |
37 | // Open the file provided. |
38 | auto FDOrErr = sys::fs::openNativeFileForRead(Name: DumpInput); |
39 | if (!FDOrErr) |
40 | return FDOrErr.takeError(); |
41 | |
42 | uint64_t FileSize; |
43 | if (auto EC = sys::fs::file_size(Path: DumpInput, Result&: FileSize)) |
44 | return createStringError(EC, Fmt: "Failed to get file size for '%s'." , |
45 | Vals: DumpInput.c_str()); |
46 | |
47 | std::error_code EC; |
48 | sys::fs::mapped_file_region MappedFile( |
49 | *FDOrErr, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, |
50 | EC); |
51 | sys::fs::closeFile(F&: *FDOrErr); |
52 | |
53 | DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8); |
54 | uint64_t OffsetPtr = 0; |
55 | |
56 | auto = readBinaryFormatHeader(HeaderExtractor&: DE, OffsetPtr); |
57 | if (!FileHeaderOrError) |
58 | return FileHeaderOrError.takeError(); |
59 | auto &H = FileHeaderOrError.get(); |
60 | |
61 | FileBasedRecordProducer P(H, DE, OffsetPtr); |
62 | |
63 | RecordPrinter RP(outs(), "\n" ); |
64 | if (!DumpVerify) { |
65 | PipelineConsumer C({&RP}); |
66 | while (DE.isValidOffsetForDataOfSize(offset: OffsetPtr, length: 1)) { |
67 | auto R = P.produce(); |
68 | if (!R) |
69 | return R.takeError(); |
70 | if (auto E = C.consume(R: std::move(R.get()))) |
71 | return E; |
72 | } |
73 | return Error::success(); |
74 | } |
75 | |
76 | BlockPrinter BP(outs(), RP); |
77 | std::vector<std::unique_ptr<Record>> Records; |
78 | LogBuilderConsumer C(Records); |
79 | while (DE.isValidOffsetForDataOfSize(offset: OffsetPtr, length: 1)) { |
80 | auto R = P.produce(); |
81 | if (!R) { |
82 | // Print records we've found so far. |
83 | for (auto &Ptr : Records) |
84 | if (auto E = Ptr->apply(V&: RP)) |
85 | return joinErrors(E1: std::move(E), E2: R.takeError()); |
86 | return R.takeError(); |
87 | } |
88 | if (auto E = C.consume(R: std::move(R.get()))) |
89 | return E; |
90 | } |
91 | |
92 | // Once we have a trace, we then index the blocks. |
93 | BlockIndexer::Index Index; |
94 | BlockIndexer BI(Index); |
95 | for (auto &Ptr : Records) |
96 | if (auto E = Ptr->apply(V&: BI)) |
97 | return E; |
98 | |
99 | if (auto E = BI.flush()) |
100 | return E; |
101 | |
102 | // Then we validate while printing each block. |
103 | BlockVerifier BV; |
104 | for (const auto &ProcessThreadBlocks : Index) { |
105 | auto &Blocks = ProcessThreadBlocks.second; |
106 | for (auto &B : Blocks) { |
107 | for (auto *R : B.Records) { |
108 | if (auto E = R->apply(V&: BV)) |
109 | return E; |
110 | if (auto E = R->apply(V&: BP)) |
111 | return E; |
112 | } |
113 | BV.reset(); |
114 | BP.reset(); |
115 | } |
116 | } |
117 | outs().flush(); |
118 | return Error::success(); |
119 | }); |
120 | |