Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3623)

Unified Diff: base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc

Issue 2650863003: [tracing] Switch to new heap dump format. (Closed)
Patch Set: Fix rebase damage Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
index 2215edebb56fd5920eb7ccade2bb103f3dd9f165..291f99ba7aa5039696128a5202b3a5e25997dd71 100644
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -8,12 +8,84 @@
#include <memory>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_string_deduplicator.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace trace_event {
+namespace {
+
+constexpr static int kInvalidStackFrameIndex =
+ StackFrameDeduplicator::FrameNode::kInvalidFrameIndex;
+
+// Calls StackFrameDeduplicator::SerializeIncrementally() and returns
+// ListValue with serialized entries.
+std::unique_ptr<ListValue> SerializeEntriesIncrementally(
+ StackFrameDeduplicator* dedup) {
+ TracedValue traced_value;
+ traced_value.BeginArray("");
+ dedup->SerializeIncrementally(&traced_value);
+ traced_value.EndArray();
+
+ auto base_value = traced_value.ToBaseValue();
+ DictionaryValue* dictionary;
+ std::unique_ptr<Value> entries;
+ if (!base_value->GetAsDictionary(&dictionary) ||
+ !dictionary->Remove("", &entries)) {
+ return nullptr;
+ }
+ return ListValue::From(std::move(entries));
+}
+
+struct StackFrameMapping {
+ StackFrameMapping(int id,
+ StackFrame frame,
+ int parent_id = kInvalidStackFrameIndex)
+ : id(id), parent_id(parent_id) {
+ EXPECT_EQ(StackFrame::Type::TRACE_EVENT_NAME, frame.type);
+ name = static_cast<const char*>(frame.value);
+ }
+
+ int id;
+ const char* name;
+ int parent_id;
+};
+
+std::unique_ptr<ListValue> SerializeMappingsAsEntries(
+ StringDeduplicator* string_dedup,
+ std::initializer_list<StackFrameMapping> mappings) {
+ auto entries = MakeUnique<ListValue>();
+ for (const auto& mapping : mappings) {
+ auto entry = MakeUnique<DictionaryValue>();
+ entry->SetInteger("id", mapping.id);
+ entry->SetInteger("name_sid", string_dedup->Insert(mapping.name));
+ if (mapping.parent_id != kInvalidStackFrameIndex) {
+ entry->SetInteger("parent", mapping.parent_id);
+ }
+ entries->Append(std::move(entry));
+ }
+ return entries;
+}
+
+void ExpectIncrementalEntries(
+ StackFrameDeduplicator* dedup,
+ StringDeduplicator* string_dedup,
+ std::initializer_list<StackFrameMapping> mappings) {
+ auto entries = SerializeEntriesIncrementally(dedup);
+ ASSERT_TRUE(entries);
+
+ auto expected_entries = SerializeMappingsAsEntries(string_dedup, mappings);
+ ASSERT_TRUE(expected_entries->Equals(entries.get()))
+ << "expected_entries = " << *expected_entries << "entries = " << *entries;
+}
+
+} // namespace
+
// Define all strings once, because the deduplicator requires pointer equality,
// and string interning is unreliable.
StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain");
@@ -21,30 +93,52 @@ StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain");
StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget");
StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize");
StackFrame kMalloc = StackFrame::FromTraceEventName("malloc");
+StackFrame kNull = StackFrame::FromTraceEventName(nullptr);
+
+TEST(StackFrameDeduplicatorTest, ImplicitId0) {
+ StackFrame null_bt[] = {kNull};
+
+ // Empty backtraces (begin == end) are mapped to an implicitly added
+ // node #0. However, backtrace with a single null frame is not empty,
+ // and should be mapped to some other id.
+
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+
+ // Node #0 is added implicitly and corresponds to an empty backtrace.
+ ASSERT_EQ(dedup.begin() + 1, dedup.end());
+ ASSERT_EQ(0, dedup.Insert(std::begin(null_bt), std::begin(null_bt)));
+
+ // Placeholder entry for ID 0 is a frame with NULL name and no parent.
+ // However inserting such a frame should yield a different ID.
+ ExpectIncrementalEntries(&dedup, &string_dedup, {{0, kNull}});
+ ASSERT_EQ(1, dedup.Insert(std::begin(null_bt), std::end(null_bt)));
+}
TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
// The call tree should look like this (index in brackets).
//
- // BrowserMain [0]
- // CreateWidget [1]
- // malloc [2]
+ // BrowserMain [1]
+ // CreateWidget [2]
+ // malloc [3]
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+ ASSERT_EQ(3, dedup.Insert(std::begin(bt), std::end(bt)));
- auto iter = dedup->begin();
+ auto iter = dedup.begin() + 1; // skip implicit node #0
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+ ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+ ASSERT_EQ(1, (iter + 1)->parent_frame_index);
ASSERT_EQ(kMalloc, (iter + 2)->frame);
- ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+ ASSERT_EQ(2, (iter + 2)->parent_frame_index);
- ASSERT_EQ(iter + 3, dedup->end());
+ ASSERT_EQ(iter + 3, dedup.end());
}
TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) {
@@ -56,24 +150,25 @@ TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) {
//
// So the call tree should look like this (index in brackets).
//
- // BrowserMain [0]
- // (null) [1]
- // malloc [2]
+ // BrowserMain [1]
+ // (null) [2]
+ // malloc [3]
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+ ASSERT_EQ(3, dedup.Insert(std::begin(bt), std::end(bt)));
- auto iter = dedup->begin();
+ auto iter = dedup.begin() + 1; // skip implicit node #0
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+ ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index);
ASSERT_EQ(null_frame, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+ ASSERT_EQ(1, (iter + 1)->parent_frame_index);
ASSERT_EQ(kMalloc, (iter + 2)->frame);
- ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+ ASSERT_EQ(2, (iter + 2)->parent_frame_index);
- ASSERT_EQ(iter + 3, dedup->end());
+ ASSERT_EQ(iter + 3, dedup.end());
}
// Test that there can be different call trees (there can be multiple bottom
@@ -85,32 +180,33 @@ TEST(StackFrameDeduplicatorTest, MultipleRoots) {
// The call tree should look like this (index in brackets).
//
- // BrowserMain [0]
- // CreateWidget [1]
- // RendererMain [2]
- // CreateWidget [3]
+ // BrowserMain [1]
+ // CreateWidget [2]
+ // RendererMain [3]
+ // CreateWidget [4]
//
// Note that there will be two instances of CreateWidget,
// with different parents.
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+ ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(4, dedup.Insert(std::begin(bt1), std::end(bt1)));
- auto iter = dedup->begin();
+ auto iter = dedup.begin() + 1; // skip implicit node #0
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+ ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+ ASSERT_EQ(1, (iter + 1)->parent_frame_index);
ASSERT_EQ(kRendererMain, (iter + 2)->frame);
- ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+ ASSERT_EQ(kInvalidStackFrameIndex, (iter + 2)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
- ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+ ASSERT_EQ(3, (iter + 3)->parent_frame_index);
- ASSERT_EQ(iter + 4, dedup->end());
+ ASSERT_EQ(iter + 4, dedup.end());
}
TEST(StackFrameDeduplicatorTest, Deduplication) {
@@ -119,33 +215,53 @@ TEST(StackFrameDeduplicatorTest, Deduplication) {
// The call tree should look like this (index in brackets).
//
- // BrowserMain [0]
- // CreateWidget [1]
- // Initialize [2]
+ // BrowserMain [1]
+ // CreateWidget [2]
+ // Initialize [3]
//
// Note that BrowserMain will be re-used.
- std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+ ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1)));
- auto iter = dedup->begin();
+ auto iter = dedup.begin() + 1; // skip implicit node #0
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
- ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+ ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
- ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+ ASSERT_EQ(1, (iter + 1)->parent_frame_index);
ASSERT_EQ(kInitialize, (iter + 2)->frame);
- ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+ ASSERT_EQ(1, (iter + 2)->parent_frame_index);
- ASSERT_EQ(iter + 3, dedup->end());
+ ASSERT_EQ(iter + 3, dedup.end());
// Inserting the same backtrace again should return the index of the existing
// node.
- ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
- ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
- ASSERT_EQ(dedup->begin() + 3, dedup->end());
+ ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1)));
+ ASSERT_EQ(4 /* 1 implicit + 3 added */, dedup.end() - dedup.begin());
+}
+
+TEST(StackFrameDeduplicatorTest, SerializeIncrementally) {
+ StringDeduplicator string_dedup;
+ StackFrameDeduplicator dedup(&string_dedup);
+
+ StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+ ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0)));
+
+ ExpectIncrementalEntries(
+ &dedup, &string_dedup,
+ {{0, kNull}, {1, kBrowserMain}, {2, kCreateWidget, 1}});
+
+ StackFrame bt1[] = {kBrowserMain, kInitialize};
+ ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1)));
+
+ ExpectIncrementalEntries(&dedup, &string_dedup, {{3, kInitialize, 1}});
+
+ ExpectIncrementalEntries(&dedup, &string_dedup, {});
}
} // namespace trace_event
« no previous file with comments | « base/trace_event/heap_profiler_stack_frame_deduplicator.cc ('k') | base/trace_event/heap_profiler_string_deduplicator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698