summaryrefslogtreecommitdiff
path: root/base/trace_event/heap_profiler_allocation_context.h
blob: 24e2dec73f1f48ff886c0eabe3d27e1604dcd48a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_

#include <stddef.h>
#include <stdint.h>

#include "base/base_export.h"
#include "base/containers/hash_tables.h"

namespace base {
namespace trace_event {

// When heap profiling is enabled, tracing keeps track of the allocation
// context for each allocation intercepted. It is generated by the
// |AllocationContextTracker| which keeps stacks of context in TLS.
// The tracker is initialized lazily.

// The backtrace in the allocation context is a snapshot of the stack. For now,
// this is the pseudo stack where frames are created by trace event macros. In
// the future, we might add the option to use the native call stack. In that
// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
// have different implementations that can be selected by a compile time flag.

// The number of stack frames stored in the backtrace is a trade off between
// memory used for tracing and accuracy. Measurements done on a prototype
// revealed that:
//
// - In 60 percent of the cases, pseudo stack depth <= 7.
// - In 87 percent of the cases, pseudo stack depth <= 9.
// - In 95 percent of the cases, pseudo stack depth <= 11.
//
// See the design doc (https://goo.gl/4s7v7b) for more details.

// Represents (pseudo) stack frame. Used in Backtrace class below.
//
// Conceptually stack frame is identified by its value, and type is used
// mostly to properly format the value. Value is expected to be a valid
// pointer from process' address space.
struct BASE_EXPORT StackFrame {
  enum class Type {
    TRACE_EVENT_NAME,   // const char* string
    THREAD_NAME,        // const char* thread name
    PROGRAM_COUNTER,    // as returned by stack tracing (e.g. by StackTrace)
  };

  static StackFrame FromTraceEventName(const char* name) {
    return {Type::TRACE_EVENT_NAME, name};
  }
  static StackFrame FromThreadName(const char* name) {
    return {Type::THREAD_NAME, name};
  }
  static StackFrame FromProgramCounter(const void* pc) {
    return {Type::PROGRAM_COUNTER, pc};
  }

  Type type;
  const void* value;
};

bool BASE_EXPORT operator < (const StackFrame& lhs, const StackFrame& rhs);
bool BASE_EXPORT operator == (const StackFrame& lhs, const StackFrame& rhs);
bool BASE_EXPORT operator != (const StackFrame& lhs, const StackFrame& rhs);

struct BASE_EXPORT Backtrace {
  Backtrace();

  // If the stack is higher than what can be stored here, the bottom frames
  // (the ones closer to main()) are stored. Depth of 12 is enough for most
  // pseudo traces (see above), but not for native traces, where we need more.
  enum { kMaxFrameCount = 48 };
  StackFrame frames[kMaxFrameCount];
  size_t frame_count;
};

bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
bool BASE_EXPORT operator!=(const Backtrace& lhs, const Backtrace& rhs);

// The |AllocationContext| is context metadata that is kept for every allocation
// when heap profiling is enabled. To simplify memory management for book-
// keeping, this struct has a fixed size.
struct BASE_EXPORT AllocationContext {
  AllocationContext();
  AllocationContext(const Backtrace& backtrace, const char* type_name);

  Backtrace backtrace;

  // Type name of the type stored in the allocated memory. A null pointer
  // indicates "unknown type". Grouping is done by comparing pointers, not by
  // deep string comparison. In a component build, where a type name can have a
  // string literal in several dynamic libraries, this may distort grouping.
  const char* type_name;
};

bool BASE_EXPORT operator==(const AllocationContext& lhs,
                            const AllocationContext& rhs);
bool BASE_EXPORT operator!=(const AllocationContext& lhs,
                            const AllocationContext& rhs);

// Struct to store the size and count of the allocations.
struct AllocationMetrics {
  size_t size;
  size_t count;
};

}  // namespace trace_event
}  // namespace base

namespace BASE_HASH_NAMESPACE {

template <>
struct BASE_EXPORT hash<base::trace_event::StackFrame> {
  size_t operator()(const base::trace_event::StackFrame& frame) const;
};

template <>
struct BASE_EXPORT hash<base::trace_event::Backtrace> {
  size_t operator()(const base::trace_event::Backtrace& backtrace) const;
};

template <>
struct BASE_EXPORT hash<base::trace_event::AllocationContext> {
  size_t operator()(const base::trace_event::AllocationContext& context) const;
};

}  // BASE_HASH_NAMESPACE

#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_