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