Commit c7336081 authored by primiano's avatar primiano Committed by Commit bot

[tracing] Add support to pre-load and merge ProcessMemoryDump(s).

Allows MemoryDumpProvider(s) with dump-time constraints (mostly GC
allocators) to create out-of-band MemoryAllocatorDump(s) and merge
them during the onMemoryDump callback.

So far, the architecture of MemoryDumpProvider expected to never
instantiate ProcessMemoryDump(s) directly, but just fill up the
one passed as argument to the onMemoryDump(ProcessMemoryDump*)
callback.
This, however, doesn't cover the cases of dumpers that cannot dump
at arbitrary times (i.e. during onMemoryDump callback) and
need to pre-fill the dump stats before the actual callback
comes.
A concrete case of this are dump providers for garbage-collected
allocators (specifically BlinkGC) where some of the stats can be
collected only during the GC.

BUG=466141

Review URL: https://codereview.chromium.org/1151603004

Cr-Commit-Position: refs/heads/master@{#330924}
parent 2d93642c
......@@ -88,6 +88,7 @@ source_set("trace_event_unittests") {
"java_heap_dump_provider_android_unittest.cc",
"memory_allocator_dump_unittest.cc",
"memory_dump_manager_unittest.cc",
"process_memory_dump_unittest.cc",
"process_memory_maps_dump_provider_unittest.cc",
"process_memory_totals_dump_provider_unittest.cc",
"trace_event_argument_unittest.cc",
......
......@@ -35,6 +35,23 @@ MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
return it == allocator_dumps_.end() ? nullptr : it->second;
}
void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
// We support only merging of MemoryAllocatorDumps. The special process_totals
// and mmaps cases are not relevant, let's just prevent clients from doing it.
DCHECK(!other->has_process_totals() && !other->has_process_mmaps());
// Moves the ownership of all MemoryAllocatorDump(s) contained in |other|
// into this ProcessMemoryDump.
for (MemoryAllocatorDump* mad : other->allocator_dumps_storage_) {
// Check that we don't merge duplicates.
DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
allocator_dumps_storage_.push_back(mad);
allocator_dumps_[mad->absolute_name()] = mad;
}
other->allocator_dumps_storage_.weak_clear();
other->allocator_dumps_.clear();
}
void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
// Build up the [dumper name] -> [value] dictionary.
if (has_process_totals_) {
......
......@@ -41,6 +41,14 @@ class BASE_EXPORT ProcessMemoryDump {
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
// Merges all MemoryAllocatorDump(s) contained in |other| inside this
// ProcessMemoryDump, transferring their ownership to this instance.
// |other| will be an empty ProcessMemoryDump after this method returns.
// This is to allow dump providers to pre-populate ProcessMemoryDump instances
// and later move their contents into the ProcessMemoryDump passed as argument
// of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
void TakeAllDumpsFrom(ProcessMemoryDump* other);
ProcessMemoryTotals* process_totals() { return &process_totals_; }
bool has_process_totals() const { return has_process_totals_; }
void set_has_process_totals() { has_process_totals_ = true; }
......
// Copyright 2015 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/trace_event/process_memory_dump.h"
#include "base/memory/scoped_ptr.h"
#include "base/trace_event/trace_event_argument.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace trace_event {
TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
scoped_refptr<TracedValue> traced_value(new TracedValue());
scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
pmd1->CreateAllocatorDump("pmd1/mad1");
pmd1->CreateAllocatorDump("pmd1/mad2");
scoped_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump(nullptr));
pmd2->CreateAllocatorDump("pmd2/mad1");
pmd2->CreateAllocatorDump("pmd2/mad2");
pmd1->TakeAllDumpsFrom(pmd2.get());
// Make sure that pmd2 is empty but still usable after it has been emptied.
ASSERT_TRUE(pmd2->allocator_dumps().empty());
pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
ASSERT_EQ(1u, pmd2->allocator_dumps().size());
ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2"));
// Check that the AsValueInto doesn't cause a crash.
pmd2->AsValueInto(traced_value.get());
// Free the |pmd2| to check that the memory ownership of the two MAD(s)
// has been transferred to |pmd1|.
pmd2.reset();
// Now check that |pmd1| has been effectively merged.
ASSERT_EQ(4u, pmd1->allocator_dumps().size());
ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1"));
ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
// Check that the AsValueInto doesn't cause a crash.
traced_value = new TracedValue();
pmd1->AsValueInto(traced_value.get());
pmd1.reset();
}
} // namespace trace_event
} // namespace base
......@@ -56,6 +56,7 @@
'trace_event/java_heap_dump_provider_android_unittest.cc',
'trace_event/memory_allocator_dump_unittest.cc',
'trace_event/memory_dump_manager_unittest.cc',
'trace_event/process_memory_dump_unittest.cc',
'trace_event/process_memory_maps_dump_provider_unittest.cc',
'trace_event/process_memory_totals_dump_provider_unittest.cc',
'trace_event/trace_event_argument_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment