blob: 40b9e33f1b6942b70b0d89d6a37b0717274fac42 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <limits>
#include <stdint.h>
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/slice_tracker.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_storage.h"
namespace perfetto {
namespace trace_processor {
SliceTracker::SliceTracker(TraceProcessorContext* context)
: context_(context) {}
SliceTracker::~SliceTracker() = default;
void SliceTracker::BeginAndroid(uint64_t timestamp,
uint32_t ftrace_tid,
uint32_t atrace_tid,
StringId cat,
StringId name) {
UniqueTid utid =
context_->process_tracker->UpdateThread(timestamp, atrace_tid, 0);
ftrace_to_atrace_pid_[ftrace_tid] = atrace_tid;
Begin(timestamp, utid, cat, name);
}
void SliceTracker::Begin(uint64_t timestamp,
UniqueTid utid,
StringId cat,
StringId name) {
MaybeCloseStack(timestamp, &threads_[utid]);
StartSlice(timestamp, 0, utid, cat, name);
}
void SliceTracker::Scoped(uint64_t timestamp,
UniqueTid utid,
StringId cat,
StringId name,
uint64_t duration) {
MaybeCloseStack(timestamp, &threads_[utid]);
StartSlice(timestamp, duration, utid, cat, name);
}
void SliceTracker::StartSlice(uint64_t timestamp,
uint64_t duration,
UniqueTid utid,
StringId cat,
StringId name) {
auto* stack = &threads_[utid];
auto* slices = context_->storage->mutable_nestable_slices();
const uint8_t depth = static_cast<uint8_t>(stack->size());
if (depth >= std::numeric_limits<uint8_t>::max()) {
PERFETTO_DFATAL("Slices with too large depth found.");
return;
}
uint64_t parent_stack_id =
depth == 0 ? 0 : slices->stack_ids()[stack->back()];
size_t slice_idx = slices->AddSlice(timestamp, duration, utid, cat, name,
depth, 0, parent_stack_id);
stack->emplace_back(slice_idx);
slices->set_stack_id(slice_idx, GetStackHash(*stack));
}
void SliceTracker::EndAndroid(uint64_t timestamp,
uint32_t ftrace_tid,
uint32_t atrace_tid) {
uint32_t actual_tid = ftrace_to_atrace_pid_[ftrace_tid];
if (atrace_tid != 0 && atrace_tid != actual_tid) {
PERFETTO_DLOG("Mismatched atrace pid %u and looked up pid %u", atrace_tid,
actual_tid);
}
if (actual_tid == 0)
return;
UniqueTid utid =
context_->process_tracker->UpdateThread(timestamp, actual_tid, 0);
End(timestamp, utid);
}
void SliceTracker::End(uint64_t timestamp,
UniqueTid utid,
StringId cat,
StringId name) {
MaybeCloseStack(timestamp, &threads_[utid]);
const auto& stack = threads_[utid];
if (stack.empty())
return;
auto* slices = context_->storage->mutable_nestable_slices();
size_t slice_idx = stack.back();
PERFETTO_CHECK(cat == 0 || slices->cats()[slice_idx] == cat);
PERFETTO_CHECK(name == 0 || slices->names()[slice_idx] == name);
slices->set_duration(slice_idx, timestamp - slices->start_ns()[slice_idx]);
CompleteSlice(utid);
// TODO(primiano): auto-close B slices left open at the end.
}
void SliceTracker::CompleteSlice(UniqueTid utid) {
threads_[utid].pop_back();
}
void SliceTracker::MaybeCloseStack(uint64_t ts, SlicesStack* stack) {
const auto& slices = context_->storage->nestable_slices();
bool check_only = false;
for (int i = static_cast<int>(stack->size()) - 1; i >= 0; i--) {
size_t slice_idx = (*stack)[static_cast<size_t>(i)];
uint64_t start_ts = slices.start_ns()[slice_idx];
uint64_t dur = slices.durations()[slice_idx];
uint64_t end_ts = start_ts + dur;
if (dur == 0) {
check_only = true;
}
if (check_only) {
PERFETTO_DCHECK(ts >= start_ts);
PERFETTO_DCHECK(dur == 0 || ts <= end_ts);
continue;
}
if (end_ts <= ts) {
stack->pop_back();
}
}
}
uint64_t SliceTracker::GetStackHash(const SlicesStack& stack) {
PERFETTO_DCHECK(!stack.empty());
const auto& slices = context_->storage->nestable_slices();
std::string s;
s.reserve(stack.size() * sizeof(uint64_t) * 2);
for (size_t i = 0; i < stack.size(); i++) {
size_t slice_idx = stack[i];
s.append(reinterpret_cast<const char*>(&slices.cats()[slice_idx]),
sizeof(slices.cats()[slice_idx]));
s.append(reinterpret_cast<const char*>(&slices.names()[slice_idx]),
sizeof(slices.names()[slice_idx]));
}
constexpr uint64_t kMask = uint64_t(-1) >> 1;
return (std::hash<std::string>{}(s)) & kMask;
}
} // namespace trace_processor
} // namespace perfetto