blob: 67ea455673c79d0cec11cabb8e26f36f0021ba66 [file] [log] [blame]
// 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/memory_allocator_dump.h"
#include <stdint.h>
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/traced_value.h"
#include "base/values.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::ElementsAre;
using testing::Eq;
using testing::ByRef;
using testing::IsEmpty;
using testing::Contains;
namespace base {
namespace trace_event {
namespace {
class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
public:
bool OnMemoryDump(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd) override {
MemoryAllocatorDump* root_heap =
pmd->CreateAllocatorDump("foobar_allocator");
root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 4096);
root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 42);
root_heap->AddScalar("attr1", "units1", 1234);
root_heap->AddString("attr2", "units2", "string_value");
MemoryAllocatorDump* sub_heap =
pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 1);
sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 3);
pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
// Leave the rest of sub heap deliberately uninitialized, to check that
// CreateAllocatorDump returns a properly zero-initialized object.
return true;
}
};
void CheckString(const MemoryAllocatorDump* dump,
const std::string& name,
const char* expected_units,
const std::string& expected_value) {
MemoryAllocatorDump::Entry expected(name, expected_units, expected_value);
EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected))));
}
void CheckScalar(const MemoryAllocatorDump* dump,
const std::string& name,
const char* expected_units,
uint64_t expected_value) {
MemoryAllocatorDump::Entry expected(name, expected_units, expected_value);
EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected))));
}
} // namespace
TEST(MemoryAllocatorDumpTest, GuidGeneration) {
std::unique_ptr<MemoryAllocatorDump> mad(new MemoryAllocatorDump(
"foo", MemoryDumpLevelOfDetail::FIRST, MemoryAllocatorDumpGuid(0x42u)));
ASSERT_EQ("42", mad->guid().ToString());
}
TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
FakeMemoryAllocatorDumpProvider fmadp;
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
ProcessMemoryDump pmd(dump_args);
fmadp.OnMemoryDump(dump_args, &pmd);
ASSERT_EQ(3u, pmd.allocator_dumps().size());
const MemoryAllocatorDump* root_heap =
pmd.GetAllocatorDump("foobar_allocator");
ASSERT_NE(nullptr, root_heap);
EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 4096);
CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 42);
CheckScalar(root_heap, "attr1", "units1", 1234);
CheckString(root_heap, "attr2", "units2", "string_value");
const MemoryAllocatorDump* sub_heap =
pmd.GetAllocatorDump("foobar_allocator/sub_heap");
ASSERT_NE(nullptr, sub_heap);
EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 1);
CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
MemoryAllocatorDump::kUnitsObjects, 3);
const MemoryAllocatorDump* empty_sub_heap =
pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
ASSERT_NE(nullptr, empty_sub_heap);
EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
EXPECT_THAT(empty_sub_heap->entries(), IsEmpty());
// Check that calling serialization routines doesn't cause a crash.
std::unique_ptr<TracedValue> traced_value(new TracedValue);
pmd.SerializeAllocatorDumpsInto(traced_value.get());
}
TEST(MemoryAllocatorDumpTest, GetSize) {
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
ProcessMemoryDump pmd(dump_args);
MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size");
dump->AddScalar(MemoryAllocatorDump::kNameSize,
MemoryAllocatorDump::kUnitsBytes, 1);
dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2);
EXPECT_EQ(1u, dump->GetSizeInternal());
}
TEST(MemoryAllocatorDumpTest, ReadValues) {
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
ProcessMemoryDump pmd(dump_args);
MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size");
dump->AddScalar("one", "byte", 1);
dump->AddString("one", "object", "one");
MemoryAllocatorDump::Entry expected_scalar("one", "byte", 1);
MemoryAllocatorDump::Entry expected_string("one", "object", "one");
EXPECT_THAT(dump->entries(), ElementsAre(Eq(ByRef(expected_scalar)),
Eq(ByRef(expected_string))));
}
TEST(MemoryAllocatorDumpTest, MovingAnEntry) {
MemoryAllocatorDump::Entry expected_entry("one", "byte", 1);
MemoryAllocatorDump::Entry from_entry("one", "byte", 1);
MemoryAllocatorDump::Entry to_entry = std::move(from_entry);
EXPECT_EQ(expected_entry, to_entry);
}
// DEATH tests are not supported in Android/iOS/Fuchsia.
#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS) && \
!defined(OS_FUCHSIA)
TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
FakeMemoryAllocatorDumpProvider fmadp;
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
ProcessMemoryDump pmd(dump_args);
pmd.CreateAllocatorDump("foo_allocator");
pmd.CreateAllocatorDump("bar_allocator/heap");
ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
}
TEST(MemoryAllocatorDumpTest, ForbidStringsInBackgroundModeDeathTest) {
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::BACKGROUND};
ProcessMemoryDump pmd(dump_args);
MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("malloc");
ASSERT_DEATH(dump->AddString("foo", "bar", "baz"), "");
}
#endif
} // namespace trace_event
} // namespace base