1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/track.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/hash.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_splitter.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_utils.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/uuid.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/internal/track_event_data_source.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/internal/track_event_internal.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Worker // static
37*6dbdd20aSAndroid Build Coastguard Worker uint64_t Track::process_uuid;
38*6dbdd20aSAndroid Build Coastguard Worker
Serialize() const39*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor Track::Serialize() const {
40*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor desc;
41*6dbdd20aSAndroid Build Coastguard Worker desc.set_uuid(uuid);
42*6dbdd20aSAndroid Build Coastguard Worker if (parent_uuid)
43*6dbdd20aSAndroid Build Coastguard Worker desc.set_parent_uuid(parent_uuid);
44*6dbdd20aSAndroid Build Coastguard Worker return desc;
45*6dbdd20aSAndroid Build Coastguard Worker }
46*6dbdd20aSAndroid Build Coastguard Worker
Serialize(protos::pbzero::TrackDescriptor * desc) const47*6dbdd20aSAndroid Build Coastguard Worker void Track::Serialize(protos::pbzero::TrackDescriptor* desc) const {
48*6dbdd20aSAndroid Build Coastguard Worker auto bytes = Serialize().SerializeAsString();
49*6dbdd20aSAndroid Build Coastguard Worker desc->AppendRawProtoBytes(bytes.data(), bytes.size());
50*6dbdd20aSAndroid Build Coastguard Worker }
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker // static
ThreadScoped(const void * ptr,Track parent)53*6dbdd20aSAndroid Build Coastguard Worker Track Track::ThreadScoped(const void* ptr, Track parent) {
54*6dbdd20aSAndroid Build Coastguard Worker if (parent.uuid == 0)
55*6dbdd20aSAndroid Build Coastguard Worker return Track::FromPointer(ptr, ThreadTrack::Current());
56*6dbdd20aSAndroid Build Coastguard Worker return Track::FromPointer(ptr, parent);
57*6dbdd20aSAndroid Build Coastguard Worker }
58*6dbdd20aSAndroid Build Coastguard Worker
Serialize() const59*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor ProcessTrack::Serialize() const {
60*6dbdd20aSAndroid Build Coastguard Worker auto desc = Track::Serialize();
61*6dbdd20aSAndroid Build Coastguard Worker auto pd = desc.mutable_process();
62*6dbdd20aSAndroid Build Coastguard Worker pd->set_pid(static_cast<int32_t>(pid));
63*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
64*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
65*6dbdd20aSAndroid Build Coastguard Worker std::string cmdline;
66*6dbdd20aSAndroid Build Coastguard Worker if (base::ReadFile("/proc/self/cmdline", &cmdline)) {
67*6dbdd20aSAndroid Build Coastguard Worker // Since cmdline is a zero-terminated list of arguments, this ends up
68*6dbdd20aSAndroid Build Coastguard Worker // writing just the first element, i.e., the process name, into the process
69*6dbdd20aSAndroid Build Coastguard Worker // name field.
70*6dbdd20aSAndroid Build Coastguard Worker pd->set_process_name(cmdline.c_str());
71*6dbdd20aSAndroid Build Coastguard Worker base::StringSplitter splitter(std::move(cmdline), '\0');
72*6dbdd20aSAndroid Build Coastguard Worker while (splitter.Next()) {
73*6dbdd20aSAndroid Build Coastguard Worker pd->add_cmdline(
74*6dbdd20aSAndroid Build Coastguard Worker std::string(splitter.cur_token(), splitter.cur_token_size()));
75*6dbdd20aSAndroid Build Coastguard Worker }
76*6dbdd20aSAndroid Build Coastguard Worker }
77*6dbdd20aSAndroid Build Coastguard Worker // TODO(skyostil): Record command line on Windows and Mac.
78*6dbdd20aSAndroid Build Coastguard Worker #endif
79*6dbdd20aSAndroid Build Coastguard Worker return desc;
80*6dbdd20aSAndroid Build Coastguard Worker }
81*6dbdd20aSAndroid Build Coastguard Worker
Serialize(protos::pbzero::TrackDescriptor * desc) const82*6dbdd20aSAndroid Build Coastguard Worker void ProcessTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
83*6dbdd20aSAndroid Build Coastguard Worker auto bytes = Serialize().SerializeAsString();
84*6dbdd20aSAndroid Build Coastguard Worker desc->AppendRawProtoBytes(bytes.data(), bytes.size());
85*6dbdd20aSAndroid Build Coastguard Worker }
86*6dbdd20aSAndroid Build Coastguard Worker
Serialize() const87*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor ThreadTrack::Serialize() const {
88*6dbdd20aSAndroid Build Coastguard Worker auto desc = Track::Serialize();
89*6dbdd20aSAndroid Build Coastguard Worker auto td = desc.mutable_thread();
90*6dbdd20aSAndroid Build Coastguard Worker td->set_pid(static_cast<int32_t>(pid));
91*6dbdd20aSAndroid Build Coastguard Worker td->set_tid(static_cast<int32_t>(tid));
92*6dbdd20aSAndroid Build Coastguard Worker if (disallow_merging_with_system_tracks) {
93*6dbdd20aSAndroid Build Coastguard Worker desc.set_disallow_merging_with_system_tracks(true);
94*6dbdd20aSAndroid Build Coastguard Worker }
95*6dbdd20aSAndroid Build Coastguard Worker std::string thread_name;
96*6dbdd20aSAndroid Build Coastguard Worker if (base::GetThreadName(thread_name))
97*6dbdd20aSAndroid Build Coastguard Worker td->set_thread_name(thread_name);
98*6dbdd20aSAndroid Build Coastguard Worker return desc;
99*6dbdd20aSAndroid Build Coastguard Worker }
100*6dbdd20aSAndroid Build Coastguard Worker
101*6dbdd20aSAndroid Build Coastguard Worker // static
Current()102*6dbdd20aSAndroid Build Coastguard Worker ThreadTrack ThreadTrack::Current() {
103*6dbdd20aSAndroid Build Coastguard Worker return ThreadTrack(
104*6dbdd20aSAndroid Build Coastguard Worker internal::TracingMuxer::Get()->GetCurrentThreadId(),
105*6dbdd20aSAndroid Build Coastguard Worker internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
106*6dbdd20aSAndroid Build Coastguard Worker }
107*6dbdd20aSAndroid Build Coastguard Worker
108*6dbdd20aSAndroid Build Coastguard Worker // static
ForThread(base::PlatformThreadId tid_)109*6dbdd20aSAndroid Build Coastguard Worker ThreadTrack ThreadTrack::ForThread(base::PlatformThreadId tid_) {
110*6dbdd20aSAndroid Build Coastguard Worker return ThreadTrack(
111*6dbdd20aSAndroid Build Coastguard Worker tid_, internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
112*6dbdd20aSAndroid Build Coastguard Worker }
113*6dbdd20aSAndroid Build Coastguard Worker
Serialize(protos::pbzero::TrackDescriptor * desc) const114*6dbdd20aSAndroid Build Coastguard Worker void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
115*6dbdd20aSAndroid Build Coastguard Worker auto bytes = Serialize().SerializeAsString();
116*6dbdd20aSAndroid Build Coastguard Worker desc->AppendRawProtoBytes(bytes.data(), bytes.size());
117*6dbdd20aSAndroid Build Coastguard Worker }
118*6dbdd20aSAndroid Build Coastguard Worker
Serialize() const119*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor NamedTrack::Serialize() const {
120*6dbdd20aSAndroid Build Coastguard Worker auto desc = Track::Serialize();
121*6dbdd20aSAndroid Build Coastguard Worker if (static_name_) {
122*6dbdd20aSAndroid Build Coastguard Worker desc.set_static_name(static_name_.value);
123*6dbdd20aSAndroid Build Coastguard Worker } else {
124*6dbdd20aSAndroid Build Coastguard Worker desc.set_name(dynamic_name_.value);
125*6dbdd20aSAndroid Build Coastguard Worker }
126*6dbdd20aSAndroid Build Coastguard Worker return desc;
127*6dbdd20aSAndroid Build Coastguard Worker }
128*6dbdd20aSAndroid Build Coastguard Worker
Serialize(protos::pbzero::TrackDescriptor * desc) const129*6dbdd20aSAndroid Build Coastguard Worker void NamedTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
130*6dbdd20aSAndroid Build Coastguard Worker auto bytes = Serialize().SerializeAsString();
131*6dbdd20aSAndroid Build Coastguard Worker desc->AppendRawProtoBytes(bytes.data(), bytes.size());
132*6dbdd20aSAndroid Build Coastguard Worker }
133*6dbdd20aSAndroid Build Coastguard Worker
Serialize() const134*6dbdd20aSAndroid Build Coastguard Worker protos::gen::TrackDescriptor CounterTrack::Serialize() const {
135*6dbdd20aSAndroid Build Coastguard Worker auto desc = Track::Serialize();
136*6dbdd20aSAndroid Build Coastguard Worker auto* counter = desc.mutable_counter();
137*6dbdd20aSAndroid Build Coastguard Worker if (static_name_) {
138*6dbdd20aSAndroid Build Coastguard Worker desc.set_static_name(static_name_.value);
139*6dbdd20aSAndroid Build Coastguard Worker } else {
140*6dbdd20aSAndroid Build Coastguard Worker desc.set_name(dynamic_name_.value);
141*6dbdd20aSAndroid Build Coastguard Worker }
142*6dbdd20aSAndroid Build Coastguard Worker
143*6dbdd20aSAndroid Build Coastguard Worker if (category_)
144*6dbdd20aSAndroid Build Coastguard Worker counter->add_categories(category_);
145*6dbdd20aSAndroid Build Coastguard Worker if (unit_ != perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED)
146*6dbdd20aSAndroid Build Coastguard Worker counter->set_unit(static_cast<protos::gen::CounterDescriptor_Unit>(unit_));
147*6dbdd20aSAndroid Build Coastguard Worker {
148*6dbdd20aSAndroid Build Coastguard Worker // if |type| is set, we don't want to emit |unit_name|. Trace processor
149*6dbdd20aSAndroid Build Coastguard Worker // infers the track name from the type in that case.
150*6dbdd20aSAndroid Build Coastguard Worker if (type_ !=
151*6dbdd20aSAndroid Build Coastguard Worker perfetto::protos::gen::CounterDescriptor::COUNTER_UNSPECIFIED) {
152*6dbdd20aSAndroid Build Coastguard Worker counter->set_type(type_);
153*6dbdd20aSAndroid Build Coastguard Worker } else if (unit_name_) {
154*6dbdd20aSAndroid Build Coastguard Worker counter->set_unit_name(unit_name_);
155*6dbdd20aSAndroid Build Coastguard Worker }
156*6dbdd20aSAndroid Build Coastguard Worker }
157*6dbdd20aSAndroid Build Coastguard Worker if (unit_multiplier_ != 1)
158*6dbdd20aSAndroid Build Coastguard Worker counter->set_unit_multiplier(unit_multiplier_);
159*6dbdd20aSAndroid Build Coastguard Worker if (is_incremental_)
160*6dbdd20aSAndroid Build Coastguard Worker counter->set_is_incremental(is_incremental_);
161*6dbdd20aSAndroid Build Coastguard Worker return desc;
162*6dbdd20aSAndroid Build Coastguard Worker }
163*6dbdd20aSAndroid Build Coastguard Worker
Serialize(protos::pbzero::TrackDescriptor * desc) const164*6dbdd20aSAndroid Build Coastguard Worker void CounterTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
165*6dbdd20aSAndroid Build Coastguard Worker auto bytes = Serialize().SerializeAsString();
166*6dbdd20aSAndroid Build Coastguard Worker desc->AppendRawProtoBytes(bytes.data(), bytes.size());
167*6dbdd20aSAndroid Build Coastguard Worker }
168*6dbdd20aSAndroid Build Coastguard Worker
169*6dbdd20aSAndroid Build Coastguard Worker namespace internal {
170*6dbdd20aSAndroid Build Coastguard Worker namespace {
171*6dbdd20aSAndroid Build Coastguard Worker
GetProcessStartTime()172*6dbdd20aSAndroid Build Coastguard Worker uint64_t GetProcessStartTime() {
173*6dbdd20aSAndroid Build Coastguard Worker #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
174*6dbdd20aSAndroid Build Coastguard Worker std::string stat;
175*6dbdd20aSAndroid Build Coastguard Worker if (!base::ReadFile("/proc/self/stat", &stat))
176*6dbdd20aSAndroid Build Coastguard Worker return 0u;
177*6dbdd20aSAndroid Build Coastguard Worker // The stat file is a single line split into space-separated fields as "pid
178*6dbdd20aSAndroid Build Coastguard Worker // (comm) state ppid ...". However because the command name can contain any
179*6dbdd20aSAndroid Build Coastguard Worker // characters (including parentheses and spaces), we need to skip past it
180*6dbdd20aSAndroid Build Coastguard Worker // before parsing the rest of the fields. To do that, we look for the last
181*6dbdd20aSAndroid Build Coastguard Worker // instance of ") " (parentheses followed by space) and parse forward from
182*6dbdd20aSAndroid Build Coastguard Worker // that point.
183*6dbdd20aSAndroid Build Coastguard Worker size_t comm_end = stat.rfind(") ");
184*6dbdd20aSAndroid Build Coastguard Worker if (comm_end == std::string::npos)
185*6dbdd20aSAndroid Build Coastguard Worker return 0u;
186*6dbdd20aSAndroid Build Coastguard Worker stat = stat.substr(comm_end + strlen(") "));
187*6dbdd20aSAndroid Build Coastguard Worker base::StringSplitter splitter(stat, ' ');
188*6dbdd20aSAndroid Build Coastguard Worker for (size_t skip = 0; skip < 20; skip++) {
189*6dbdd20aSAndroid Build Coastguard Worker if (!splitter.Next())
190*6dbdd20aSAndroid Build Coastguard Worker return 0u;
191*6dbdd20aSAndroid Build Coastguard Worker }
192*6dbdd20aSAndroid Build Coastguard Worker return base::CStringToUInt64(splitter.cur_token()).value_or(0u);
193*6dbdd20aSAndroid Build Coastguard Worker #else
194*6dbdd20aSAndroid Build Coastguard Worker return 0;
195*6dbdd20aSAndroid Build Coastguard Worker #endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
196*6dbdd20aSAndroid Build Coastguard Worker }
197*6dbdd20aSAndroid Build Coastguard Worker
198*6dbdd20aSAndroid Build Coastguard Worker } // namespace
199*6dbdd20aSAndroid Build Coastguard Worker
200*6dbdd20aSAndroid Build Coastguard Worker // static
201*6dbdd20aSAndroid Build Coastguard Worker TrackRegistry* TrackRegistry::instance_;
202*6dbdd20aSAndroid Build Coastguard Worker
203*6dbdd20aSAndroid Build Coastguard Worker TrackRegistry::TrackRegistry() = default;
204*6dbdd20aSAndroid Build Coastguard Worker TrackRegistry::~TrackRegistry() = default;
205*6dbdd20aSAndroid Build Coastguard Worker
206*6dbdd20aSAndroid Build Coastguard Worker // static
InitializeInstance()207*6dbdd20aSAndroid Build Coastguard Worker void TrackRegistry::InitializeInstance() {
208*6dbdd20aSAndroid Build Coastguard Worker if (instance_)
209*6dbdd20aSAndroid Build Coastguard Worker return;
210*6dbdd20aSAndroid Build Coastguard Worker instance_ = new TrackRegistry();
211*6dbdd20aSAndroid Build Coastguard Worker Track::process_uuid = ComputeProcessUuid();
212*6dbdd20aSAndroid Build Coastguard Worker }
213*6dbdd20aSAndroid Build Coastguard Worker
214*6dbdd20aSAndroid Build Coastguard Worker // static
ComputeProcessUuid()215*6dbdd20aSAndroid Build Coastguard Worker uint64_t TrackRegistry::ComputeProcessUuid() {
216*6dbdd20aSAndroid Build Coastguard Worker // Use the process start time + pid as the unique identifier for this process.
217*6dbdd20aSAndroid Build Coastguard Worker // This ensures that if there are two independent copies of the Perfetto SDK
218*6dbdd20aSAndroid Build Coastguard Worker // in the same process (e.g., one in the app and another in a system
219*6dbdd20aSAndroid Build Coastguard Worker // framework), events emitted by each will be consistently interleaved on
220*6dbdd20aSAndroid Build Coastguard Worker // common thread and process tracks.
221*6dbdd20aSAndroid Build Coastguard Worker if (uint64_t start_time = GetProcessStartTime()) {
222*6dbdd20aSAndroid Build Coastguard Worker base::Hasher hash;
223*6dbdd20aSAndroid Build Coastguard Worker hash.Update(start_time);
224*6dbdd20aSAndroid Build Coastguard Worker hash.Update(Platform::GetCurrentProcessId());
225*6dbdd20aSAndroid Build Coastguard Worker return hash.digest();
226*6dbdd20aSAndroid Build Coastguard Worker }
227*6dbdd20aSAndroid Build Coastguard Worker // Fall back to a randomly generated identifier.
228*6dbdd20aSAndroid Build Coastguard Worker static uint64_t random_once = static_cast<uint64_t>(base::Uuidv4().lsb());
229*6dbdd20aSAndroid Build Coastguard Worker return random_once;
230*6dbdd20aSAndroid Build Coastguard Worker }
231*6dbdd20aSAndroid Build Coastguard Worker
ResetForTesting()232*6dbdd20aSAndroid Build Coastguard Worker void TrackRegistry::ResetForTesting() {
233*6dbdd20aSAndroid Build Coastguard Worker instance_->tracks_.clear();
234*6dbdd20aSAndroid Build Coastguard Worker }
235*6dbdd20aSAndroid Build Coastguard Worker
UpdateTrack(Track track,const std::string & serialized_desc)236*6dbdd20aSAndroid Build Coastguard Worker void TrackRegistry::UpdateTrack(Track track,
237*6dbdd20aSAndroid Build Coastguard Worker const std::string& serialized_desc) {
238*6dbdd20aSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mutex_);
239*6dbdd20aSAndroid Build Coastguard Worker tracks_[track.uuid] = {serialized_desc, track.parent_uuid};
240*6dbdd20aSAndroid Build Coastguard Worker }
241*6dbdd20aSAndroid Build Coastguard Worker
EraseTrack(Track track)242*6dbdd20aSAndroid Build Coastguard Worker void TrackRegistry::EraseTrack(Track track) {
243*6dbdd20aSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mutex_);
244*6dbdd20aSAndroid Build Coastguard Worker tracks_.erase(track.uuid);
245*6dbdd20aSAndroid Build Coastguard Worker }
246*6dbdd20aSAndroid Build Coastguard Worker
247*6dbdd20aSAndroid Build Coastguard Worker // static
WriteTrackDescriptor(const SerializedTrackDescriptor & desc,protozero::MessageHandle<protos::pbzero::TracePacket> packet)248*6dbdd20aSAndroid Build Coastguard Worker void TrackRegistry::WriteTrackDescriptor(
249*6dbdd20aSAndroid Build Coastguard Worker const SerializedTrackDescriptor& desc,
250*6dbdd20aSAndroid Build Coastguard Worker protozero::MessageHandle<protos::pbzero::TracePacket> packet) {
251*6dbdd20aSAndroid Build Coastguard Worker packet->AppendString(
252*6dbdd20aSAndroid Build Coastguard Worker perfetto::protos::pbzero::TracePacket::kTrackDescriptorFieldNumber, desc);
253*6dbdd20aSAndroid Build Coastguard Worker }
254*6dbdd20aSAndroid Build Coastguard Worker
255*6dbdd20aSAndroid Build Coastguard Worker } // namespace internal
256*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
257