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 #ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_ 6 #define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <functional> 12 13 #include "base/base_export.h" 14 15 namespace base { 16 namespace trace_event { 17 18 // When heap profiling is enabled, tracing keeps track of the allocation 19 // context for each allocation intercepted. It is generated by the 20 // |AllocationContextTracker| which keeps stacks of context in TLS. 21 // The tracker is initialized lazily. 22 23 // The backtrace in the allocation context is a snapshot of the stack. For now, 24 // this is the pseudo stack where frames are created by trace event macros. In 25 // the future, we might add the option to use the native call stack. In that 26 // case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might 27 // have different implementations that can be selected by a compile time flag. 28 29 // The number of stack frames stored in the backtrace is a trade off between 30 // memory used for tracing and accuracy. Measurements done on a prototype 31 // revealed that: 32 // 33 // - In 60 percent of the cases, pseudo stack depth <= 7. 34 // - In 87 percent of the cases, pseudo stack depth <= 9. 35 // - In 95 percent of the cases, pseudo stack depth <= 11. 36 // 37 // See the design doc (https://goo.gl/4s7v7b) for more details. 38 39 // Represents (pseudo) stack frame. Used in Backtrace class below. 40 // 41 // Conceptually stack frame is identified by its value, and type is used 42 // mostly to properly format the value. Value is expected to be a valid 43 // pointer from process' address space. 44 struct BASE_EXPORT StackFrame { 45 enum class Type { 46 TRACE_EVENT_NAME, // const char* string 47 THREAD_NAME, // const char* thread name 48 PROGRAM_COUNTER, // as returned by stack tracing (e.g. by StackTrace) 49 }; 50 FromTraceEventNameStackFrame51 static StackFrame FromTraceEventName(const char* name) { 52 return {Type::TRACE_EVENT_NAME, name}; 53 } FromThreadNameStackFrame54 static StackFrame FromThreadName(const char* name) { 55 return {Type::THREAD_NAME, name}; 56 } FromProgramCounterStackFrame57 static StackFrame FromProgramCounter(const void* pc) { 58 return {Type::PROGRAM_COUNTER, pc}; 59 } 60 61 Type type; 62 const void* value; 63 }; 64 65 bool BASE_EXPORT operator < (const StackFrame& lhs, const StackFrame& rhs); 66 bool BASE_EXPORT operator == (const StackFrame& lhs, const StackFrame& rhs); 67 bool BASE_EXPORT operator != (const StackFrame& lhs, const StackFrame& rhs); 68 69 struct BASE_EXPORT Backtrace { 70 Backtrace(); 71 72 // If the stack is higher than what can be stored here, the top frames 73 // (the ones further from main()) are stored. Depth of 12 is enough for most 74 // pseudo traces (see above), but not for native traces, where we need more. 75 enum { kMaxFrameCount = 48 }; 76 StackFrame frames[kMaxFrameCount]; 77 size_t frame_count = 0; 78 }; 79 80 bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs); 81 bool BASE_EXPORT operator!=(const Backtrace& lhs, const Backtrace& rhs); 82 83 // The |AllocationContext| is context metadata that is kept for every allocation 84 // when heap profiling is enabled. To simplify memory management for book- 85 // keeping, this struct has a fixed size. 86 struct BASE_EXPORT AllocationContext { 87 AllocationContext(); 88 AllocationContext(const Backtrace& backtrace, const char* type_name); 89 90 Backtrace backtrace; 91 92 // Type name of the type stored in the allocated memory. A null pointer 93 // indicates "unknown type". Grouping is done by comparing pointers, not by 94 // deep string comparison. In a component build, where a type name can have a 95 // string literal in several dynamic libraries, this may distort grouping. 96 const char* type_name; 97 }; 98 99 bool BASE_EXPORT operator==(const AllocationContext& lhs, 100 const AllocationContext& rhs); 101 bool BASE_EXPORT operator!=(const AllocationContext& lhs, 102 const AllocationContext& rhs); 103 104 // Struct to store the size and count of the allocations. 105 struct AllocationMetrics { 106 size_t size; 107 size_t count; 108 }; 109 110 } // namespace trace_event 111 } // namespace base 112 113 namespace std { 114 115 template <> 116 struct BASE_EXPORT hash<base::trace_event::StackFrame> { 117 size_t operator()(const base::trace_event::StackFrame& frame) const; 118 }; 119 120 template <> 121 struct BASE_EXPORT hash<base::trace_event::Backtrace> { 122 size_t operator()(const base::trace_event::Backtrace& backtrace) const; 123 }; 124 125 template <> 126 struct BASE_EXPORT hash<base::trace_event::AllocationContext> { 127 size_t operator()(const base::trace_event::AllocationContext& context) const; 128 }; 129 130 } // namespace std 131 132 #endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_ 133