• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  etw* Copyright (C) 2024 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 #include "src/trace_processor/importers/etw/etw_parser.h"
18 #include <cstdint>
19 #include <limits>
20 
21 #include "perfetto/base/status.h"
22 #include "perfetto/ext/base/string_view.h"
23 #include "perfetto/protozero/field.h"
24 #include "perfetto/trace_processor/status.h"
25 #include "perfetto/trace_processor/trace_blob_view.h"
26 #include "src/trace_processor/importers/common/parser_types.h"
27 #include "src/trace_processor/importers/common/process_tracker.h"
28 #include "src/trace_processor/importers/common/sched_event_tracker.h"
29 #include "src/trace_processor/importers/common/thread_state_tracker.h"
30 #include "src/trace_processor/storage/stats.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 
33 #include "protos/perfetto/trace/etw/etw.pbzero.h"
34 #include "protos/perfetto/trace/etw/etw_event.pbzero.h"
35 #include "src/trace_processor/types/trace_processor_context.h"
36 
37 namespace perfetto {
38 namespace trace_processor {
39 
40 namespace {
41 
42 using protozero::ConstBytes;
43 
44 }  // namespace
EtwParser(TraceProcessorContext * context)45 EtwParser::EtwParser(TraceProcessorContext* context) : context_(context) {}
46 
ParseEtwEvent(uint32_t cpu,int64_t ts,const TracePacketData & data)47 base::Status EtwParser::ParseEtwEvent(uint32_t cpu,
48                                       int64_t ts,
49                                       const TracePacketData& data) {
50   using protos::pbzero::EtwTraceEvent;
51   const TraceBlobView& event = data.packet;
52   protos::pbzero::EtwTraceEvent::Decoder decoder(event.data(), event.length());
53 
54   if (decoder.has_c_switch()) {
55     ParseCswitch(ts, cpu, decoder.c_switch());
56   }
57 
58   if (decoder.has_ready_thread()) {
59     ParseReadyThread(ts, decoder.ready_thread());
60   }
61 
62   return base::OkStatus();
63 }
64 
ParseCswitch(int64_t timestamp,uint32_t cpu,ConstBytes blob)65 void EtwParser::ParseCswitch(int64_t timestamp, uint32_t cpu, ConstBytes blob) {
66   protos::pbzero::CSwitchEtwEvent::Decoder cs(blob);
67   PushSchedSwitch(cpu, timestamp, cs.old_thread_id(), cs.old_thread_state(),
68                   cs.new_thread_id(), cs.new_thread_priority());
69 }
70 
ParseReadyThread(int64_t timestamp,ConstBytes blob)71 void EtwParser::ParseReadyThread(int64_t timestamp, ConstBytes blob) {
72   protos::pbzero::ReadyThreadEtwEvent::Decoder rt(blob);
73   UniqueTid utid =
74       context_->process_tracker->GetOrCreateThread(rt.t_thread_id());
75   ThreadStateTracker::GetOrCreate(context_)->PushWakingEvent(timestamp, utid,
76                                                              utid);
77 }
78 
PushSchedSwitch(uint32_t cpu,int64_t ts,uint32_t prev_tid,int64_t prev_state,uint32_t next_tid,int32_t next_prio)79 void EtwParser::PushSchedSwitch(uint32_t cpu,
80                                 int64_t ts,
81                                 uint32_t prev_tid,
82                                 int64_t prev_state,
83                                 uint32_t next_tid,
84                                 int32_t next_prio) {
85   UniqueTid next_utid = context_->process_tracker->GetOrCreateThread(next_tid);
86 
87   // First use this data to close the previous slice.
88   bool prev_pid_match_prev_next_pid = false;
89   auto* pending_sched = sched_event_state_.GetPendingSchedInfoForCpu(cpu);
90   uint32_t pending_slice_idx = pending_sched->pending_slice_storage_idx;
91   StringId prev_state_string_id = TaskStateToStringId(prev_state);
92   if (prev_state_string_id == kNullStringId) {
93     context_->storage->IncrementStats(stats::task_state_invalid);
94   }
95   if (pending_slice_idx < std::numeric_limits<uint32_t>::max()) {
96     prev_pid_match_prev_next_pid = prev_tid == pending_sched->last_pid;
97     if (PERFETTO_LIKELY(prev_pid_match_prev_next_pid)) {
98       context_->sched_event_tracker->ClosePendingSlice(pending_slice_idx, ts,
99                                                        prev_state_string_id);
100     } else {
101       // If the pids are not consistent, make a note of this.
102       context_->storage->IncrementStats(stats::mismatched_sched_switch_tids);
103     }
104   }
105 
106   auto new_slice_idx = context_->sched_event_tracker->AddStartSlice(
107       cpu, ts, next_utid, next_prio);
108 
109   // Finally, update the info for the next sched switch on this CPU.
110   pending_sched->pending_slice_storage_idx = new_slice_idx;
111   pending_sched->last_pid = next_tid;
112   pending_sched->last_utid = next_utid;
113   pending_sched->last_prio = next_prio;
114 
115   UniqueTid prev_utid = context_->process_tracker->GetOrCreateThread(prev_tid);
116 
117   // Update the ThreadState table.
118   ThreadStateTracker::GetOrCreate(context_)->PushSchedSwitchEvent(
119       ts, cpu, prev_utid, prev_state_string_id, next_utid);
120 }
121 
TaskStateToStringId(int64_t task_state_int)122 StringId EtwParser::TaskStateToStringId(int64_t task_state_int) {
123   const auto state = static_cast<uint8_t>(task_state_int);
124   // Mapping for the different Etw states with their string description.
125   std::map<uint8_t, base::StringView> etw_states_map = {
126       {0x00, "Initialized"},     // INITIALIZED
127       {0x01, "R"},               // READY
128       {0x02, "Running"},         // RUNNING
129       {0x03, "Stand By"},        // STANDBY
130       {0x04, "T"},               // TERMINATED
131       {0x05, "Waiting"},         // WAITING
132       {0x06, "Transition"},      // TRANSITION
133       {0x07, "Deferred Ready"},  // DEFERRED_READY
134   };
135 
136   return etw_states_map.find(state) != etw_states_map.end()
137              ? context_->storage->InternString(etw_states_map[state])
138              : kNullStringId;
139 }
140 
141 }  // namespace trace_processor
142 }  // namespace perfetto
143