OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 #include <iterator> | |
7 #include <vector> | |
8 | |
9 #include "base/memory/ptr_util.h" | |
10 #include "base/strings/stringprintf.h" | |
11 #include "base/time/time.h" | |
12 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" | |
13 #include "base/trace_event/heap_profiler_string_deduplicator.h" | |
14 #include "base/trace_event/trace_event_argument.h" | |
15 #include "perf_test_helpers.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace tracing { | |
19 namespace { | |
20 | |
21 using namespace base::trace_event; | |
22 | |
23 class HeapProfilerPerfTest : public testing::Test { | |
24 protected: | |
25 struct StackFrameVariations { | |
26 size_t skew; | |
27 std::vector<StackFrame> values; | |
28 }; | |
29 using BacktraceVariations = std::vector<StackFrameVariations>; | |
30 | |
31 BacktraceVariations GetRandomBacktraceVariations() { | |
32 struct VariationSpec { | |
33 size_t value_count; // number of unique frames | |
34 size_t skew; // see GetSkewedRandom() | |
35 size_t length; // number of backtrace levels covered | |
36 }; | |
37 static const VariationSpec specs[] = { | |
38 // These values give realistic insertion pattern with 60% hit count. | |
39 {100, 90, Backtrace::kMaxFrameCount - 5}, | |
40 {10, 5, 5}}; | |
41 | |
42 BacktraceVariations backtrace_variations; | |
43 const VariationSpec* spec = std::begin(specs); | |
44 size_t spec_end_depth = spec->length; | |
45 for (size_t depth = 0; depth != Backtrace::kMaxFrameCount; ++depth) { | |
46 if (depth == spec_end_depth) { | |
47 if (spec != std::end(specs) - 1) { | |
48 spec++; | |
49 spec_end_depth = depth + spec->length; | |
50 } else { | |
51 spec_end_depth = Backtrace::kMaxFrameCount; | |
52 } | |
53 } | |
54 backtrace_variations.push_back({spec->skew}); | |
55 auto& frame_variations = backtrace_variations.back(); | |
56 for (size_t v = 0; v != spec->value_count; ++v) { | |
57 uintptr_t pc = static_cast<uintptr_t>(GetRandom64()); | |
58 frame_variations.values.push_back( | |
59 StackFrame::FromProgramCounter(reinterpret_cast<void*>(pc))); | |
60 } | |
61 } | |
62 | |
63 return backtrace_variations; | |
64 } | |
65 | |
66 size_t InsertRandomBacktraces(StackFrameDeduplicator* deduplicator, | |
67 const BacktraceVariations& backtrace_variations, | |
68 size_t max_frame_count) { | |
69 size_t insert_count = 0; | |
70 while (true) { | |
71 insert_count++; | |
72 Backtrace backtrace = RandomBacktrace(backtrace_variations); | |
73 deduplicator->Insert(backtrace.frames, | |
74 backtrace.frames + backtrace.frame_count); | |
75 size_t frame_count = deduplicator->end() - deduplicator->begin(); | |
76 if (frame_count > max_frame_count) { | |
77 break; | |
78 } | |
79 } | |
80 return insert_count; | |
81 } | |
82 | |
83 private: | |
84 uint32_t GetRandom32() { | |
85 random_seed_ = random_seed_ * 1664525 + 1013904223; | |
Primiano Tucci (use gerrit)
2017/07/13 17:33:16
y not like rand()?
DmitrySkiba
2017/07/13 17:36:40
handwritten rand is best rand :)
But seriously, I
| |
86 return random_seed_; | |
87 } | |
88 | |
89 uint64_t GetRandom64() { | |
90 uint64_t rnd = GetRandom32(); | |
91 return (rnd << 32) | GetRandom32(); | |
92 } | |
93 | |
94 // Returns random number in range [0, max). | |
95 uint32_t GetRandom32(uint32_t max) { | |
96 uint64_t rnd = GetRandom32(); | |
97 return static_cast<uint32_t>((rnd * max) >> 32); | |
98 } | |
99 | |
100 // In 1/skew cases returns random value in range [0, max), in all | |
101 // other cases returns value in range [0, max/skew). The average value | |
102 // ends up being (2*skew - 1) / (2*skew^2) * max. | |
103 uint32_t GetSkewedRandom(uint32_t max, uint32_t skew) { | |
104 if (GetRandom32(skew) != (skew - 1)) { | |
105 max /= skew; | |
106 } | |
107 return GetRandom32(max); | |
108 } | |
109 | |
110 Backtrace RandomBacktrace(const BacktraceVariations& backtrace_variations) { | |
111 Backtrace backtrace; | |
112 backtrace.frame_count = Backtrace::kMaxFrameCount; | |
113 for (size_t depth = 0; depth != backtrace.frame_count; ++depth) { | |
114 const auto& frame_variations = backtrace_variations[depth]; | |
115 size_t value_index = GetSkewedRandom(frame_variations.values.size(), | |
116 frame_variations.skew); | |
117 backtrace.frames[depth] = frame_variations.values[value_index]; | |
118 } | |
119 return backtrace; | |
120 } | |
121 | |
122 private: | |
123 uint32_t random_seed_ = 777; | |
124 }; | |
125 | |
126 TEST_F(HeapProfilerPerfTest, DeduplicateStackFrames) { | |
127 StringDeduplicator string_deduplicator; | |
128 StackFrameDeduplicator deduplicator(&string_deduplicator); | |
129 | |
130 auto variations = GetRandomBacktraceVariations(); | |
131 | |
132 { | |
133 ScopedStopwatch stopwatch("time_to_insert"); | |
134 InsertRandomBacktraces(&deduplicator, variations, 1000000); | |
135 } | |
136 } | |
137 | |
138 TEST_F(HeapProfilerPerfTest, AppendStackFramesAsTraceFormat) { | |
139 StringDeduplicator string_deduplicator; | |
140 StackFrameDeduplicator deduplicator(&string_deduplicator); | |
141 | |
142 auto variations = GetRandomBacktraceVariations(); | |
143 InsertRandomBacktraces(&deduplicator, variations, 1000000); | |
144 | |
145 auto traced_value = base::MakeUnique<TracedValue>(); | |
146 traced_value->BeginArray("nodes"); | |
147 deduplicator.SerializeIncrementally(traced_value.get()); | |
148 traced_value->EndArray(); | |
149 | |
150 { | |
151 ScopedStopwatch stopwatch("time_to_append"); | |
152 std::string json; | |
153 traced_value->AppendAsTraceFormat(&json); | |
154 } | |
155 } | |
156 | |
157 } // namespace | |
158 } // namespace tracing | |
OLD | NEW |