Home | History | Annotate | Download | only in trace_processor
      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 
     34 SliceTracker::SliceTracker(TraceProcessorContext* context)
     35     : context_(context) {}
     36 
     37 SliceTracker::~SliceTracker() = default;
     38 
     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 
     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 
     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 
     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 
     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 
    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 
    139 void SliceTracker::CompleteSlice(UniqueTid utid) {
    140   threads_[utid].pop_back();
    141 }
    142 
    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 
    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