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