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