// 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 "content/child/web_process_memory_dump_impl.h" #include "base/trace_event/memory_allocator_dump.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event_argument.h" #include "base/values.h" #include "content/child/web_memory_allocator_dump_impl.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { // Tests that the Chromium<>Blink plumbing that exposes the MemoryInfra classes // behaves correctly, performs the right transfers of memory ownerships and // doesn't leak objects. TEST(WebProcessMemoryDumpImplTest, IntegrationTest) { scoped_refptr traced_value( new base::trace_event::TracedValue()); scoped_ptr wpmd1(new WebProcessMemoryDumpImpl()); auto wmad1 = wpmd1->createMemoryAllocatorDump("1/1"); auto wmad2 = wpmd1->createMemoryAllocatorDump("1/2"); ASSERT_EQ(wmad1, wpmd1->getMemoryAllocatorDump("1/1")); ASSERT_EQ(wmad2, wpmd1->getMemoryAllocatorDump("1/2")); scoped_ptr wpmd2(new WebProcessMemoryDumpImpl()); wpmd2->createMemoryAllocatorDump("2/1"); wpmd2->createMemoryAllocatorDump("2/2"); wpmd1->takeAllDumpsFrom(wpmd2.get()); // Make sure that wpmd2 still owns its own PMD, even if empty. ASSERT_NE(static_cast(nullptr), wpmd2->process_memory_dump_); ASSERT_EQ(wpmd2->owned_process_memory_dump_.get(), wpmd2->process_memory_dump()); ASSERT_TRUE(wpmd2->process_memory_dump()->allocator_dumps().empty()); // Make sure that wpmd2 is still usable after it has been emptied. auto wmad = wpmd2->createMemoryAllocatorDump("2/new"); wmad->AddScalar("attr_name", "bytes", 42); wmad->AddScalarF("attr_name_2", "rate", 42.0f); ASSERT_EQ(1u, wpmd2->process_memory_dump()->allocator_dumps().size()); auto mad = wpmd2->process_memory_dump()->GetAllocatorDump("2/new"); ASSERT_NE(static_cast(nullptr), mad); ASSERT_EQ(wmad, wpmd2->getMemoryAllocatorDump("2/new")); // Check that the attributes are propagated correctly. auto raw_attrs = mad->attributes_for_testing()->ToBaseValue(); base::DictionaryValue* attrs = nullptr; ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs)); base::DictionaryValue* attr = nullptr; ASSERT_TRUE(attrs->GetDictionary("attr_name", &attr)); std::string attr_value; ASSERT_TRUE(attr->GetString("type", &attr_value)); ASSERT_EQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_value); ASSERT_TRUE(attr->GetString("units", &attr_value)); ASSERT_EQ("bytes", attr_value); ASSERT_TRUE(attrs->GetDictionary("attr_name_2", &attr)); ASSERT_TRUE(attr->GetString("type", &attr_value)); ASSERT_EQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_value); ASSERT_TRUE(attr->GetString("units", &attr_value)); ASSERT_EQ("rate", attr_value); ASSERT_TRUE(attr->HasKey("value")); // Check that AsValueInto() doesn't cause a crash. wpmd2->process_memory_dump()->AsValueInto(traced_value.get()); // Free the |wpmd2| to check that the memory ownership of the two MAD(s) // has been transferred to |wpmd1|. wpmd2.reset(); // Now check that |wpmd1| has been effectively merged. ASSERT_EQ(4u, wpmd1->process_memory_dump()->allocator_dumps().size()); ASSERT_EQ(1u, wpmd1->process_memory_dump()->allocator_dumps().count("1/1")); ASSERT_EQ(1u, wpmd1->process_memory_dump()->allocator_dumps().count("1/2")); ASSERT_EQ(1u, wpmd1->process_memory_dump()->allocator_dumps().count("2/1")); ASSERT_EQ(1u, wpmd1->process_memory_dump()->allocator_dumps().count("1/2")); // Check that also the WMAD wrappers got merged. blink::WebMemoryAllocatorDump* null_wmad = nullptr; ASSERT_NE(null_wmad, wpmd1->getMemoryAllocatorDump("1/1")); ASSERT_NE(null_wmad, wpmd1->getMemoryAllocatorDump("1/2")); ASSERT_NE(null_wmad, wpmd1->getMemoryAllocatorDump("2/1")); ASSERT_NE(null_wmad, wpmd1->getMemoryAllocatorDump("2/2")); // Check that AsValueInto() doesn't cause a crash. traced_value = new base::trace_event::TracedValue(); wpmd1->process_memory_dump()->AsValueInto(traced_value.get()); // Check that clear() actually works. wpmd1->clear(); ASSERT_TRUE(wpmd1->process_memory_dump()->allocator_dumps().empty()); ASSERT_EQ(nullptr, wpmd1->process_memory_dump()->GetAllocatorDump("1/1")); ASSERT_EQ(nullptr, wpmd1->process_memory_dump()->GetAllocatorDump("2/1")); // Check that AsValueInto() doesn't cause a crash. traced_value = new base::trace_event::TracedValue(); wpmd1->process_memory_dump()->AsValueInto(traced_value.get()); // Check if a WebMemoryAllocatorDump created with guid, has correct guid. blink::WebMemoryAllocatorDumpGuid guid = base::trace_event::MemoryAllocatorDumpGuid("id_1").ToUint64(); auto wmad3 = wpmd1->createMemoryAllocatorDump("1/3", guid); ASSERT_EQ(wmad3->guid(), guid); ASSERT_EQ(wmad3, wpmd1->getMemoryAllocatorDump("1/3")); // Check that AddOwnershipEdge is propagated correctly. auto wmad4 = wpmd1->createMemoryAllocatorDump("1/4"); wpmd1->AddOwnershipEdge(wmad4->guid(), guid); auto allocator_dumps_edges = wpmd1->process_memory_dump()->allocator_dumps_edges(); ASSERT_EQ(1u, allocator_dumps_edges.size()); ASSERT_EQ(wmad4->guid(), allocator_dumps_edges[0].source.ToUint64()); ASSERT_EQ(guid, allocator_dumps_edges[0].target.ToUint64()); wpmd1.reset(); } } // namespace content