普通文本  |  203行  |  6.75 KB

/*
 * Copyright (C) 2019 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 "src/trace_processor/heap_profile_tracker.h"

#include "src/trace_processor/trace_processor_context.h"

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {

HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
    : context_(context), empty_(context_->storage->InternString({"", 0})) {}

HeapProfileTracker::~HeapProfileTracker() = default;

void HeapProfileTracker::AddString(ProfileIndex pidx,
                                   SourceStringId id,
                                   StringId str) {
  string_map_.emplace(std::make_pair(pidx, id), str);
}

void HeapProfileTracker::AddMapping(ProfileIndex pidx,
                                    SourceMappingId id,
                                    const SourceMapping& mapping) {
  auto opt_name_id = FindString(pidx, mapping.name_id);
  if (!opt_name_id)
    return;
  const StringId name_id = opt_name_id.value();

  auto opt_build_id = FindString(pidx, mapping.build_id);
  if (!opt_build_id)
    return;
  const StringId build_id = opt_build_id.value();

  TraceStorage::HeapProfileMappings::Row row{
      build_id,
      static_cast<int64_t>(mapping.offset),
      static_cast<int64_t>(mapping.start),
      static_cast<int64_t>(mapping.end),
      static_cast<int64_t>(mapping.load_bias),
      name_id};

  int64_t cur_row;
  auto it = mapping_idx_.find(row);
  if (it != mapping_idx_.end()) {
    cur_row = it->second;
  } else {
    cur_row = context_->storage->mutable_heap_profile_mappings()->Insert(row);
    mapping_idx_.emplace(row, cur_row);
  }
  mappings_.emplace(std::make_pair(pidx, id), cur_row);
}

void HeapProfileTracker::AddFrame(ProfileIndex pidx,
                                  SourceFrameId id,
                                  const SourceFrame& frame) {
  auto opt_str_id = FindString(pidx, frame.name_id);
  if (!opt_str_id)
    return;
  const StringId& str_id = opt_str_id.value();

  auto mapping_it = mappings_.find({pidx, frame.mapping_id});
  if (mapping_it == mappings_.end()) {
    context_->storage->IncrementStats(stats::heapprofd_invalid_mapping_id);
    PERFETTO_DFATAL("Invalid mapping.");
    return;
  }
  int64_t mapping_row = mapping_it->second;

  TraceStorage::HeapProfileFrames::Row row{str_id, mapping_row,
                                           static_cast<int64_t>(frame.rel_pc)};

  int64_t cur_row;
  auto it = frame_idx_.find(row);
  if (it != frame_idx_.end()) {
    cur_row = it->second;
  } else {
    cur_row = context_->storage->mutable_heap_profile_frames()->Insert(row);
    frame_idx_.emplace(row, cur_row);
  }
  frames_.emplace(std::make_pair(pidx, id), cur_row);
}

void HeapProfileTracker::AddCallstack(ProfileIndex pidx,
                                      SourceCallstackId id,
                                      const SourceCallstack& frame_ids) {
  int64_t parent_id = 0;
  for (size_t depth = 0; depth < frame_ids.size(); ++depth) {
    std::vector<uint64_t> frame_subset = frame_ids;
    frame_subset.resize(depth + 1);
    auto self_it = callstacks_from_frames_.find({pidx, frame_subset});
    if (self_it != callstacks_from_frames_.end()) {
      parent_id = self_it->second;
      continue;
    }

    uint64_t frame_id = frame_ids[depth];
    auto it = frames_.find({pidx, frame_id});
    if (it == frames_.end()) {
      context_->storage->IncrementStats(stats::heapprofd_invalid_frame_id);
      PERFETTO_DFATAL("Unknown frames.");
      return;
    }
    int64_t frame_row = it->second;

    TraceStorage::HeapProfileCallsites::Row row{static_cast<int64_t>(depth),
                                                parent_id, frame_row};

    int64_t self_id;
    auto callsite_it = callsite_idx_.find(row);
    if (callsite_it != callsite_idx_.end()) {
      self_id = callsite_it->second;
    } else {
      self_id =
          context_->storage->mutable_heap_profile_callsites()->Insert(row);
      callsite_idx_.emplace(row, self_id);
    }
    parent_id = self_id;
  }
  callstacks_.emplace(std::make_pair(pidx, id), parent_id);
}

void HeapProfileTracker::AddAllocation(ProfileIndex pidx,
                                       const SourceAllocation& alloc) {
  auto it = callstacks_.find({pidx, alloc.callstack_id});
  if (it == callstacks_.end()) {
    context_->storage->IncrementStats(stats::heapprofd_invalid_callstack_id);
    PERFETTO_DFATAL("Unknown callstack %" PRIu64 " : %zu", alloc.callstack_id,
                    callstacks_.size());
    return;
  }

  TraceStorage::HeapProfileAllocations::Row alloc_row{
      static_cast<int64_t>(alloc.timestamp), static_cast<int64_t>(alloc.pid),
      static_cast<int64_t>(it->second), static_cast<int64_t>(alloc.alloc_count),
      static_cast<int64_t>(alloc.self_allocated)};

  TraceStorage::HeapProfileAllocations::Row free_row{
      static_cast<int64_t>(alloc.timestamp), static_cast<int64_t>(alloc.pid),
      static_cast<int64_t>(it->second), -static_cast<int64_t>(alloc.free_count),
      -static_cast<int64_t>(alloc.self_freed)};

  context_->storage->mutable_heap_profile_allocations()->Insert(alloc_row);
  context_->storage->mutable_heap_profile_allocations()->Insert(free_row);
}

void HeapProfileTracker::StoreAllocation(ProfileIndex pidx,
                                         SourceAllocation alloc) {
  pending_allocs_.emplace_back(pidx, std::move(alloc));
}

void HeapProfileTracker::ApplyAllAllocations() {
  for (const auto& p : pending_allocs_)
    AddAllocation(p.first, p.second);
}

int64_t HeapProfileTracker::GetDatabaseFrameIdForTesting(
    ProfileIndex pidx,
    SourceFrameId frame_id) {
  auto it = frames_.find({pidx, frame_id});
  if (it == frames_.end()) {
    PERFETTO_DFATAL("Invalid frame.");
    return -1;
  }
  return it->second;
}

base::Optional<StringId> HeapProfileTracker::FindString(ProfileIndex pidx,
                                                        SourceStringId id) {
  base::Optional<StringId> res;
  if (id == 0) {
    res = empty_;
    return res;
  }

  auto it = string_map_.find({pidx, id});
  if (it == string_map_.end()) {
    context_->storage->IncrementStats(stats::heapprofd_invalid_string_id);
    PERFETTO_DFATAL("Invalid string.");
    return res;
  }
  res = it->second;
  return res;
}

}  // namespace trace_processor
}  // namespace perfetto