Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: base/debug/trace_memory.cc

Issue 15418002: Record Chrome trace events in tcmalloc heap profiles (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cleanup, run in all renderers Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/debug/trace_memory.h ('k') | base/message_loop.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 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 #include "base/debug/trace_memory.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop.h"
12 #include "base/threading/thread_local.h"
13
14 #if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
15 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
16 #endif
17
18 namespace base {
19
20 namespace {
21
22 // Maximum number of nested TRACE_MEMORY macros.
23 const int kMaxStackSize = 32;
24
25 /////////////////////////////////////////////////////////////////////////////
26 // Holds a memory dump until the tracing system needs to serialize it.
27 class MemoryDumpHolder : public base::debug::ConvertableToTraceFormat {
28 public:
29 // Takes ownership of dump, which must be a JSON string, allocated with
30 // malloc() and NULL terminated.
31 explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
32 virtual ~MemoryDumpHolder() { free(dump_); }
33
34 // base::debug::ConvertableToTraceFormat overrides:
35 virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
36 out->append(dump_);
37 }
38
39 private:
40 char* dump_;
41
42 DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
43 };
44
45 /////////////////////////////////////////////////////////////////////////////
46 // Records a stack of TRACE_MEMORY events. One per thread is required.
47 struct TraceMemoryStack {
48 TraceMemoryStack() : index_(0) {
49 memset(category_stack_, 0, kMaxStackSize * sizeof(const char*));
50 }
51
52 // Points to the next free entry.
53 int index_;
54 const char* category_stack_[kMaxStackSize];
55 };
56
57 // A stack of TRACE_MEMORY events, per thread.
58 LazyInstance<ThreadLocalPointer<TraceMemoryStack> >::Leaky trace_memory_stack =
59 LAZY_INSTANCE_INITIALIZER;
60
61 // Returns a "pseudo-stack" of pointers to trace events.
62 // TODO(jamescook): Record both category and name, perhaps in a pair for speed.
63 int GetPseudoStack(void** stack_out) {
64 // Is this a fast enough lookup? Should we avoid LazyInstance somehow?
65 TraceMemoryStack* stack = trace_memory_stack.Get().Get();
66 // TODO - figure out how to initialize this on every thread so we don't need
67 // this if().
68 if (!stack)
69 return 0; // could also init the stack here
70 const int count = stack->index_;
71 // memcpy works for zero bytes.
72 memcpy(stack_out, stack->category_stack_, count * sizeof(void*));
73 return count;
74 }
75
76 // Polls for memory tracing being enabled. If so, dumps a memory profile every
77 // few seconds.
78 // TODO(jamescook): Don't poll. Get a signal when tracing is enabled.
79 void DumpMemoryProfile() {
80 // Don't trace allocations here in the memory tracing system.
81 TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"), TRACE_MEMORY_IGNORE);
82 // Check to see if tracing is enabled for the memory category.
83 bool enabled;
84 TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"),
85 &enabled);
86 if (enabled) {
87 // We take ownership of this string.
88 char* dump = base::TraceMemoryDumpAsString();
89 scoped_ptr<MemoryDumpHolder> dump_holder(new MemoryDumpHolder(dump));
90 const int kSnapshotId = 1;
91 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
92 "memory",
93 "memory::Heap",
94 kSnapshotId,
95 dump_holder.PassAs<base::debug::ConvertableToTraceFormat>());
96 }
97 base::MessageLoop::current()->PostDelayedTask(
98 FROM_HERE,
99 base::Bind(&DumpMemoryProfile),
100 base::TimeDelta::FromSeconds(5));
101 }
102
103 } // namespace
104
105 ScopedTraceMemory::ScopedTraceMemory(const char* category) {
106 // Get our thread's copy of the stack.
107 TraceMemoryStack* stack = trace_memory_stack.Get().Get();
108 if (!stack) {
109 trace_memory_stack.Get().Set(new TraceMemoryStack);
110 stack = trace_memory_stack.Get().Get();
111 }
112 // Bounds checking is for the weak.
113 const int index = stack->index_;
114 stack->category_stack_[index] = category;
115 stack->index_++;
116 }
117
118 ScopedTraceMemory::~ScopedTraceMemory() {
119 // Get our thread's copy of the stack.
120 TraceMemoryStack* stack = trace_memory_stack.Get().Get();
121 stack->index_--;
122 }
123
124 // static
125 int ScopedTraceMemory::GetStackIndexForTest() {
126 return trace_memory_stack.Get().Get()->index_;
127 }
128
129 void TraceMemoryStart() {
130 #if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
131 DVLOG(1) << "Starting trace memory";
132 // Ensure thread-local-storage is initialized by creating a dummy event.
133 ScopedTraceMemory initialize(TRACE_MEMORY_IGNORE);
134 ::SetPseudoStackGenerator(&GetPseudoStack);
135 ::HeapProfilerStart("/tmp/trace-memory");
136 // This won't do anything initially, but will get the polling timer going.
137 DumpMemoryProfile();
138 #endif
139 }
140
141 void TraceMemoryDump() {
142 #if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
143 DVLOG(1) << "Dumping trace memory";
144 ::HeapProfilerDump("dump-for-trace-memory");
145 #endif
146 }
147
148 char* TraceMemoryDumpAsString() {
149 #if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
150 DVLOG(1) << "Getting memory dump as string";
151 return ::GetHeapProfile();
152 #endif
153 return NULL;
154 }
155
156 void TraceMemoryStop() {
157 #if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
158 DVLOG(1) << "Stopping trace memory";
159 ::HeapProfilerStop();
160 #endif
161 }
162
163 } // namespace base
OLDNEW
« no previous file with comments | « base/debug/trace_memory.h ('k') | base/message_loop.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698