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(perfetto::LockedHandle<ETWInterceptor> locked_self)19 explicit Delegate(perfetto::LockedHandle<ETWInterceptor> locked_self)
20 : locked_self_(std::move(locked_self)) {
21 DCHECK(locked_self_);
22 }
23 ~Delegate() override;
24
25 perfetto::TrackEventStateTracker::SessionState* GetSessionState() override;
26 void OnTrackUpdated(perfetto::TrackEventStateTracker::Track&) override;
27 void OnTrackEvent(
28 const perfetto::TrackEventStateTracker::Track&,
29 const perfetto::TrackEventStateTracker::ParsedTrackEvent&) override;
30
31 private:
32 perfetto::LockedHandle<ETWInterceptor> locked_self_;
33 };
34
35 ETWInterceptor::Delegate::~Delegate() = default;
36
37 perfetto::TrackEventStateTracker::SessionState*
GetSessionState()38 ETWInterceptor::Delegate::GetSessionState() {
39 return &locked_self_->session_state_;
40 }
41
OnTrackUpdated(perfetto::TrackEventStateTracker::Track & track)42 void ETWInterceptor::Delegate::OnTrackUpdated(
43 perfetto::TrackEventStateTracker::Track& track) {}
44
OnTrackEvent(const perfetto::TrackEventStateTracker::Track & track,const perfetto::TrackEventStateTracker::ParsedTrackEvent & event)45 void ETWInterceptor::Delegate::OnTrackEvent(
46 const perfetto::TrackEventStateTracker::Track& track,
47 const perfetto::TrackEventStateTracker::ParsedTrackEvent& event) {
48 uint64_t keyword = base::trace_event::CategoryGroupToETWKeyword(
49 std::string_view(event.category.data, event.category.size));
50 const char* phase_string = nullptr;
51 switch (event.track_event.type()) {
52 case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN:
53 phase_string = "Begin";
54 break;
55 case perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END:
56 phase_string = "End";
57 break;
58 case perfetto::protos::pbzero::TrackEvent::TYPE_INSTANT:
59 phase_string = "Instant";
60 break;
61 }
62 DCHECK_NE(nullptr, phase_string);
63 // TODO(crbug.com/1465855): Consider exporting thread time once
64 // TrackEventStateTracker supports it.
65 if (event.track_event.type() ==
66 perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END) {
67 locked_self_->provider_->WriteEvent(
68 std::string_view(event.name.data, event.name.size),
69 TlmEventDescriptor(0, keyword),
70 TlmMbcsStringField("Phase", phase_string),
71 TlmUInt64Field(
72 "Timestamp",
73 event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond),
74 TlmUInt64Field(
75 "Duration",
76 event.duration_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
77 } else {
78 locked_self_->provider_->WriteEvent(
79 std::string_view(event.name.data, event.name.size),
80 TlmEventDescriptor(0, keyword),
81 TlmMbcsStringField("Phase", phase_string),
82 TlmUInt64Field(
83 "Timestamp",
84 event.timestamp_ns / base::TimeTicks::kNanosecondsPerMicrosecond));
85 }
86 }
87
ETWInterceptor(TlmProvider * provider)88 ETWInterceptor::ETWInterceptor(TlmProvider* provider) : provider_(provider) {}
89 ETWInterceptor::~ETWInterceptor() = default;
90
Register(TlmProvider * provider)91 void ETWInterceptor::Register(TlmProvider* provider) {
92 perfetto::protos::gen::InterceptorDescriptor desc;
93 desc.set_name("etwexport");
94 perfetto::Interceptor<ETWInterceptor>::Register(desc, provider);
95 }
96
OnTracePacket(InterceptorContext context)97 void ETWInterceptor::OnTracePacket(InterceptorContext context) {
98 auto& tls = context.GetThreadLocalState();
99 perfetto::LockedHandle<ETWInterceptor> locked_self =
100 context.GetInterceptorLocked();
101 if (!locked_self) {
102 return;
103 }
104 Delegate delegate(std::move(locked_self));
105 perfetto::protos::pbzero::TracePacket::Decoder packet(
106 context.packet_data.data, context.packet_data.size);
107 perfetto::TrackEventStateTracker::ProcessTracePacket(
108 delegate, tls.sequence_state, packet);
109 }
110
ThreadLocalState(ThreadLocalStateArgs & args)111 ETWInterceptor::ThreadLocalState::ThreadLocalState(ThreadLocalStateArgs& args) {
112 }
113 ETWInterceptor::ThreadLocalState::~ThreadLocalState() = default;
114
OnSetup(const SetupArgs &)115 void ETWInterceptor::OnSetup(const SetupArgs&) {}
OnStart(const StartArgs &)116 void ETWInterceptor::OnStart(const StartArgs&) {}
OnStop(const StopArgs &)117 void ETWInterceptor::OnStop(const StopArgs&) {}
118
119 } // namespace base::trace_event
120