| Index: skia/ext/skia_memory_dump_provider.cc
 | 
| diff --git a/skia/ext/skia_memory_dump_provider.cc b/skia/ext/skia_memory_dump_provider.cc
 | 
| index e0767526beacb4c293351dc9b401fbd7df7fabc1..5f09afb906bd47703f653788990ebfe5592188cc 100644
 | 
| --- a/skia/ext/skia_memory_dump_provider.cc
 | 
| +++ b/skia/ext/skia_memory_dump_provider.cc
 | 
| @@ -4,6 +4,8 @@
 | 
|  
 | 
|  #include "skia_memory_dump_provider.h"
 | 
|  
 | 
| +#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 | 
| +#include "base/trace_event/heap_profiler_heap_dump_writer.cc"
 | 
|  #include "base/trace_event/memory_allocator_dump.h"
 | 
|  #include "base/trace_event/memory_dump_manager.h"
 | 
|  #include "base/trace_event/process_memory_dump.h"
 | 
| @@ -12,6 +14,21 @@
 | 
|  
 | 
|  namespace skia {
 | 
|  
 | 
| +namespace {
 | 
| +
 | 
| +void ReportAllocation(void* address, size_t size, const char* type_name) {
 | 
| +  SkiaMemoryDumpProvider::GetInstance()->Insert(address, size, type_name);
 | 
| +}
 | 
| +
 | 
| +void ReportFree(void* address) {
 | 
| +  SkiaMemoryDumpProvider::GetInstance()->Remove(address);
 | 
| +}
 | 
| +
 | 
| +} // namespace
 | 
| +
 | 
| +SkiaAllocHooks::AllocationHook* SkiaAllocHooks::allocation_hook_ = nullptr;
 | 
| +SkiaAllocHooks::FreeHook* SkiaAllocHooks::free_hook_ = nullptr;
 | 
| +
 | 
|  // static
 | 
|  SkiaMemoryDumpProvider* SkiaMemoryDumpProvider::GetInstance() {
 | 
|    return base::Singleton<
 | 
| @@ -19,7 +36,9 @@ SkiaMemoryDumpProvider* SkiaMemoryDumpProvider::GetInstance() {
 | 
|        base::LeakySingletonTraits<SkiaMemoryDumpProvider>>::get();
 | 
|  }
 | 
|  
 | 
| -SkiaMemoryDumpProvider::SkiaMemoryDumpProvider() {}
 | 
| +SkiaMemoryDumpProvider::SkiaMemoryDumpProvider()
 | 
| +  : is_heap_profiling_enabled_(false) {
 | 
| +}
 | 
|  
 | 
|  SkiaMemoryDumpProvider::~SkiaMemoryDumpProvider() {}
 | 
|  
 | 
| @@ -30,7 +49,89 @@ bool SkiaMemoryDumpProvider::OnMemoryDump(
 | 
|                                        process_memory_dump);
 | 
|    SkGraphics::DumpMemoryStatistics(&skia_dumper);
 | 
|  
 | 
| +  if (is_heap_profiling_enabled_) {
 | 
| +    int total_size = 0;
 | 
| +    /*if (args.level_of_detail ==
 | 
| +      base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {*/
 | 
| +    if (true) {
 | 
| +      base::trace_event::TraceEventMemoryOverhead overhead;
 | 
| +      base::hash_map<base::trace_event::AllocationContext, size_t>
 | 
| +          bytes_by_context;
 | 
| +      {
 | 
| +        base::AutoLock scoped_lock(lock_);
 | 
| +        for (const auto& alloc_size : *allocation_register_) {
 | 
| +          bytes_by_context[alloc_size.context] += alloc_size.size;
 | 
| +          total_size += alloc_size.size;
 | 
| +        }
 | 
| +        allocation_register_->EstimateTraceMemoryOverhead(&overhead);
 | 
| +      }
 | 
| +
 | 
| +      // Copied from WebProcessMemoryDumpImpl::dumpHeapUsage
 | 
| +      const char* allocator_name = "skia";
 | 
| +      if (!bytes_by_context.empty()) {
 | 
| +        scoped_refptr<base::trace_event::MemoryDumpSessionState> session_state =
 | 
| +          process_memory_dump->session_state();
 | 
| +        scoped_ptr<base::trace_event::TracedValue> heap_dump =
 | 
| +          ExportHeapDump(bytes_by_context,
 | 
| +                         session_state->stack_frame_deduplicator(),
 | 
| +                         session_state->type_name_deduplicator());
 | 
| +        process_memory_dump->AddHeapDump(allocator_name, std::move(heap_dump));
 | 
| +      }
 | 
| +      std::string base_name =
 | 
| +        base::StringPrintf("tracing/heap_profiler_%s", allocator_name);
 | 
| +      overhead.DumpInto(base_name.c_str(), process_memory_dump);
 | 
| +    } else {
 | 
| +      int total_size = 0;
 | 
| +      {
 | 
| +        base::AutoLock scoped_lock(lock_);
 | 
| +        for (const auto& alloc_size : *allocation_register_) {
 | 
| +          total_size += alloc_size.size;
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    const char* dump_name = "skia/sk_malloc";
 | 
| +    skia_dumper.dumpNumericValue(dump_name, "size", "bytes", total_size);
 | 
| +    skia_dumper.setMemoryBacking(dump_name, "malloc", nullptr);
 | 
| +  }
 | 
| +
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| +void SkiaMemoryDumpProvider::OnHeapProfilingEnabled(bool enabled) {
 | 
| +  if (enabled) {
 | 
| +    {
 | 
| +      base::AutoLock scoped_lock(lock_);
 | 
| +      if (!allocation_register_) {
 | 
| +        allocation_register_ = make_scoped_ptr(
 | 
| +            new base::trace_event::AllocationRegister());
 | 
| +      }
 | 
| +    }
 | 
| +    SkiaAllocHooks::SetAllocationHook(ReportAllocation);
 | 
| +    SkiaAllocHooks::SetFreeHook(ReportFree);
 | 
| +  } else {
 | 
| +    SkiaAllocHooks::SetAllocationHook(nullptr);
 | 
| +    SkiaAllocHooks::SetFreeHook(nullptr);
 | 
| +  }
 | 
| +  is_heap_profiling_enabled_ = enabled;
 | 
| +}
 | 
| +
 | 
| +void SkiaMemoryDumpProvider::Insert(void* address, size_t size,
 | 
| +                                    const char* type_name) {
 | 
| +  base::trace_event::AllocationContext context =
 | 
| +    base::trace_event::AllocationContextTracker::GetInstanceForCurrentThread()->GetContextSnapshot();
 | 
| +  context.type_name = type_name;
 | 
| +  base::AutoLock scoped_lock(lock_);
 | 
| +  if (allocation_register_) {
 | 
| +    allocation_register_->Insert(address, size, context);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void SkiaMemoryDumpProvider::Remove(void* address) {
 | 
| +  base::AutoLock scoped_lock(lock_);
 | 
| +  if (allocation_register_) {
 | 
| +    allocation_register_->Remove(address);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  }  // namespace skia
 | 
| 
 |