1 /*
2 * Copyright (C) 2018 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 <limits>
18
19 #include <stdint.h>
20
21 #include "src/trace_processor/process_tracker.h"
22 #include "src/trace_processor/slice_tracker.h"
23 #include "src/trace_processor/trace_processor_context.h"
24 #include "src/trace_processor/trace_storage.h"
25
26 namespace perfetto {
27 namespace trace_processor {
28 namespace {
29 // Slices which have been opened but haven't been closed yet will be marked
30 // with this duration placeholder.
31 constexpr int64_t kPendingDuration = -1;
32 }; // namespace
33
SliceTracker(TraceProcessorContext * context)34 SliceTracker::SliceTracker(TraceProcessorContext* context)
35 : context_(context) {}
36
37 SliceTracker::~SliceTracker() = default;
38
BeginAndroid(int64_t timestamp,uint32_t ftrace_tid,uint32_t atrace_tgid,StringId cat,StringId name)39 void SliceTracker::BeginAndroid(int64_t timestamp,
40 uint32_t ftrace_tid,
41 uint32_t atrace_tgid,
42 StringId cat,
43 StringId name) {
44 UniqueTid utid =
45 context_->process_tracker->UpdateThread(ftrace_tid, atrace_tgid);
46 ftrace_to_atrace_tgid_[ftrace_tid] = atrace_tgid;
47 Begin(timestamp, utid, cat, name);
48 }
49
Begin(int64_t timestamp,UniqueTid utid,StringId cat,StringId name)50 void SliceTracker::Begin(int64_t timestamp,
51 UniqueTid utid,
52 StringId cat,
53 StringId name) {
54 MaybeCloseStack(timestamp, &threads_[utid]);
55 StartSlice(timestamp, kPendingDuration, utid, cat, name);
56 }
57
Scoped(int64_t timestamp,UniqueTid utid,StringId cat,StringId name,int64_t duration)58 void SliceTracker::Scoped(int64_t timestamp,
59 UniqueTid utid,
60 StringId cat,
61 StringId name,
62 int64_t duration) {
63 PERFETTO_DCHECK(duration >= 0);
64 MaybeCloseStack(timestamp, &threads_[utid]);
65 StartSlice(timestamp, duration, utid, cat, name);
66 }
67
StartSlice(int64_t timestamp,int64_t duration,UniqueTid utid,StringId cat,StringId name)68 void SliceTracker::StartSlice(int64_t timestamp,
69 int64_t duration,
70 UniqueTid utid,
71 StringId cat,
72 StringId name) {
73 auto* stack = &threads_[utid];
74 auto* slices = context_->storage->mutable_nestable_slices();
75
76 const uint8_t depth = static_cast<uint8_t>(stack->size());
77 if (depth >= std::numeric_limits<uint8_t>::max()) {
78 PERFETTO_DFATAL("Slices with too large depth found.");
79 return;
80 }
81 int64_t parent_stack_id = depth == 0 ? 0 : slices->stack_ids()[stack->back()];
82 size_t slice_idx =
83 slices->AddSlice(timestamp, duration, utid, RefType::kRefUtid, cat, name,
84 depth, 0, parent_stack_id);
85 stack->emplace_back(slice_idx);
86
87 slices->set_stack_id(slice_idx, GetStackHash(*stack));
88 }
89
EndAndroid(int64_t timestamp,uint32_t ftrace_tid,uint32_t atrace_tgid)90 void SliceTracker::EndAndroid(int64_t timestamp,
91 uint32_t ftrace_tid,
92 uint32_t atrace_tgid) {
93 auto actual_tgid_it = ftrace_to_atrace_tgid_.find(ftrace_tid);
94 if (actual_tgid_it == ftrace_to_atrace_tgid_.end()) {
95 // This is possible if we start tracing after a begin slice.
96 PERFETTO_DLOG("Unknown tgid for ftrace tid %u", ftrace_tid);
97 return;
98 }
99 uint32_t actual_tgid = actual_tgid_it->second;
100 // atrace_tgid can be 0 in older android versions where the end event would
101 // not contain the value.
102 if (atrace_tgid != 0 && atrace_tgid != actual_tgid) {
103 PERFETTO_DLOG("Mismatched atrace pid %u and looked up pid %u", atrace_tgid,
104 actual_tgid);
105 context_->storage->IncrementStats(stats::atrace_tgid_mismatch);
106 }
107 UniqueTid utid =
108 context_->process_tracker->UpdateThread(ftrace_tid, actual_tgid);
109 End(timestamp, utid);
110 }
111
End(int64_t timestamp,UniqueTid utid,StringId cat,StringId name)112 void SliceTracker::End(int64_t timestamp,
113 UniqueTid utid,
114 StringId cat,
115 StringId name) {
116 MaybeCloseStack(timestamp, &threads_[utid]);
117
118 const auto& stack = threads_[utid];
119 if (stack.empty())
120 return;
121
122 auto* slices = context_->storage->mutable_nestable_slices();
123 size_t slice_idx = stack.back();
124
125 // If we are trying to close mismatching slices (e.g., slices that began
126 // before tracing started), bail out.
127 if (cat && slices->cats()[slice_idx] != cat)
128 return;
129 if (name && slices->names()[slice_idx] != name)
130 return;
131
132 PERFETTO_DCHECK(slices->durations()[slice_idx] == kPendingDuration);
133 slices->set_duration(slice_idx, timestamp - slices->start_ns()[slice_idx]);
134
135 CompleteSlice(utid);
136 // TODO(primiano): auto-close B slices left open at the end.
137 }
138
CompleteSlice(UniqueTid utid)139 void SliceTracker::CompleteSlice(UniqueTid utid) {
140 threads_[utid].pop_back();
141 }
142
MaybeCloseStack(int64_t ts,SlicesStack * stack)143 void SliceTracker::MaybeCloseStack(int64_t ts, SlicesStack* stack) {
144 const auto& slices = context_->storage->nestable_slices();
145 bool check_only = false;
146 for (int i = static_cast<int>(stack->size()) - 1; i >= 0; i--) {
147 size_t slice_idx = (*stack)[static_cast<size_t>(i)];
148
149 int64_t start_ts = slices.start_ns()[slice_idx];
150 int64_t dur = slices.durations()[slice_idx];
151 int64_t end_ts = start_ts + dur;
152 if (dur == kPendingDuration) {
153 check_only = true;
154 }
155
156 if (check_only) {
157 PERFETTO_CHECK(ts >= start_ts);
158 PERFETTO_CHECK(dur == kPendingDuration || ts <= end_ts);
159 continue;
160 }
161
162 if (end_ts <= ts) {
163 stack->pop_back();
164 }
165 }
166 }
167
GetStackHash(const SlicesStack & stack)168 int64_t SliceTracker::GetStackHash(const SlicesStack& stack) {
169 PERFETTO_DCHECK(!stack.empty());
170
171 const auto& slices = context_->storage->nestable_slices();
172
173 std::string s;
174 s.reserve(stack.size() * sizeof(uint64_t) * 2);
175 for (size_t i = 0; i < stack.size(); i++) {
176 size_t slice_idx = stack[i];
177 s.append(reinterpret_cast<const char*>(&slices.cats()[slice_idx]),
178 sizeof(slices.cats()[slice_idx]));
179 s.append(reinterpret_cast<const char*>(&slices.names()[slice_idx]),
180 sizeof(slices.names()[slice_idx]));
181 }
182 constexpr uint64_t kMask = uint64_t(-1) >> 1;
183 return static_cast<int64_t>((std::hash<std::string>{}(s)) & kMask);
184 }
185
186 } // namespace trace_processor
187 } // namespace perfetto
188