• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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/proto/profile_module.h"
18 
19 #include "perfetto/base/logging.h"
20 #include "src/trace_processor/importers/common/clock_tracker.h"
21 #include "src/trace_processor/importers/common/process_tracker.h"
22 #include "src/trace_processor/importers/proto/packet_sequence_state.h"
23 #include "src/trace_processor/importers/proto/profile_packet_utils.h"
24 #include "src/trace_processor/importers/proto/stack_profile_tracker.h"
25 #include "src/trace_processor/storage/trace_storage.h"
26 #include "src/trace_processor/tables/profiler_tables.h"
27 #include "src/trace_processor/timestamped_trace_piece.h"
28 #include "src/trace_processor/trace_sorter.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30 
31 #include "protos/perfetto/common/builtin_clock.pbzero.h"
32 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
33 
34 namespace perfetto {
35 namespace trace_processor {
36 
37 using perfetto::protos::pbzero::TracePacket;
38 using protozero::ConstBytes;
39 
ProfileModule(TraceProcessorContext * context)40 ProfileModule::ProfileModule(TraceProcessorContext* context)
41     : context_(context) {
42   RegisterForField(TracePacket::kStreamingProfilePacketFieldNumber, context);
43 }
44 
45 ProfileModule::~ProfileModule() = default;
46 
TokenizePacket(const TracePacket::Decoder & decoder,TraceBlobView * packet,int64_t,PacketSequenceState * state,uint32_t field_id)47 ModuleResult ProfileModule::TokenizePacket(const TracePacket::Decoder& decoder,
48                                            TraceBlobView* packet,
49                                            int64_t /*packet_timestamp*/,
50                                            PacketSequenceState* state,
51                                            uint32_t field_id) {
52   switch (field_id) {
53     case TracePacket::kStreamingProfilePacketFieldNumber:
54       return TokenizeStreamingProfilePacket(state, packet,
55                                             decoder.streaming_profile_packet());
56   }
57   return ModuleResult::Ignored();
58 }
59 
ParsePacket(const TracePacket::Decoder & decoder,const TimestampedTracePiece & ttp,uint32_t field_id)60 void ProfileModule::ParsePacket(const TracePacket::Decoder& decoder,
61                                 const TimestampedTracePiece& ttp,
62                                 uint32_t field_id) {
63   switch (field_id) {
64     case TracePacket::kStreamingProfilePacketFieldNumber:
65       PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
66       ParseStreamingProfilePacket(ttp.timestamp, ttp.packet_data.sequence_state,
67                                   decoder.streaming_profile_packet());
68       return;
69   }
70 }
71 
TokenizeStreamingProfilePacket(PacketSequenceState * sequence_state,TraceBlobView * packet,ConstBytes streaming_profile_packet)72 ModuleResult ProfileModule::TokenizeStreamingProfilePacket(
73     PacketSequenceState* sequence_state,
74     TraceBlobView* packet,
75     ConstBytes streaming_profile_packet) {
76   protos::pbzero::StreamingProfilePacket::Decoder decoder(
77       streaming_profile_packet.data, streaming_profile_packet.size);
78 
79   // We have to resolve the reference timestamp of a StreamingProfilePacket
80   // during tokenization. If we did this during parsing instead, the
81   // tokenization of a subsequent ThreadDescriptor with a new reference
82   // timestamp would cause us to later calculate timestamps based on the wrong
83   // reference value during parsing. Since StreamingProfilePackets only need to
84   // be sorted correctly with respect to process/thread metadata events (so that
85   // pid/tid are resolved correctly during parsing), we forward the packet as a
86   // whole through the sorter, using the "root" timestamp of the packet, i.e.
87   // the current timestamp of the packet sequence.
88   auto packet_ts =
89       sequence_state->IncrementAndGetTrackEventTimeNs(/*delta_ns=*/0);
90   auto trace_ts = context_->clock_tracker->ToTraceTime(
91       protos::pbzero::BUILTIN_CLOCK_MONOTONIC, packet_ts);
92   if (trace_ts)
93     packet_ts = *trace_ts;
94 
95   // Increment the sequence's timestamp by all deltas.
96   for (auto timestamp_it = decoder.timestamp_delta_us(); timestamp_it;
97        ++timestamp_it) {
98     sequence_state->IncrementAndGetTrackEventTimeNs(*timestamp_it * 1000);
99   }
100 
101   context_->sorter->PushTracePacket(packet_ts, sequence_state,
102                                     std::move(*packet));
103   return ModuleResult::Handled();
104 }
105 
ParseStreamingProfilePacket(int64_t timestamp,PacketSequenceStateGeneration * sequence_state,ConstBytes streaming_profile_packet)106 void ProfileModule::ParseStreamingProfilePacket(
107     int64_t timestamp,
108     PacketSequenceStateGeneration* sequence_state,
109     ConstBytes streaming_profile_packet) {
110   protos::pbzero::StreamingProfilePacket::Decoder packet(
111       streaming_profile_packet.data, streaming_profile_packet.size);
112 
113   ProcessTracker* procs = context_->process_tracker.get();
114   TraceStorage* storage = context_->storage.get();
115   StackProfileTracker& stack_profile_tracker =
116       sequence_state->state()->stack_profile_tracker();
117   ProfilePacketInternLookup intern_lookup(sequence_state);
118 
119   uint32_t pid = static_cast<uint32_t>(sequence_state->state()->pid());
120   uint32_t tid = static_cast<uint32_t>(sequence_state->state()->tid());
121   UniqueTid utid = procs->UpdateThread(tid, pid);
122 
123   // Iterate through timestamps and callstacks simultaneously.
124   auto timestamp_it = packet.timestamp_delta_us();
125   for (auto callstack_it = packet.callstack_iid(); callstack_it;
126        ++callstack_it, ++timestamp_it) {
127     if (!timestamp_it) {
128       context_->storage->IncrementStats(stats::stackprofile_parser_error);
129       PERFETTO_ELOG(
130           "StreamingProfilePacket has less callstack IDs than timestamps!");
131       break;
132     }
133 
134     auto opt_cs_id = stack_profile_tracker.FindOrInsertCallstack(
135         *callstack_it, &intern_lookup);
136     if (!opt_cs_id) {
137       context_->storage->IncrementStats(stats::stackprofile_parser_error);
138       PERFETTO_ELOG("StreamingProfilePacket referencing invalid callstack!");
139       continue;
140     }
141 
142     // Resolve the delta timestamps based on the packet's root timestamp.
143     timestamp += *timestamp_it * 1000;
144 
145     tables::CpuProfileStackSampleTable::Row sample_row{
146         timestamp, *opt_cs_id, utid, packet.process_priority()};
147     storage->mutable_cpu_profile_stack_sample_table()->Insert(sample_row);
148   }
149 }
150 
151 }  // namespace trace_processor
152 }  // namespace perfetto
153