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; |
| 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 = |
| 116 GetSkewedRandom(static_cast<uint32_t>(frame_variations.values.size()), |
| 117 static_cast<uint32_t>(frame_variations.skew)); |
| 118 backtrace.frames[depth] = frame_variations.values[value_index]; |
| 119 } |
| 120 return backtrace; |
| 121 } |
| 122 |
| 123 private: |
| 124 uint32_t random_seed_ = 777; |
| 125 }; |
| 126 |
| 127 TEST_F(HeapProfilerPerfTest, DeduplicateStackFrames) { |
| 128 StringDeduplicator string_deduplicator; |
| 129 StackFrameDeduplicator deduplicator(&string_deduplicator); |
| 130 |
| 131 auto variations = GetRandomBacktraceVariations(); |
| 132 |
| 133 { |
| 134 ScopedStopwatch stopwatch("time_to_insert"); |
| 135 InsertRandomBacktraces(&deduplicator, variations, 1000000); |
| 136 } |
| 137 } |
| 138 |
| 139 TEST_F(HeapProfilerPerfTest, AppendStackFramesAsTraceFormat) { |
| 140 StringDeduplicator string_deduplicator; |
| 141 StackFrameDeduplicator deduplicator(&string_deduplicator); |
| 142 |
| 143 auto variations = GetRandomBacktraceVariations(); |
| 144 InsertRandomBacktraces(&deduplicator, variations, 1000000); |
| 145 |
| 146 auto traced_value = base::MakeUnique<TracedValue>(); |
| 147 traced_value->BeginArray("nodes"); |
| 148 deduplicator.SerializeIncrementally(traced_value.get()); |
| 149 traced_value->EndArray(); |
| 150 |
| 151 { |
| 152 ScopedStopwatch stopwatch("time_to_append"); |
| 153 std::string json; |
| 154 traced_value->AppendAsTraceFormat(&json); |
| 155 } |
| 156 } |
| 157 |
| 158 } // namespace |
| 159 } // namespace tracing |
OLD | NEW |