blob: 429062adba3ecf4aae0a7f4edac87ecc3d0433ef [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/trace_event/etw_interceptor_win.h"
#include "base/containers/flat_map.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event_etw_export_win.h"
#include "third_party/perfetto/protos/perfetto/common/interceptor_descriptor.gen.h"
#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace base::trace_event {
class ETWInterceptor::Delegate
: public perfetto::TrackEventStateTracker::Delegate {
public:
explicit Delegate(InterceptorContext& context)
: context_(&context), locked_self_(context_->GetInterceptorLocked()) {}
~Delegate() override;
perfetto::TrackEventStateTracker::SessionState* GetSessionState() override;
void OnTrackUpdated(perfetto::TrackEventStateTracker::Track&) override;
void OnTrackEvent(
const perfetto::TrackEventStateTracker::Track&,
const perfetto::TrackEventStateTracker::ParsedTrackEvent&) override;
private:
raw_ptr<InterceptorContext> context_;
perfetto::LockedHandle<ETWInterceptor> locked_self_;
};
ETWInterceptor::Delegate::~Delegate() = default;
perfetto::TrackEventStateTracker::SessionState*
ETWInterceptor::Delegate::GetSessionState() {
return &locked_self_->session_state_;
}
void ETWInterceptor::Delegate::OnTrackUpdated(
perfetto::TrackEventStateTracker::Track& track) {}
void ETWInterceptor::Delegate::OnTrackEvent(
const perfetto::TrackEventStateTracker::Track& track,
const perfetto::TrackEventStateTracker::ParsedTrackEvent& event) {
uint64_t keyword = base::trace_event::CategoryGroupToETWKeyword(
std::string_view(event.category.data, event.category.size));
const char* phase_string = nullptr;
switch (event.track_event.type()) {
case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN:
phase_string = "Begin";
break;
case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END:
phase_string = "End";
break;
case perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT:
phase_string = "Instant";
break;
}
DCHECK_NE(nullptr, phase_string);
// TODO(crbug.com/1465855): Consider exporting thread time once
// TrackEventStateTracker supports it.
if (event.track_event.type() ==
perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END) {
locked_self_->provider_->WriteEvent(
std::string_view(event.name.data, event.name.size),
TlmEventDescriptor(0, keyword),
TlmMbcsStringField("Phase", phase_string),
TlmUInt64Field(
"Timestamp",
event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond),
TlmUInt64Field(
"Duration",
event.duration_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
} else {
locked_self_->provider_->WriteEvent(
std::string_view(event.name.data, event.name.size),
TlmEventDescriptor(0, keyword),
TlmMbcsStringField("Phase", phase_string),
TlmUInt64Field(
"Timestamp",
event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
}
}
ETWInterceptor::ETWInterceptor(TlmProvider* provider) : provider_(provider) {}
ETWInterceptor::~ETWInterceptor() = default;
void ETWInterceptor::Register(TlmProvider* provider) {
perfetto::protos::gen::InterceptorDescriptor desc;
desc.set_name("etwexport");
perfetto::Interceptor<ETWInterceptor>::Register(desc, provider);
}
void ETWInterceptor::OnTracePacket(InterceptorContext context) {
auto& tls = context.GetThreadLocalState();
Delegate delegate(context);
perfetto::protos::pbzero::TracePacket::Decoder packet(
context.packet_data.data, context.packet_data.size);
perfetto::TrackEventStateTracker::ProcessTracePacket(
delegate, tls.sequence_state, packet);
}
ETWInterceptor::ThreadLocalState::ThreadLocalState(ThreadLocalStateArgs& args) {
}
ETWInterceptor::ThreadLocalState::~ThreadLocalState() = default;
void ETWInterceptor::OnSetup(const SetupArgs&) {}
void ETWInterceptor::OnStart(const StartArgs&) {}
void ETWInterceptor::OnStop(const StopArgs&) {}
} // namespace base::trace_event