| Index: base/debug/trace_event_memory.cc
 | 
| diff --git a/base/debug/trace_event_memory.cc b/base/debug/trace_event_memory.cc
 | 
| deleted file mode 100644
 | 
| index 28318654750950df5f179aec0f7fa25c26165f7e..0000000000000000000000000000000000000000
 | 
| --- a/base/debug/trace_event_memory.cc
 | 
| +++ /dev/null
 | 
| @@ -1,440 +0,0 @@
 | 
| -// 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_event_memory.h"
 | 
| -
 | 
| -#include "base/debug/leak_annotations.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/message_loop.h"
 | 
| -#include "base/strings/string_number_conversions.h"
 | 
| -#include "base/strings/string_util.h"
 | 
| -#include "base/threading/thread_local_storage.h"
 | 
| -
 | 
| -namespace base {
 | 
| -namespace debug {
 | 
| -
 | 
| -namespace {
 | 
| -
 | 
| -// Maximum number of nested TRACE_EVENT scopes to record. Must be less than
 | 
| -// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two
 | 
| -// entries on the pseudo-stack per scope.
 | 
| -const size_t kMaxScopeDepth = 16;
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -// 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) {}
 | 
| -
 | 
| -  // base::debug::ConvertableToTraceFormat overrides:
 | 
| -  void AppendAsTraceFormat(std::string* out) const override {
 | 
| -    AppendHeapProfileAsTraceFormat(dump_, out);
 | 
| -  }
 | 
| -
 | 
| - private:
 | 
| -  ~MemoryDumpHolder() override { free(dump_); }
 | 
| -
 | 
| -  char* dump_;
 | 
| -
 | 
| -  DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
 | 
| -};
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -// Records a stack of TRACE_MEMORY events. One per thread is required.
 | 
| -struct TraceMemoryStack {
 | 
| -  TraceMemoryStack() : scope_depth(0) {
 | 
| -    memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0]));
 | 
| -  }
 | 
| -
 | 
| -  // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater
 | 
| -  // than kMaxScopeDepth so we can match scope pushes and pops even if we don't
 | 
| -  // have enough space to store the EventData.
 | 
| -  size_t scope_depth;
 | 
| -
 | 
| -  // Stack of categories and names.
 | 
| -  ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth];
 | 
| -};
 | 
| -
 | 
| -// Pointer to a TraceMemoryStack per thread.
 | 
| -base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER;
 | 
| -
 | 
| -// Clean up memory pointed to by our thread-local storage.
 | 
| -void DeleteStackOnThreadCleanup(void* value) {
 | 
| -  TraceMemoryStack* stack = static_cast<TraceMemoryStack*>(value);
 | 
| -  delete stack;
 | 
| -}
 | 
| -
 | 
| -// Initializes the thread-local TraceMemoryStack pointer. Returns true on
 | 
| -// success or if it is already initialized.
 | 
| -bool InitThreadLocalStorage() {
 | 
| -  if (tls_trace_memory_stack.initialized())
 | 
| -    return true;
 | 
| -  // Initialize the thread-local storage key, returning true on success.
 | 
| -  return tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
 | 
| -}
 | 
| -
 | 
| -// Clean up thread-local-storage in the main thread.
 | 
| -void CleanupThreadLocalStorage() {
 | 
| -  if (!tls_trace_memory_stack.initialized())
 | 
| -    return;
 | 
| -  TraceMemoryStack* stack =
 | 
| -      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
 | 
| -  delete stack;
 | 
| -  tls_trace_memory_stack.Set(NULL);
 | 
| -  // Intentionally do not release the thread-local-storage key here, that is,
 | 
| -  // do not call tls_trace_memory_stack.Free(). Other threads have lazily
 | 
| -  // created pointers in thread-local-storage via GetTraceMemoryStack() below.
 | 
| -  // Those threads need to run the DeleteStack() destructor function when they
 | 
| -  // exit. If we release the key the destructor will not be called and those
 | 
| -  // threads will not clean up their memory.
 | 
| -}
 | 
| -
 | 
| -// Returns the thread-local trace memory stack for the current thread, creating
 | 
| -// one if needed. Returns NULL if the thread-local storage key isn't
 | 
| -// initialized, which indicates that heap profiling isn't running.
 | 
| -TraceMemoryStack* GetTraceMemoryStack() {
 | 
| -  TraceMemoryStack* stack =
 | 
| -      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
 | 
| -  // Lazily initialize TraceMemoryStack objects for new threads.
 | 
| -  if (!stack) {
 | 
| -    stack = new TraceMemoryStack;
 | 
| -    tls_trace_memory_stack.Set(stack);
 | 
| -  }
 | 
| -  return stack;
 | 
| -}
 | 
| -
 | 
| -// Returns a "pseudo-stack" of pointers to trace event categories and names.
 | 
| -// Because tcmalloc stores one pointer per stack frame this converts N nested
 | 
| -// trace events into N * 2 pseudo-stack entries. Thus this macro invocation:
 | 
| -//    TRACE_EVENT0("category1", "name1");
 | 
| -//    TRACE_EVENT0("category2", "name2");
 | 
| -// becomes this pseudo-stack:
 | 
| -//    stack_out[0] = "category1"
 | 
| -//    stack_out[1] = "name1"
 | 
| -//    stack_out[2] = "category2"
 | 
| -//    stack_out[3] = "name2"
 | 
| -// Returns int instead of size_t to match the signature required by tcmalloc.
 | 
| -int GetPseudoStack(int skip_count_ignored, void** stack_out) {
 | 
| -  // If the tracing system isn't fully initialized, just skip this allocation.
 | 
| -  // Attempting to initialize will allocate memory, causing this function to
 | 
| -  // be called recursively from inside the allocator.
 | 
| -  if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get())
 | 
| -    return 0;
 | 
| -  TraceMemoryStack* stack =
 | 
| -      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
 | 
| -  // Copy at most kMaxScopeDepth scope entries.
 | 
| -  const size_t count = std::min(stack->scope_depth, kMaxScopeDepth);
 | 
| -  // Notes that memcpy() works for zero bytes.
 | 
| -  memcpy(stack_out,
 | 
| -         stack->scope_data,
 | 
| -         count * sizeof(stack->scope_data[0]));
 | 
| -  // Each item in the trace event stack contains both name and category so tell
 | 
| -  // tcmalloc that we have returned |count| * 2 stack frames.
 | 
| -  return static_cast<int>(count * 2);
 | 
| -}
 | 
| -
 | 
| -}  // namespace
 | 
| -
 | 
| -//////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -TraceMemoryController::TraceMemoryController(
 | 
| -    scoped_refptr<MessageLoopProxy> message_loop_proxy,
 | 
| -    HeapProfilerStartFunction heap_profiler_start_function,
 | 
| -    HeapProfilerStopFunction heap_profiler_stop_function,
 | 
| -    GetHeapProfileFunction get_heap_profile_function)
 | 
| -    : message_loop_proxy_(message_loop_proxy),
 | 
| -      heap_profiler_start_function_(heap_profiler_start_function),
 | 
| -      heap_profiler_stop_function_(heap_profiler_stop_function),
 | 
| -      get_heap_profile_function_(get_heap_profile_function),
 | 
| -      weak_factory_(this) {
 | 
| -  // Force the "memory" category to show up in the trace viewer.
 | 
| -  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init");
 | 
| -  // Watch for the tracing system being enabled.
 | 
| -  TraceLog::GetInstance()->AddEnabledStateObserver(this);
 | 
| -}
 | 
| -
 | 
| -TraceMemoryController::~TraceMemoryController() {
 | 
| -  if (dump_timer_.IsRunning())
 | 
| -    StopProfiling();
 | 
| -  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
 | 
| -}
 | 
| -
 | 
| -  // base::debug::TraceLog::EnabledStateChangedObserver overrides:
 | 
| -void TraceMemoryController::OnTraceLogEnabled() {
 | 
| -  // 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)
 | 
| -    return;
 | 
| -  DVLOG(1) << "OnTraceLogEnabled";
 | 
| -  message_loop_proxy_->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&TraceMemoryController::StartProfiling,
 | 
| -                 weak_factory_.GetWeakPtr()));
 | 
| -}
 | 
| -
 | 
| -void TraceMemoryController::OnTraceLogDisabled() {
 | 
| -  // The memory category is always disabled before OnTraceLogDisabled() is
 | 
| -  // called, so we cannot tell if it was enabled before. Always try to turn
 | 
| -  // off profiling.
 | 
| -  DVLOG(1) << "OnTraceLogDisabled";
 | 
| -  message_loop_proxy_->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&TraceMemoryController::StopProfiling,
 | 
| -                 weak_factory_.GetWeakPtr()));
 | 
| -}
 | 
| -
 | 
| -void TraceMemoryController::StartProfiling() {
 | 
| -  // Watch for the tracing framework sending enabling more than once.
 | 
| -  if (dump_timer_.IsRunning())
 | 
| -    return;
 | 
| -  DVLOG(1) << "Starting trace memory";
 | 
| -  if (!InitThreadLocalStorage())
 | 
| -    return;
 | 
| -  ScopedTraceMemory::set_enabled(true);
 | 
| -  // Call ::HeapProfilerWithPseudoStackStart().
 | 
| -  heap_profiler_start_function_(&GetPseudoStack);
 | 
| -  const int kDumpIntervalSeconds = 5;
 | 
| -  dump_timer_.Start(FROM_HERE,
 | 
| -                    TimeDelta::FromSeconds(kDumpIntervalSeconds),
 | 
| -                    base::Bind(&TraceMemoryController::DumpMemoryProfile,
 | 
| -                               weak_factory_.GetWeakPtr()));
 | 
| -}
 | 
| -
 | 
| -void TraceMemoryController::DumpMemoryProfile() {
 | 
| -  // Don't trace allocations here in the memory tracing system.
 | 
| -  INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"),
 | 
| -                        TRACE_MEMORY_IGNORE);
 | 
| -
 | 
| -  DVLOG(1) << "DumpMemoryProfile";
 | 
| -  // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in
 | 
| -  // tcmalloc for details.
 | 
| -  char* dump = get_heap_profile_function_();
 | 
| -  const int kSnapshotId = 1;
 | 
| -  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
 | 
| -      TRACE_DISABLED_BY_DEFAULT("memory"),
 | 
| -      "memory::Heap",
 | 
| -      kSnapshotId,
 | 
| -      scoped_refptr<ConvertableToTraceFormat>(new MemoryDumpHolder(dump)));
 | 
| -}
 | 
| -
 | 
| -void TraceMemoryController::StopProfiling() {
 | 
| -  // Watch for the tracing framework sending disabled more than once.
 | 
| -  if (!dump_timer_.IsRunning())
 | 
| -    return;
 | 
| -  DVLOG(1) << "Stopping trace memory";
 | 
| -  dump_timer_.Stop();
 | 
| -  ScopedTraceMemory::set_enabled(false);
 | 
| -  CleanupThreadLocalStorage();
 | 
| -  // Call ::HeapProfilerStop().
 | 
| -  heap_profiler_stop_function_();
 | 
| -}
 | 
| -
 | 
| -bool TraceMemoryController::IsTimerRunningForTest() const {
 | 
| -  return dump_timer_.IsRunning();
 | 
| -}
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -// static
 | 
| -bool ScopedTraceMemory::enabled_ = false;
 | 
| -
 | 
| -void ScopedTraceMemory::Initialize(const char* category, const char* name) {
 | 
| -  DCHECK(enabled_);
 | 
| -  // Get our thread's copy of the stack.
 | 
| -  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
 | 
| -  const size_t index = trace_memory_stack->scope_depth;
 | 
| -  // Don't record data for deeply nested scopes, but continue to increment
 | 
| -  // |stack_depth| so we can match pushes and pops.
 | 
| -  if (index < kMaxScopeDepth) {
 | 
| -    ScopeData& event = trace_memory_stack->scope_data[index];
 | 
| -    event.category = category;
 | 
| -    event.name = name;
 | 
| -  }
 | 
| -  trace_memory_stack->scope_depth++;
 | 
| -}
 | 
| -
 | 
| -void ScopedTraceMemory::Destroy() {
 | 
| -  DCHECK(enabled_);
 | 
| -  // Get our thread's copy of the stack.
 | 
| -  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
 | 
| -  // The tracing system can be turned on with ScopedTraceMemory objects
 | 
| -  // allocated on the stack, so avoid potential underflow as they are destroyed.
 | 
| -  if (trace_memory_stack->scope_depth > 0)
 | 
| -    trace_memory_stack->scope_depth--;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -void ScopedTraceMemory::InitForTest() {
 | 
| -  InitThreadLocalStorage();
 | 
| -  enabled_ = true;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -void ScopedTraceMemory::CleanupForTest() {
 | 
| -  enabled_ = false;
 | 
| -  CleanupThreadLocalStorage();
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -int ScopedTraceMemory::GetStackDepthForTest() {
 | 
| -  TraceMemoryStack* stack = GetTraceMemoryStack();
 | 
| -  return static_cast<int>(stack->scope_depth);
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest(
 | 
| -    int stack_index) {
 | 
| -  TraceMemoryStack* stack = GetTraceMemoryStack();
 | 
| -  return stack->scope_data[stack_index];
 | 
| -}
 | 
| -
 | 
| -/////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) {
 | 
| -  // Heap profile output has a header total line, then a list of stacks with
 | 
| -  // memory totals, like this:
 | 
| -  //
 | 
| -  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
 | 
| -  //    95:    40940 [   649:   114260] @ 0x7fa7f4b3be13
 | 
| -  //    77:    32546 [   742:   106234] @
 | 
| -  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
 | 
| -  //
 | 
| -  // MAPPED_LIBRARIES:
 | 
| -  // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0
 | 
| -  // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0
 | 
| -  // ...
 | 
| -  //
 | 
| -  // Skip input after MAPPED_LIBRARIES.
 | 
| -  std::string input_string;
 | 
| -  const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES");
 | 
| -  if (mapped_libraries) {
 | 
| -    input_string.assign(input, mapped_libraries - input);
 | 
| -  } else {
 | 
| -    input_string.assign(input);
 | 
| -  }
 | 
| -
 | 
| -  std::vector<std::string> lines;
 | 
| -  size_t line_count = Tokenize(input_string, "\n", &lines);
 | 
| -  if (line_count == 0) {
 | 
| -    DLOG(WARNING) << "No lines found";
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Handle the initial summary line.
 | 
| -  output->append("[");
 | 
| -  AppendHeapProfileTotalsAsTraceFormat(lines[0], output);
 | 
| -
 | 
| -  // Handle the following stack trace lines.
 | 
| -  for (size_t i = 1; i < line_count; ++i) {
 | 
| -    const std::string& line = lines[i];
 | 
| -    AppendHeapProfileLineAsTraceFormat(line, output);
 | 
| -  }
 | 
| -  output->append("]\n");
 | 
| -}
 | 
| -
 | 
| -void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
 | 
| -                                          std::string* output) {
 | 
| -  // This is what a line looks like:
 | 
| -  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
 | 
| -  //
 | 
| -  // The numbers represent total allocations since profiling was enabled.
 | 
| -  // From the example above:
 | 
| -  //     357 = Outstanding allocations (mallocs - frees)
 | 
| -  //   55227 = Outstanding bytes (malloc bytes - free bytes)
 | 
| -  //   14653 = Total allocations (mallocs)
 | 
| -  // 2624014 = Total bytes (malloc bytes)
 | 
| -  std::vector<std::string> tokens;
 | 
| -  Tokenize(line, " :[]@", &tokens);
 | 
| -  if (tokens.size() < 4) {
 | 
| -    DLOG(WARNING) << "Invalid totals line " << line;
 | 
| -    return;
 | 
| -  }
 | 
| -  DCHECK_EQ(tokens[0], "heap");
 | 
| -  DCHECK_EQ(tokens[1], "profile");
 | 
| -  output->append("{\"current_allocs\": ");
 | 
| -  output->append(tokens[2]);
 | 
| -  output->append(", \"current_bytes\": ");
 | 
| -  output->append(tokens[3]);
 | 
| -  output->append(", \"trace\": \"\"}");
 | 
| -}
 | 
| -
 | 
| -bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
 | 
| -                                        std::string* output) {
 | 
| -  // This is what a line looks like:
 | 
| -  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
 | 
| -  //
 | 
| -  // The numbers represent allocations for a particular stack trace since
 | 
| -  // profiling was enabled. From the example above:
 | 
| -  //    68 = Outstanding allocations (mallocs - frees)
 | 
| -  //  4195 = Outstanding bytes (malloc bytes - free bytes)
 | 
| -  //  1087 = Total allocations (mallocs)
 | 
| -  // 98009 = Total bytes (malloc bytes)
 | 
| -  //
 | 
| -  // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to
 | 
| -  //                                 static strings from trace event categories
 | 
| -  //                                 and names.
 | 
| -  std::vector<std::string> tokens;
 | 
| -  Tokenize(line, " :[]@", &tokens);
 | 
| -  // It's valid to have no stack addresses, so only require 4 tokens.
 | 
| -  if (tokens.size() < 4) {
 | 
| -    DLOG(WARNING) << "Invalid line " << line;
 | 
| -    return false;
 | 
| -  }
 | 
| -  // Don't bother with stacks that have no current allocations.
 | 
| -  if (tokens[0] == "0")
 | 
| -    return false;
 | 
| -  output->append(",\n");
 | 
| -  output->append("{\"current_allocs\": ");
 | 
| -  output->append(tokens[0]);
 | 
| -  output->append(", \"current_bytes\": ");
 | 
| -  output->append(tokens[1]);
 | 
| -  output->append(", \"trace\": \"");
 | 
| -
 | 
| -  // Convert pairs of "stack addresses" into category and name strings.
 | 
| -  const std::string kSingleQuote = "'";
 | 
| -  for (size_t t = 4; t < tokens.size(); t += 2) {
 | 
| -    // Casting strings into pointers is ugly but otherwise tcmalloc would need
 | 
| -    // to gain a special output serializer just for pseudo-stacks.
 | 
| -    const char* trace_category = StringFromHexAddress(tokens[t]);
 | 
| -    DCHECK_LT(t + 1, tokens.size());
 | 
| -    const char* trace_name = StringFromHexAddress(tokens[t + 1]);
 | 
| -
 | 
| -    // TODO(jamescook): Report the trace category and name separately to the
 | 
| -    // trace viewer and allow it to decide what decorations to apply. For now
 | 
| -    // just hard-code a decoration for posted tasks (toplevel).
 | 
| -    std::string trace_string(trace_name);
 | 
| -    if (!strcmp(trace_category, "toplevel"))
 | 
| -      trace_string.append("->PostTask");
 | 
| -
 | 
| -    // Some trace name strings have double quotes, convert them to single.
 | 
| -    ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string);
 | 
| -
 | 
| -    output->append(trace_string);
 | 
| -
 | 
| -    // Trace viewer expects a trailing space.
 | 
| -    output->append(" ");
 | 
| -  }
 | 
| -  output->append("\"}");
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -const char* StringFromHexAddress(const std::string& hex_address) {
 | 
| -  uint64 address = 0;
 | 
| -  if (!base::HexStringToUInt64(hex_address, &address))
 | 
| -    return "error";
 | 
| -  if (!address)
 | 
| -    return "null";
 | 
| -  // Note that this cast handles 64-bit to 32-bit conversion if necessary.
 | 
| -  return reinterpret_cast<const char*>(address);
 | 
| -}
 | 
| -
 | 
| -}  // namespace debug
 | 
| -}  // namespace base
 | 
| 
 |