• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "perfetto/trace_processor/ref_counted.h"
23 #include "perfetto/trace_processor/trace_blob_view.h"
24 #include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
25 #include "src/trace_processor/importers/json/json_utils.h"
26 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
27 #include "src/trace_processor/importers/systrace/systrace_line.h"
28 #include "src/trace_processor/storage/trace_storage.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30 
31 // GCC can't figure out the relationship between TimestampedTracePiece's type
32 // and the union, and thus thinks that we may be moving or destroying
33 // uninitialized data in the move constructors / destructors. Disable those
34 // warnings for TimestampedTracePiece and the types it contains.
35 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
36 #pragma GCC diagnostic push
37 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
38 #endif
39 
40 namespace perfetto {
41 namespace trace_processor {
42 
43 struct InlineSchedSwitch {
44   int64_t prev_state;
45   int32_t next_pid;
46   int32_t next_prio;
47   StringId next_comm;
48 };
49 
50 struct InlineSchedWaking {
51   int32_t pid;
52   int32_t target_cpu;
53   int32_t prio;
54   StringId comm;
55 };
56 
57 struct TracePacketData {
58   TraceBlobView packet;
59   RefPtr<PacketSequenceStateGeneration> sequence_state;
60 };
61 
62 struct FtraceEventData {
63   TraceBlobView event;
64   RefPtr<PacketSequenceStateGeneration> sequence_state;
65 };
66 
67 struct TrackEventData : public TracePacketData {
TrackEventDataTrackEventData68   TrackEventData(TraceBlobView pv,
69                  RefPtr<PacketSequenceStateGeneration> generation)
70       : TracePacketData{std::move(pv), std::move(generation)} {}
71 
72   static constexpr size_t kMaxNumExtraCounters = 8;
73 
74   base::Optional<int64_t> thread_timestamp;
75   base::Optional<int64_t> thread_instruction_count;
76   double counter_value = 0;
77   std::array<double, kMaxNumExtraCounters> extra_counter_values = {};
78 };
79 
80 // On Windows std::aligned_storage was broken before VS 2017 15.8 and the
81 // compiler (even clang-cl) requires -D_ENABLE_EXTENDED_ALIGNED_STORAGE. Given
82 // the alignment here is purely a performance enhancment with no other
83 // functional requirement, disable it on Win.
84 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
85 #define PERFETTO_TTS_ALIGNMENT alignas(64)
86 #else
87 #define PERFETTO_TTS_ALIGNMENT
88 #endif
89 
90 // A TimestampedTracePiece is (usually a reference to) a piece of a trace that
91 // is sorted by TraceSorter.
92 struct PERFETTO_TTS_ALIGNMENT TimestampedTracePiece {
93   enum class Type {
94     kInvalid = 0,
95     kFtraceEvent,
96     kTracePacket,
97     kInlineSchedSwitch,
98     kInlineSchedWaking,
99     kJsonValue,
100     kFuchsiaRecord,
101     kTrackEvent,
102     kSystraceLine,
103   };
104 
TimestampedTracePieceTimestampedTracePiece105   TimestampedTracePiece(int64_t ts,
106                         uint64_t idx,
107                         TraceBlobView tbv,
108                         RefPtr<PacketSequenceStateGeneration> sequence_state)
109       : packet_data{std::move(tbv), std::move(sequence_state)},
110         timestamp(ts),
111         packet_idx(idx),
112         type(Type::kTracePacket) {}
113 
TimestampedTracePieceTimestampedTracePiece114   TimestampedTracePiece(int64_t ts, uint64_t idx, FtraceEventData fed)
115       : ftrace_event(std::move(fed)),
116         timestamp(ts),
117         packet_idx(idx),
118         type(Type::kFtraceEvent) {}
119 
TimestampedTracePieceTimestampedTracePiece120   TimestampedTracePiece(int64_t ts, uint64_t idx, std::string value)
121       : json_value(std::move(value)),
122         timestamp(ts),
123         packet_idx(idx),
124         type(Type::kJsonValue) {}
125 
TimestampedTracePieceTimestampedTracePiece126   TimestampedTracePiece(int64_t ts,
127                         uint64_t idx,
128                         std::unique_ptr<FuchsiaRecord> fr)
129       : fuchsia_record(std::move(fr)),
130         timestamp(ts),
131         packet_idx(idx),
132         type(Type::kFuchsiaRecord) {}
133 
TimestampedTracePieceTimestampedTracePiece134   TimestampedTracePiece(int64_t ts,
135                         uint64_t idx,
136                         std::unique_ptr<TrackEventData> ted)
137       : track_event_data(std::move(ted)),
138         timestamp(ts),
139         packet_idx(idx),
140         type(Type::kTrackEvent) {}
141 
TimestampedTracePieceTimestampedTracePiece142   TimestampedTracePiece(int64_t ts,
143                         uint64_t idx,
144                         std::unique_ptr<SystraceLine> ted)
145       : systrace_line(std::move(ted)),
146         timestamp(ts),
147         packet_idx(idx),
148         type(Type::kSystraceLine) {}
149 
TimestampedTracePieceTimestampedTracePiece150   TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedSwitch iss)
151       : sched_switch(std::move(iss)),
152         timestamp(ts),
153         packet_idx(idx),
154         type(Type::kInlineSchedSwitch) {}
155 
TimestampedTracePieceTimestampedTracePiece156   TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedWaking isw)
157       : sched_waking(std::move(isw)),
158         timestamp(ts),
159         packet_idx(idx),
160         type(Type::kInlineSchedWaking) {}
161 
TimestampedTracePieceTimestampedTracePiece162   TimestampedTracePiece(TimestampedTracePiece&& ttp) noexcept {
163     // Adopt |ttp|'s data. We have to use placement-new to fill the fields
164     // because their original values may be uninitialized and thus
165     // move-assignment won't work correctly.
166     switch (ttp.type) {
167       case Type::kInvalid:
168         break;
169       case Type::kFtraceEvent:
170         new (&ftrace_event) FtraceEventData(std::move(ttp.ftrace_event));
171         break;
172       case Type::kTracePacket:
173         new (&packet_data) TracePacketData(std::move(ttp.packet_data));
174         break;
175       case Type::kInlineSchedSwitch:
176         new (&sched_switch) InlineSchedSwitch(std::move(ttp.sched_switch));
177         break;
178       case Type::kInlineSchedWaking:
179         new (&sched_waking) InlineSchedWaking(std::move(ttp.sched_waking));
180         break;
181       case Type::kJsonValue:
182         new (&json_value) std::string(std::move(ttp.json_value));
183         break;
184       case Type::kFuchsiaRecord:
185         new (&fuchsia_record)
186             std::unique_ptr<FuchsiaRecord>(std::move(ttp.fuchsia_record));
187         break;
188       case Type::kTrackEvent:
189         new (&track_event_data)
190             std::unique_ptr<TrackEventData>(std::move(ttp.track_event_data));
191         break;
192       case Type::kSystraceLine:
193         new (&systrace_line)
194             std::unique_ptr<SystraceLine>(std::move(ttp.systrace_line));
195     }
196     timestamp = ttp.timestamp;
197     packet_idx = ttp.packet_idx;
198     type = ttp.type;
199 
200     // Invalidate |ttp|.
201     ttp.type = Type::kInvalid;
202   }
203 
204   TimestampedTracePiece& operator=(TimestampedTracePiece&& ttp) {
205     if (this != &ttp) {
206       // First invoke the destructor and then invoke the move constructor
207       // inline via placement-new to implement move-assignment.
208       this->~TimestampedTracePiece();
209       new (this) TimestampedTracePiece(std::move(ttp));
210     }
211     return *this;
212   }
213 
214   TimestampedTracePiece(const TimestampedTracePiece&) = delete;
215   TimestampedTracePiece& operator=(const TimestampedTracePiece&) = delete;
216 
~TimestampedTracePieceTimestampedTracePiece217   ~TimestampedTracePiece() {
218     switch (type) {
219       case Type::kInvalid:
220       case Type::kInlineSchedSwitch:
221       case Type::kInlineSchedWaking:
222         break;
223       case Type::kFtraceEvent:
224         ftrace_event.~FtraceEventData();
225         break;
226       case Type::kTracePacket:
227         packet_data.~TracePacketData();
228         break;
229       case Type::kJsonValue:
230         json_value.~basic_string();
231         break;
232       case Type::kFuchsiaRecord:
233         fuchsia_record.~unique_ptr();
234         break;
235       case Type::kTrackEvent:
236         track_event_data.~unique_ptr();
237         break;
238       case Type::kSystraceLine:
239         systrace_line.~unique_ptr();
240         break;
241     }
242   }
243 
244   // For std::lower_bound().
CompareTimestampedTracePiece245   static inline bool Compare(const TimestampedTracePiece& x, int64_t ts) {
246     return x.timestamp < ts;
247   }
248 
249   // For std::sort().
250   inline bool operator<(const TimestampedTracePiece& o) const {
251     return timestamp < o.timestamp ||
252            (timestamp == o.timestamp && packet_idx < o.packet_idx);
253   }
254 
255   // For std::sort(). Without this the compiler will fall back on invoking
256   // move operators on temporary objects.
swapTimestampedTracePiece257   friend void swap(TimestampedTracePiece& a, TimestampedTracePiece& b) {
258     // We know that TimestampedTracePiece is 64-byte aligned (because of the
259     // alignas(64) in the declaration above). We also know that swapping it is
260     // trivial and we can just swap the memory without invoking move operators.
261     // The cast to aligned_storage below allows the compiler to turn this into
262     // a bunch of movaps with large XMM registers (128/256/512 bit depending on
263     // -mavx).
264     using AS =
265         typename std::aligned_storage<sizeof(TimestampedTracePiece),
266                                       alignof(TimestampedTracePiece)>::type;
267     using std::swap;
268     swap(reinterpret_cast<AS&>(a), reinterpret_cast<AS&>(b));
269   }
270 
271   // Fields ordered for packing.
272 
273   // Data for different types of TimestampedTracePiece.
274   union {
275     FtraceEventData ftrace_event;
276     TracePacketData packet_data;
277     InlineSchedSwitch sched_switch;
278     InlineSchedWaking sched_waking;
279     std::string json_value;
280     std::unique_ptr<FuchsiaRecord> fuchsia_record;
281     std::unique_ptr<TrackEventData> track_event_data;
282     std::unique_ptr<SystraceLine> systrace_line;
283   };
284 
285   int64_t timestamp;
286   uint64_t packet_idx;
287   Type type;
288 };
289 
290 // std::sort<TTS> is an extremely hot path in TraceProcessor (in trace_sorter.h)
291 // When TTS is 512-bit wide, we can leverage SIMD instructions to swap it by
292 // declaring it aligned at its own size, without losing any space in the
293 // CircularQueue due to fragmentation. This makes a 6% difference in the
294 // ingestion time of a large trace. See the comments above in the swap() above.
295 static_assert(sizeof(TimestampedTracePiece) <= 64,
296               "TimestampedTracePiece cannot grow beyond 64 bytes");
297 
298 }  // namespace trace_processor
299 }  // namespace perfetto
300 
301 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
302 #pragma GCC diagnostic pop
303 #endif
304 
305 #endif  // SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
306