Home | History | Annotate | Download | only in trace_event
      1 // Copyright 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
      6 
      7 #include <inttypes.h>
      8 #include <stddef.h>
      9 
     10 #include <string>
     11 #include <utility>
     12 
     13 #include "base/strings/stringprintf.h"
     14 #include "base/trace_event/memory_usage_estimator.h"
     15 #include "base/trace_event/trace_event_argument.h"
     16 #include "base/trace_event/trace_event_memory_overhead.h"
     17 
     18 namespace base {
     19 namespace trace_event {
     20 
     21 StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
     22                                              int parent_frame_index)
     23     : frame(frame), parent_frame_index(parent_frame_index) {}
     24 StackFrameDeduplicator::FrameNode::FrameNode(const FrameNode& other) = default;
     25 StackFrameDeduplicator::FrameNode::~FrameNode() {}
     26 
     27 size_t StackFrameDeduplicator::FrameNode::EstimateMemoryUsage() const {
     28   return base::trace_event::EstimateMemoryUsage(children);
     29 }
     30 
     31 StackFrameDeduplicator::StackFrameDeduplicator() {}
     32 StackFrameDeduplicator::~StackFrameDeduplicator() {}
     33 
     34 int StackFrameDeduplicator::Insert(const StackFrame* beginFrame,
     35                                    const StackFrame* endFrame) {
     36   int frame_index = -1;
     37   std::map<StackFrame, int>* nodes = &roots_;
     38 
     39   // Loop through the frames, early out when a frame is null.
     40   for (const StackFrame* it = beginFrame; it != endFrame; it++) {
     41     StackFrame frame = *it;
     42 
     43     auto node = nodes->find(frame);
     44     if (node == nodes->end()) {
     45       // There is no tree node for this frame yet, create it. The parent node
     46       // is the node associated with the previous frame.
     47       FrameNode frame_node(frame, frame_index);
     48 
     49       // The new frame node will be appended, so its index is the current size
     50       // of the vector.
     51       frame_index = static_cast<int>(frames_.size());
     52 
     53       // Add the node to the trie so it will be found next time.
     54       nodes->insert(std::make_pair(frame, frame_index));
     55 
     56       // Append the node after modifying |nodes|, because the |frames_| vector
     57       // might need to resize, and this invalidates the |nodes| pointer.
     58       frames_.push_back(frame_node);
     59     } else {
     60       // A tree node for this frame exists. Look for the next one.
     61       frame_index = node->second;
     62     }
     63 
     64     nodes = &frames_[frame_index].children;
     65   }
     66 
     67   return frame_index;
     68 }
     69 
     70 void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
     71   out->append("{");  // Begin the |stackFrames| dictionary.
     72 
     73   int i = 0;
     74   auto frame_node = begin();
     75   auto it_end = end();
     76   std::string stringify_buffer;
     77 
     78   while (frame_node != it_end) {
     79     // The |stackFrames| format is a dictionary, not an array, so the
     80     // keys are stringified indices. Write the index manually, then use
     81     // |TracedValue| to format the object. This is to avoid building the
     82     // entire dictionary as a |TracedValue| in memory.
     83     SStringPrintf(&stringify_buffer, "\"%d\":", i);
     84     out->append(stringify_buffer);
     85 
     86     std::unique_ptr<TracedValue> frame_node_value(new TracedValue);
     87     const StackFrame& frame = frame_node->frame;
     88     switch (frame.type) {
     89       case StackFrame::Type::TRACE_EVENT_NAME:
     90         frame_node_value->SetString(
     91             "name", static_cast<const char*>(frame.value));
     92         break;
     93       case StackFrame::Type::THREAD_NAME:
     94         SStringPrintf(&stringify_buffer,
     95                       "[Thread: %s]",
     96                       static_cast<const char*>(frame.value));
     97         frame_node_value->SetString("name", stringify_buffer);
     98         break;
     99       case StackFrame::Type::PROGRAM_COUNTER:
    100         SStringPrintf(&stringify_buffer,
    101                       "pc:%" PRIxPTR,
    102                       reinterpret_cast<uintptr_t>(frame.value));
    103         frame_node_value->SetString("name", stringify_buffer);
    104         break;
    105     }
    106     if (frame_node->parent_frame_index >= 0) {
    107       SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
    108       frame_node_value->SetString("parent", stringify_buffer);
    109     }
    110     frame_node_value->AppendAsTraceFormat(out);
    111 
    112     i++;
    113     frame_node++;
    114 
    115     if (frame_node != it_end)
    116       out->append(",");
    117   }
    118 
    119   out->append("}");  // End the |stackFrames| dictionary.
    120 }
    121 
    122 void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
    123     TraceEventMemoryOverhead* overhead) {
    124   size_t memory_usage =
    125       EstimateMemoryUsage(frames_) + EstimateMemoryUsage(roots_);
    126   overhead->Add("StackFrameDeduplicator",
    127                 sizeof(StackFrameDeduplicator) + memory_usage);
    128 }
    129 
    130 }  // namespace trace_event
    131 }  // namespace base
    132