1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
18 #define SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
19 
20 #include "perfetto/base/build_config.h"
21 #include "perfetto/trace_processor/basic_types.h"
22 #include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
23 #include "src/trace_processor/importers/json/json_utils.h"
24 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
25 #include "src/trace_processor/importers/systrace/systrace_line.h"
26 #include "src/trace_processor/storage/trace_storage.h"
27 #include "src/trace_processor/trace_blob_view.h"
28 #include "src/trace_processor/types/trace_processor_context.h"
29 
30 // GCC can't figure out the relationship between TimestampedTracePiece's type
31 // and the union, and thus thinks that we may be moving or destroying
32 // uninitialized data in the move constructors / destructors. Disable those
33 // warnings for TimestampedTracePiece and the types it contains.
34 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
35 #pragma GCC diagnostic push
36 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
37 #endif
38 
39 namespace perfetto {
40 namespace trace_processor {
41 
42 struct InlineSchedSwitch {
43   int64_t prev_state;
44   int32_t next_pid;
45   int32_t next_prio;
46   StringId next_comm;
47 };
48 
49 struct InlineSchedWaking {
50   int32_t pid;
51   int32_t target_cpu;
52   int32_t prio;
53   StringId comm;
54 };
55 
56 struct TracePacketData {
57   TraceBlobView packet;
58   std::shared_ptr<PacketSequenceStateGeneration> sequence_state;
59 };
60 
61 struct FtraceEventData {
62   TraceBlobView event;
63   std::shared_ptr<PacketSequenceStateGeneration> sequence_state;
64 };
65 
66 struct TrackEventData : public TracePacketData {
TrackEventDataTrackEventData67   TrackEventData(TraceBlobView pv,
68                  std::shared_ptr<PacketSequenceStateGeneration> generation)
69       : TracePacketData{std::move(pv), std::move(generation)} {}
70 
71   static constexpr size_t kMaxNumExtraCounters = 8;
72 
73   int64_t thread_timestamp = 0;
74   int64_t thread_instruction_count = 0;
75   int64_t counter_value = 0;
76   std::array<int64_t, kMaxNumExtraCounters> extra_counter_values = {};
77 };
78 
79 // A TimestampedTracePiece is (usually a reference to) a piece of a trace that
80 // is sorted by TraceSorter.
81 struct TimestampedTracePiece {
82   enum class Type {
83     kInvalid = 0,
84     kFtraceEvent,
85     kTracePacket,
86     kInlineSchedSwitch,
87     kInlineSchedWaking,
88     kJsonValue,
89     kFuchsiaRecord,
90     kTrackEvent,
91     kSystraceLine,
92   };
93 
TimestampedTracePieceTimestampedTracePiece94   TimestampedTracePiece(
95       int64_t ts,
96       uint64_t idx,
97       TraceBlobView tbv,
98       std::shared_ptr<PacketSequenceStateGeneration> sequence_state)
99       : packet_data{std::move(tbv), std::move(sequence_state)},
100         timestamp(ts),
101         packet_idx(idx),
102         type(Type::kTracePacket) {}
103 
TimestampedTracePieceTimestampedTracePiece104   TimestampedTracePiece(int64_t ts, uint64_t idx, FtraceEventData fed)
105       : ftrace_event(std::move(fed)),
106         timestamp(ts),
107         packet_idx(idx),
108         type(Type::kFtraceEvent) {}
109 
TimestampedTracePieceTimestampedTracePiece110   TimestampedTracePiece(int64_t ts,
111                         uint64_t idx,
112                         std::unique_ptr<Json::Value> value)
113       : json_value(std::move(value)),
114         timestamp(ts),
115         packet_idx(idx),
116         type(Type::kJsonValue) {}
117 
TimestampedTracePieceTimestampedTracePiece118   TimestampedTracePiece(int64_t ts,
119                         uint64_t idx,
120                         std::unique_ptr<FuchsiaRecord> fr)
121       : fuchsia_record(std::move(fr)),
122         timestamp(ts),
123         packet_idx(idx),
124         type(Type::kFuchsiaRecord) {}
125 
TimestampedTracePieceTimestampedTracePiece126   TimestampedTracePiece(int64_t ts,
127                         uint64_t idx,
128                         std::unique_ptr<TrackEventData> ted)
129       : track_event_data(std::move(ted)),
130         timestamp(ts),
131         packet_idx(idx),
132         type(Type::kTrackEvent) {}
133 
TimestampedTracePieceTimestampedTracePiece134   TimestampedTracePiece(int64_t ts,
135                         uint64_t idx,
136                         std::unique_ptr<SystraceLine> ted)
137       : systrace_line(std::move(ted)),
138         timestamp(ts),
139         packet_idx(idx),
140         type(Type::kSystraceLine) {}
141 
TimestampedTracePieceTimestampedTracePiece142   TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedSwitch iss)
143       : sched_switch(std::move(iss)),
144         timestamp(ts),
145         packet_idx(idx),
146         type(Type::kInlineSchedSwitch) {}
147 
TimestampedTracePieceTimestampedTracePiece148   TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedWaking isw)
149       : sched_waking(std::move(isw)),
150         timestamp(ts),
151         packet_idx(idx),
152         type(Type::kInlineSchedWaking) {}
153 
TimestampedTracePieceTimestampedTracePiece154   TimestampedTracePiece(TimestampedTracePiece&& ttp) noexcept {
155     // Adopt |ttp|'s data. We have to use placement-new to fill the fields
156     // because their original values may be uninitialized and thus
157     // move-assignment won't work correctly.
158     switch (ttp.type) {
159       case Type::kInvalid:
160         break;
161       case Type::kFtraceEvent:
162         new (&ftrace_event) FtraceEventData(std::move(ttp.ftrace_event));
163         break;
164       case Type::kTracePacket:
165         new (&packet_data) TracePacketData(std::move(ttp.packet_data));
166         break;
167       case Type::kInlineSchedSwitch:
168         new (&sched_switch) InlineSchedSwitch(std::move(ttp.sched_switch));
169         break;
170       case Type::kInlineSchedWaking:
171         new (&sched_waking) InlineSchedWaking(std::move(ttp.sched_waking));
172         break;
173       case Type::kJsonValue:
174         new (&json_value)
175             std::unique_ptr<Json::Value>(std::move(ttp.json_value));
176         break;
177       case Type::kFuchsiaRecord:
178         new (&fuchsia_record)
179             std::unique_ptr<FuchsiaRecord>(std::move(ttp.fuchsia_record));
180         break;
181       case Type::kTrackEvent:
182         new (&track_event_data)
183             std::unique_ptr<TrackEventData>(std::move(ttp.track_event_data));
184         break;
185       case Type::kSystraceLine:
186         new (&systrace_line)
187             std::unique_ptr<SystraceLine>(std::move(ttp.systrace_line));
188     }
189     timestamp = ttp.timestamp;
190     packet_idx = ttp.packet_idx;
191     type = ttp.type;
192 
193     // Invalidate |ttp|.
194     ttp.type = Type::kInvalid;
195   }
196 
197   TimestampedTracePiece& operator=(TimestampedTracePiece&& ttp) {
198     if (this != &ttp) {
199       // First invoke the destructor and then invoke the move constructor
200       // inline via placement-new to implement move-assignment.
201       this->~TimestampedTracePiece();
202       new (this) TimestampedTracePiece(std::move(ttp));
203     }
204     return *this;
205   }
206 
207   TimestampedTracePiece(const TimestampedTracePiece&) = delete;
208   TimestampedTracePiece& operator=(const TimestampedTracePiece&) = delete;
209 
~TimestampedTracePieceTimestampedTracePiece210   ~TimestampedTracePiece() {
211     switch (type) {
212       case Type::kInvalid:
213       case Type::kInlineSchedSwitch:
214       case Type::kInlineSchedWaking:
215         break;
216       case Type::kFtraceEvent:
217         ftrace_event.~FtraceEventData();
218         break;
219       case Type::kTracePacket:
220         packet_data.~TracePacketData();
221         break;
222       case Type::kJsonValue:
223         json_value.~unique_ptr();
224         break;
225       case Type::kFuchsiaRecord:
226         fuchsia_record.~unique_ptr();
227         break;
228       case Type::kTrackEvent:
229         track_event_data.~unique_ptr();
230         break;
231       case Type::kSystraceLine:
232         systrace_line.~unique_ptr();
233         break;
234     }
235   }
236 
237   // For std::lower_bound().
CompareTimestampedTracePiece238   static inline bool Compare(const TimestampedTracePiece& x, int64_t ts) {
239     return x.timestamp < ts;
240   }
241 
242   // For std::sort().
243   inline bool operator<(const TimestampedTracePiece& o) const {
244     return timestamp < o.timestamp ||
245            (timestamp == o.timestamp && packet_idx < o.packet_idx);
246   }
247 
248   // Fields ordered for packing.
249 
250   // Data for different types of TimestampedTracePiece.
251   union {
252     FtraceEventData ftrace_event;
253     TracePacketData packet_data;
254     InlineSchedSwitch sched_switch;
255     InlineSchedWaking sched_waking;
256     std::unique_ptr<Json::Value> json_value;
257     std::unique_ptr<FuchsiaRecord> fuchsia_record;
258     std::unique_ptr<TrackEventData> track_event_data;
259     std::unique_ptr<SystraceLine> systrace_line;
260   };
261 
262   int64_t timestamp;
263   uint64_t packet_idx;
264   Type type;
265 };
266 
267 }  // namespace trace_processor
268 }  // namespace perfetto
269 
270 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
271 #pragma GCC diagnostic pop
272 #endif
273 
274 #endif  // SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
275