1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/trace_event/etw_interceptor_win.h"
6
7 #include "base/containers/flat_map.h"
8 #include "base/time/time.h"
9 #include "base/trace_event/trace_event_etw_export_win.h"
10 #include "third_party/perfetto/protos/perfetto/common/interceptor_descriptor.gen.h"
11 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
12 #include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
13
14 namespace base::trace_event {
15
16 class ETWInterceptor::Delegate
17 : public perfetto::TrackEventStateTracker::Delegate {
18 public:
Delegate(InterceptorContext & context)19 explicit Delegate(InterceptorContext& context)
20 : context_(&context), locked_self_(context_->GetInterceptorLocked()) {}
21 ~Delegate() override;
22
23 perfetto::TrackEventStateTracker::SessionState* GetSessionState() override;
24 void OnTrackUpdated(perfetto::TrackEventStateTracker::Track&) override;
25 void OnTrackEvent(
26 const perfetto::TrackEventStateTracker::Track&,
27 const perfetto::TrackEventStateTracker::ParsedTrackEvent&) override;
28
29 private:
30 raw_ptr<InterceptorContext> context_;
31 perfetto::LockedHandle<ETWInterceptor> locked_self_;
32 };
33
34 ETWInterceptor::Delegate::~Delegate() = default;
35
36 perfetto::TrackEventStateTracker::SessionState*
GetSessionState()37 ETWInterceptor::Delegate::GetSessionState() {
38 return &locked_self_->session_state_;
39 }
40
OnTrackUpdated(perfetto::TrackEventStateTracker::Track & track)41 void ETWInterceptor::Delegate::OnTrackUpdated(
42 perfetto::TrackEventStateTracker::Track& track) {}
43
OnTrackEvent(const perfetto::TrackEventStateTracker::Track & track,const perfetto::TrackEventStateTracker::ParsedTrackEvent & event)44 void ETWInterceptor::Delegate::OnTrackEvent(
45 const perfetto::TrackEventStateTracker::Track& track,
46 const perfetto::TrackEventStateTracker::ParsedTrackEvent& event) {
47 uint64_t keyword = base::trace_event::CategoryGroupToETWKeyword(
48 std::string_view(event.category.data, event.category.size));
49 const char* phase_string = nullptr;
50 switch (event.track_event.type()) {
51 case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN:
52 phase_string = "Begin";
53 break;
54 case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END:
55 phase_string = "End";
56 break;
57 case perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT:
58 phase_string = "Instant";
59 break;
60 }
61 DCHECK_NE(nullptr, phase_string);
62 // TODO(crbug.com/1465855): Consider exporting thread time once
63 // TrackEventStateTracker supports it.
64 if (event.track_event.type() ==
65 perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END) {
66 locked_self_->provider_->WriteEvent(
67 std::string_view(event.name.data, event.name.size),
68 TlmEventDescriptor(0, keyword),
69 TlmMbcsStringField("Phase", phase_string),
70 TlmUInt64Field(
71 "Timestamp",
72 event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond),
73 TlmUInt64Field(
74 "Duration",
75 event.duration_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
76 } else {
77 locked_self_->provider_->WriteEvent(
78 std::string_view(event.name.data, event.name.size),
79 TlmEventDescriptor(0, keyword),
80 TlmMbcsStringField("Phase", phase_string),
81 TlmUInt64Field(
82 "Timestamp",
83 event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
84 }
85 }
86
ETWInterceptor(TlmProvider * provider)87 ETWInterceptor::ETWInterceptor(TlmProvider* provider) : provider_(provider) {}
88 ETWInterceptor::~ETWInterceptor() = default;
89
Register(TlmProvider * provider)90 void ETWInterceptor::Register(TlmProvider* provider) {
91 perfetto::protos::gen::InterceptorDescriptor desc;
92 desc.set_name("etwexport");
93 perfetto::Interceptor<ETWInterceptor>::Register(desc, provider);
94 }
95
OnTracePacket(InterceptorContext context)96 void ETWInterceptor::OnTracePacket(InterceptorContext context) {
97 auto& tls = context.GetThreadLocalState();
98 Delegate delegate(context);
99 perfetto::protos::pbzero::TracePacket::Decoder packet(
100 context.packet_data.data, context.packet_data.size);
101 perfetto::TrackEventStateTracker::ProcessTracePacket(
102 delegate, tls.sequence_state, packet);
103 }
104
ThreadLocalState(ThreadLocalStateArgs & args)105 ETWInterceptor::ThreadLocalState::ThreadLocalState(ThreadLocalStateArgs& args) {
106 }
107 ETWInterceptor::ThreadLocalState::~ThreadLocalState() = default;
108
OnSetup(const SetupArgs &)109 void ETWInterceptor::OnSetup(const SetupArgs&) {}
OnStart(const StartArgs &)110 void ETWInterceptor::OnStart(const StartArgs&) {}
OnStop(const StopArgs &)111 void ETWInterceptor::OnStop(const StopArgs&) {}
112
113 } // namespace base::trace_event
114