1 /*
2     SPDX-FileCopyrightText: 2015-2020 Milian Wolff <mail@milianw.de>
3 
4     SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #ifndef ACCUMULATEDTRACEDATA_H
8 #define ACCUMULATEDTRACEDATA_H
9 
10 #include <iosfwd>
11 #include <tuple>
12 #include <vector>
13 
14 #include <fstream>
15 
16 #include <boost/iostreams/filtering_stream.hpp>
17 
18 #include "allocationdata.h"
19 #include "filterparameters.h"
20 #include "util/indices.h"
21 
22 struct Frame
23 {
24     FunctionIndex functionIndex;
25     FileIndex fileIndex;
26     int line = 0;
27 
28     bool operator==(const Frame& rhs) const
29     {
30         return functionIndex == rhs.functionIndex &&
31                 fileIndex == rhs.fileIndex &&
32                 line == rhs.line;
33     }
34 
35     bool operator<(const Frame& rhs) const
36     {
37         return std::tie(functionIndex, fileIndex, line) < std::tie(rhs.functionIndex, rhs.fileIndex, rhs.line);
38     }
39 };
40 
41 struct InstructionPointer
42 {
43     uint64_t instructionPointer = 0;
44     ModuleIndex moduleIndex;
45     Frame frame;
46     std::vector<Frame> inlined;
47 
compareWithoutAddressInstructionPointer48     bool compareWithoutAddress(const InstructionPointer& other) const
49     {
50         return std::tie(moduleIndex, frame) < std::tie(other.moduleIndex, other.frame);
51     }
52 
equalWithoutAddressInstructionPointer53     bool equalWithoutAddress(const InstructionPointer& other) const
54     {
55         return moduleIndex == other.moduleIndex && frame == other.frame;
56     }
57 };
58 
59 struct TraceNode
60 {
61     IpIndex ipIndex;
62     TraceIndex parentIndex;
63 };
64 
65 struct Allocation : public AllocationData
66 {
67     // backtrace entry point
68     TraceIndex traceIndex;
69 };
70 
71 /**
72  * Information for a single call to an allocation function.
73  */
74 struct AllocationInfo
75 {
76     uint64_t size = 0;
77     // index into AccumulatedTraceData::allocations
78     AllocationIndex allocationIndex;
79     bool operator==(const AllocationInfo& rhs) const
80     {
81         return rhs.allocationIndex == allocationIndex && rhs.size == size;
82     }
83 };
84 
85 struct Suppression;
86 
87 struct AccumulatedTraceData
88 {
89     AccumulatedTraceData();
90     virtual ~AccumulatedTraceData();
91 
92     enum ParsePass
93     {
94         // find time of total peak cost
95         FirstPass,
96         // parse individual allocations
97         SecondPass,
98         // GUI only: graph-building
99         ThirdPass
100     };
101 
102     virtual void handleTimeStamp(int64_t oldStamp, int64_t newStamp, bool isFinalTimeStamp, const ParsePass pass) = 0;
103     virtual void handleAllocation(const AllocationInfo& info, const AllocationInfoIndex index) = 0;
104     virtual void handleDebuggee(const char* command) = 0;
105 
106     const std::string& stringify(const StringIndex stringId) const;
107 
108     std::string prettyFunction(const std::string& function) const;
109 
110     bool read(const std::string& inputFile, bool isReparsing);
111     bool read(const std::string& inputFile, const ParsePass pass, bool isReparsing);
112     bool read(boost::iostreams::filtering_istream& in, const ParsePass pass, bool isReparsing);
113 
114     void diff(const AccumulatedTraceData& base);
115 
116     bool shortenTemplates = false;
117     bool fromAttached = false;
118     FilterParameters filterParameters;
119 
120     std::vector<Allocation> allocations;
121     AllocationData totalCost;
122     int64_t totalTime = 0;
123     int64_t peakTime = 0;
124     int64_t peakRSS = 0;
125 
126     struct SystemInfo
127     {
128         int64_t pages = 0;
129         int64_t pageSize = 0;
130     };
131     SystemInfo systemInfo;
132 
133     // our indices are sequentially increasing thus a new allocation can only ever
134     // occur with an index larger than any other we encountered so far
135     // this can be used to our advantage in speeding up the mapToAllocationIndex calls.
136     TraceIndex m_maxAllocationTraceIndex;
137     AllocationIndex m_maxAllocationIndex;
138     // we don't want to shuffle allocations around, so instead keep a secondary
139     // vector around for efficient index lookup
140     std::vector<std::pair<TraceIndex, AllocationIndex>> traceIndexToAllocationIndex;
141 
142     /// find and return the index into the @c allocations vector for the given trace index.
143     /// if the trace index wasn't mapped before, an empty Allocation will be added
144     /// and its index returned.
145     AllocationIndex mapToAllocationIndex(const TraceIndex traceIndex);
146 
147     const InstructionPointer& findIp(const IpIndex ipIndex) const;
148 
149     TraceNode findTrace(const TraceIndex traceIndex) const;
150 
151     bool isStopIndex(const StringIndex index) const;
152 
153     // indices of functions that should stop the backtrace, e.g. main or static
154     // initialization
155     std::vector<StringIndex> stopIndices;
156     std::vector<InstructionPointer> instructionPointers;
157     std::vector<TraceNode> traces;
158     std::vector<std::string> strings;
159     std::vector<IpIndex> opNewIpIndices;
160 
161     std::vector<AllocationInfo> allocationInfos;
162 
163     struct ParsingState
164     {
165         int64_t fileSize = 0; // bytes
166         int64_t readCompressedByte = 0;
167         int64_t readUncompressedByte = 0;
168         int64_t timestamp = 0; // ms
169         ParsePass pass = ParsePass::FirstPass;
170         bool reparsing = false;
171     };
172 
173     ParsingState parsingState;
174 
175     void applyLeakSuppressions();
176     std::vector<Suppression> suppressions;
177     int64_t totalLeakedSuppressed = 0;
178 };
179 
180 #endif // ACCUMULATEDTRACEDATA_H
181