blob: 2414f898fc3978c55675b1f79adca394f884d492 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
#define SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
#include "perfetto/base/build_config.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/trace_blob_view.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_storage.h"
#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON_IMPORT)
#include <json/value.h>
#else // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON_IMPORT)
// Json traces are only supported in some build configurations (standalone, UI).
namespace Json {
class Value {};
} // namespace Json
#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON_IMPORT)
// GCC can't figure out the relationship between TimestampedTracePiece's type
// and the union, and thus thinks that we may be moving or destroying
// uninitialized data in the move constructors / destructors. Disable those
// warnings for TimestampedTracePiece and the types it contains.
#if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
namespace perfetto {
namespace trace_processor {
struct InlineSchedSwitch {
int64_t prev_state;
int32_t next_pid;
int32_t next_prio;
StringId next_comm;
};
struct InlineSchedWaking {
int32_t pid;
int32_t target_cpu;
int32_t prio;
StringId comm;
};
struct TracePacketData {
TraceBlobView packet;
PacketSequenceStateGeneration* sequence_state;
};
struct TrackEventData : public TracePacketData {
TrackEventData(TraceBlobView pv,
PacketSequenceStateGeneration* generation,
int64_t thread_ts,
int64_t thread_ic)
: TracePacketData{std::move(pv), generation},
thread_timestamp(thread_ts),
thread_instruction_count(thread_ic) {}
int64_t thread_timestamp;
int64_t thread_instruction_count;
};
// A TimestampedTracePiece is (usually a reference to) a piece of a trace that
// is sorted by TraceSorter.
struct TimestampedTracePiece {
enum class Type {
kInvalid = 0,
kFtraceEvent,
kTracePacket,
kInlineSchedSwitch,
kInlineSchedWaking,
kJsonValue,
kFuchsiaRecord,
kTrackEvent
};
TimestampedTracePiece(int64_t ts,
uint64_t idx,
TraceBlobView tbv,
PacketSequenceStateGeneration* sequence_state)
: packet_data{std::move(tbv), sequence_state},
timestamp(ts),
packet_idx(idx),
type(Type::kTracePacket) {}
TimestampedTracePiece(int64_t ts, uint64_t idx, TraceBlobView tbv)
: ftrace_event(std::move(tbv)),
timestamp(ts),
packet_idx(idx),
type(Type::kFtraceEvent) {}
TimestampedTracePiece(int64_t ts,
uint64_t idx,
std::unique_ptr<Json::Value> value)
: json_value(std::move(value)),
timestamp(ts),
packet_idx(idx),
type(Type::kJsonValue) {}
TimestampedTracePiece(int64_t ts,
uint64_t idx,
std::unique_ptr<FuchsiaRecord> fr)
: fuchsia_record(std::move(fr)),
timestamp(ts),
packet_idx(idx),
type(Type::kFuchsiaRecord) {}
TimestampedTracePiece(int64_t ts,
uint64_t idx,
std::unique_ptr<TrackEventData> ted)
: track_event_data(std::move(ted)),
timestamp(ts),
packet_idx(idx),
type(Type::kTrackEvent) {}
TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedSwitch iss)
: sched_switch(std::move(iss)),
timestamp(ts),
packet_idx(idx),
type(Type::kInlineSchedSwitch) {}
TimestampedTracePiece(int64_t ts, uint64_t idx, InlineSchedWaking isw)
: sched_waking(std::move(isw)),
timestamp(ts),
packet_idx(idx),
type(Type::kInlineSchedWaking) {}
TimestampedTracePiece(TimestampedTracePiece&& ttp) noexcept {
// Adopt |ttp|'s data. We have to use placement-new to fill the fields
// because their original values may be uninitialized and thus
// move-assignment won't work correctly.
switch (ttp.type) {
case Type::kInvalid:
break;
case Type::kFtraceEvent:
new (&ftrace_event) TraceBlobView(std::move(ttp.ftrace_event));
break;
case Type::kTracePacket:
new (&packet_data) TracePacketData(std::move(ttp.packet_data));
break;
case Type::kInlineSchedSwitch:
new (&sched_switch) InlineSchedSwitch(std::move(ttp.sched_switch));
break;
case Type::kInlineSchedWaking:
new (&sched_waking) InlineSchedWaking(std::move(ttp.sched_waking));
break;
case Type::kJsonValue:
new (&json_value)
std::unique_ptr<Json::Value>(std::move(ttp.json_value));
break;
case Type::kFuchsiaRecord:
new (&fuchsia_record)
std::unique_ptr<FuchsiaRecord>(std::move(ttp.fuchsia_record));
break;
case Type::kTrackEvent:
new (&track_event_data)
std::unique_ptr<TrackEventData>(std::move(ttp.track_event_data));
break;
}
timestamp = ttp.timestamp;
packet_idx = ttp.packet_idx;
type = ttp.type;
// Invalidate |ttp|.
ttp.type = Type::kInvalid;
}
TimestampedTracePiece& operator=(TimestampedTracePiece&& ttp) {
if (this != &ttp) {
// First invoke the destructor and then invoke the move constructor
// inline via placement-new to implement move-assignment.
this->~TimestampedTracePiece();
new (this) TimestampedTracePiece(std::move(ttp));
}
return *this;
}
~TimestampedTracePiece() {
switch (type) {
case Type::kInvalid:
case Type::kInlineSchedSwitch:
case Type::kInlineSchedWaking:
break;
case Type::kFtraceEvent:
ftrace_event.~TraceBlobView();
break;
case Type::kTracePacket:
packet_data.~TracePacketData();
break;
case Type::kJsonValue:
json_value.~unique_ptr();
break;
case Type::kFuchsiaRecord:
fuchsia_record.~unique_ptr();
break;
case Type::kTrackEvent:
track_event_data.~unique_ptr();
break;
}
}
// For std::lower_bound().
static inline bool Compare(const TimestampedTracePiece& x, int64_t ts) {
return x.timestamp < ts;
}
// For std::sort().
inline bool operator<(const TimestampedTracePiece& o) const {
return timestamp < o.timestamp ||
(timestamp == o.timestamp && packet_idx < o.packet_idx);
}
// Fields ordered for packing.
// Data for different types of TimestampedTracePiece.
union {
TraceBlobView ftrace_event;
TracePacketData packet_data;
InlineSchedSwitch sched_switch;
InlineSchedWaking sched_waking;
std::unique_ptr<Json::Value> json_value;
std::unique_ptr<FuchsiaRecord> fuchsia_record;
std::unique_ptr<TrackEventData> track_event_data;
};
int64_t timestamp;
uint64_t packet_idx;
Type type;
};
} // namespace trace_processor
} // namespace perfetto
#if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
#pragma GCC diagnostic pop
#endif
#endif // SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_