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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/debug/trace_memory.h ('k') | base/message_loop.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/debug/trace_memory.cc
diff --git a/base/debug/trace_memory.cc b/base/debug/trace_memory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..745fe373c219d1b94af4ee46225b534753b4c5bf
--- /dev/null
+++ b/base/debug/trace_memory.cc
@@ -0,0 +1,163 @@
+// 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.
+
+#include "base/debug/trace_memory.h"
+
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/threading/thread_local.h"
+
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// Maximum number of nested TRACE_MEMORY macros.
+const int kMaxStackSize = 32;
+
+/////////////////////////////////////////////////////////////////////////////
+// Holds a memory dump until the tracing system needs to serialize it.
+class MemoryDumpHolder : public base::debug::ConvertableToTraceFormat {
+ public:
+ // Takes ownership of dump, which must be a JSON string, allocated with
+ // malloc() and NULL terminated.
+ explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
+ virtual ~MemoryDumpHolder() { free(dump_); }
+
+ // base::debug::ConvertableToTraceFormat overrides:
+ virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
+ out->append(dump_);
+ }
+
+ private:
+ char* dump_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Records a stack of TRACE_MEMORY events. One per thread is required.
+struct TraceMemoryStack {
+ TraceMemoryStack() : index_(0) {
+ memset(category_stack_, 0, kMaxStackSize * sizeof(const char*));
+ }
+
+ // Points to the next free entry.
+ int index_;
+ const char* category_stack_[kMaxStackSize];
+};
+
+// A stack of TRACE_MEMORY events, per thread.
+LazyInstance<ThreadLocalPointer<TraceMemoryStack> >::Leaky trace_memory_stack =
+ LAZY_INSTANCE_INITIALIZER;
+
+// Returns a "pseudo-stack" of pointers to trace events.
+// TODO(jamescook): Record both category and name, perhaps in a pair for speed.
+int GetPseudoStack(void** stack_out) {
+ // Is this a fast enough lookup? Should we avoid LazyInstance somehow?
+ TraceMemoryStack* stack = trace_memory_stack.Get().Get();
+ // TODO - figure out how to initialize this on every thread so we don't need
+ // this if().
+ if (!stack)
+ return 0; // could also init the stack here
+ const int count = stack->index_;
+ // memcpy works for zero bytes.
+ memcpy(stack_out, stack->category_stack_, count * sizeof(void*));
+ return count;
+}
+
+// Polls for memory tracing being enabled. If so, dumps a memory profile every
+// few seconds.
+// TODO(jamescook): Don't poll. Get a signal when tracing is enabled.
+void DumpMemoryProfile() {
+ // Don't trace allocations here in the memory tracing system.
+ TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"), TRACE_MEMORY_IGNORE);
+ // Check to see if tracing is enabled for the memory category.
+ bool enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"),
+ &enabled);
+ if (enabled) {
+ // We take ownership of this string.
+ char* dump = base::TraceMemoryDumpAsString();
+ scoped_ptr<MemoryDumpHolder> dump_holder(new MemoryDumpHolder(dump));
+ const int kSnapshotId = 1;
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ "memory",
+ "memory::Heap",
+ kSnapshotId,
+ dump_holder.PassAs<base::debug::ConvertableToTraceFormat>());
+ }
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DumpMemoryProfile),
+ base::TimeDelta::FromSeconds(5));
+}
+
+} // namespace
+
+ScopedTraceMemory::ScopedTraceMemory(const char* category) {
+ // Get our thread's copy of the stack.
+ TraceMemoryStack* stack = trace_memory_stack.Get().Get();
+ if (!stack) {
+ trace_memory_stack.Get().Set(new TraceMemoryStack);
+ stack = trace_memory_stack.Get().Get();
+ }
+ // Bounds checking is for the weak.
+ const int index = stack->index_;
+ stack->category_stack_[index] = category;
+ stack->index_++;
+}
+
+ScopedTraceMemory::~ScopedTraceMemory() {
+ // Get our thread's copy of the stack.
+ TraceMemoryStack* stack = trace_memory_stack.Get().Get();
+ stack->index_--;
+}
+
+// static
+int ScopedTraceMemory::GetStackIndexForTest() {
+ return trace_memory_stack.Get().Get()->index_;
+}
+
+void TraceMemoryStart() {
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
+ DVLOG(1) << "Starting trace memory";
+ // Ensure thread-local-storage is initialized by creating a dummy event.
+ ScopedTraceMemory initialize(TRACE_MEMORY_IGNORE);
+ ::SetPseudoStackGenerator(&GetPseudoStack);
+ ::HeapProfilerStart("/tmp/trace-memory");
+ // This won't do anything initially, but will get the polling timer going.
+ DumpMemoryProfile();
+#endif
+}
+
+void TraceMemoryDump() {
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
+ DVLOG(1) << "Dumping trace memory";
+ ::HeapProfilerDump("dump-for-trace-memory");
+#endif
+}
+
+char* TraceMemoryDumpAsString() {
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
+ DVLOG(1) << "Getting memory dump as string";
+ return ::GetHeapProfile();
+#endif
+ return NULL;
+}
+
+void TraceMemoryStop() {
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && defined(OS_LINUX)
+ DVLOG(1) << "Stopping trace memory";
+ ::HeapProfilerStop();
+#endif
+}
+
+} // namespace base
« 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