summaryrefslogtreecommitdiffstats
path: root/base/debug/trace_event_memory.h
blob: df2e66382660e92085f4d9a08027312b17052b27 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright 2013 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_DEBUG_TRACE_EVENT_MEMORY_H_
#define BASE_DEBUG_TRACE_EVENT_MEMORY_H_

#include "base/base_export.h"
#include "base/debug/trace_event_impl.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"

// TODO(jamescook): Windows support for memory tracing.
#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
    (defined(OS_LINUX) || defined(OS_ANDROID))
#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1
#endif

namespace base {

class MessageLoopProxy;

namespace debug {

// Watches for chrome://tracing to be enabled or disabled. When tracing is
// enabled, also enables tcmalloc heap profiling. This class is the preferred
// way to turn trace-base heap memory profiling on and off.
class BASE_EXPORT TraceMemoryController
    : public TraceLog::EnabledStateObserver {
 public:
  typedef int (*StackGeneratorFunction)(int skip_count, void** stack);
  typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback);
  typedef void (*HeapProfilerStopFunction)();
  typedef char* (*GetHeapProfileFunction)();

  // |message_loop_proxy| must be a proxy to the primary thread for the client
  // process, e.g. the UI thread in a browser. The function pointers must be
  // pointers to tcmalloc heap profiling functions; by avoiding direct calls to
  // these functions we avoid a dependency on third_party/tcmalloc from base.
  TraceMemoryController(
      scoped_refptr<MessageLoopProxy> message_loop_proxy,
      HeapProfilerStartFunction heap_profiler_start_function,
      HeapProfilerStopFunction heap_profiler_stop_function,
      GetHeapProfileFunction get_heap_profile_function);
  virtual ~TraceMemoryController();

  // base::debug::TraceLog::EnabledStateChangedObserver overrides:
  virtual void OnTraceLogEnabled() OVERRIDE;
  virtual void OnTraceLogDisabled() OVERRIDE;

  // Starts heap memory profiling.
  void StartProfiling();

  // Captures a heap profile.
  void DumpMemoryProfile();

  // If memory tracing is enabled, dumps a memory profile to the tracing system.
  void StopProfiling();

 private:
  FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController);

  bool IsTimerRunningForTest() const;

  // Ensures the observer starts and stops tracing on the primary thread.
  scoped_refptr<MessageLoopProxy> message_loop_proxy_;

  // Pointers to tcmalloc heap profiling functions. Allows this class to use
  // tcmalloc functions without introducing a dependency from base to tcmalloc.
  HeapProfilerStartFunction heap_profiler_start_function_;
  HeapProfilerStopFunction heap_profiler_stop_function_;
  GetHeapProfileFunction get_heap_profile_function_;

  // Timer to schedule memory profile dumps.
  RepeatingTimer<TraceMemoryController> dump_timer_;

  WeakPtrFactory<TraceMemoryController> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(TraceMemoryController);
};

//////////////////////////////////////////////////////////////////////////////

// A scoped context for memory tracing. Pushes the name onto a stack for
// recording by tcmalloc heap profiling.
class BASE_EXPORT ScopedTraceMemory {
 public:
  struct ScopeData {
    const char* category;
    const char* name;
  };

  // Memory for |category| and |name| must be static, for example, literal
  // strings in a TRACE_EVENT macro.
  ScopedTraceMemory(const char* category, const char* name) {
    if (!enabled_)
      return;
    Initialize(category, name);
  }
  ~ScopedTraceMemory() {
    if (!enabled_)
      return;
    Destroy();
  }

  // Enables the storing of trace names on a per-thread stack.
  static void set_enabled(bool enabled) { enabled_ = enabled; }

  // Testing interface:
  static void InitForTest();
  static void CleanupForTest();
  static int GetStackDepthForTest();
  static ScopeData GetScopeDataForTest(int stack_index);

 private:
  void Initialize(const char* category, const char* name);
  void Destroy();

  static bool enabled_;
  DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
};

//////////////////////////////////////////////////////////////////////////////

// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to
// trace event compatible JSON and appends to |output|. Visible for testing.
BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input,
                                                std::string* output);

// Converts the first |line| of heap profiler data, which contains totals for
// all allocations in a special format, into trace event compatible JSON and
// appends to |output|. Visible for testing.
BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
                                                      std::string* output);

// Converts a single |line| of heap profiler data into trace event compatible
// JSON and appends to |output|. Returns true if the line was valid and has a
// non-zero number of current allocations. Visible for testing.
BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
                                                    std::string* output);

// Returns a pointer to a string given its hexadecimal address in |hex_address|.
// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
// and "error" if |address| could not be parsed. Visible for testing.
BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);

}  // namespace debug
}  // namespace base

// Make local variables with unique names based on the line number. Note that
// the extra level of redirection is needed.
#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line
#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line)
#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__)

// This is the core macro that adds a scope to each TRACE_EVENT location.
// It generates a unique local variable name using the macros above.
#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
#define INTERNAL_TRACE_MEMORY(category, name) \
  base::debug::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
#else
#define INTERNAL_TRACE_MEMORY(category, name)
#endif  // defined(TRACE_MEMORY_SUPPORTED)

// A special trace name that allows us to ignore memory allocations inside
// the memory dump system itself. The allocations are recorded, but the
// visualizer skips them. Must match the value in heap.js.
#define TRACE_MEMORY_IGNORE "trace-memory-ignore"

#endif  // BASE_DEBUG_TRACE_EVENT_MEMORY_H_