| // Copyright (c) 2019 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/callback.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/perf/perf_result_reporter.h" |
| #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" |
| #include "third_party/blink/renderer/platform/heap/persistent.h" |
| |
| namespace blink { |
| |
| class WriteBarrierPerfTest : public TestSupportingGC {}; |
| |
| namespace { |
| |
| constexpr char kMetricPrefixWriteBarrier[] = "WriteBarrier."; |
| constexpr char kMetricWritesDuringGcRunsPerS[] = "writes_during_gc"; |
| constexpr char kMetricWritesOutsideGcRunsPerS[] = "writes_outside_gc"; |
| constexpr char kMetricRelativeSpeedDifferenceUnitless[] = |
| "relative_speed_difference"; |
| |
| perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) { |
| perf_test::PerfResultReporter reporter(kMetricPrefixWriteBarrier, story_name); |
| reporter.RegisterImportantMetric(kMetricWritesDuringGcRunsPerS, "runs/s"); |
| reporter.RegisterImportantMetric(kMetricWritesOutsideGcRunsPerS, "runs/s"); |
| reporter.RegisterImportantMetric(kMetricRelativeSpeedDifferenceUnitless, |
| "unitless"); |
| return reporter; |
| } |
| |
| class PerfDummyObject : public GarbageCollected<PerfDummyObject> { |
| public: |
| PerfDummyObject() = default; |
| virtual void Trace(Visitor*) const {} |
| }; |
| |
| base::TimeDelta TimedRun(base::RepeatingCallback<void()> callback) { |
| const base::TimeTicks start = base::TimeTicks::Now(); |
| callback.Run(); |
| return base::TimeTicks::Now() - start; |
| } |
| |
| } // namespace |
| |
| TEST_F(WriteBarrierPerfTest, MemberWritePerformance) { |
| // Setup. |
| constexpr wtf_size_t kNumElements = 100000; |
| Persistent<HeapVector<Member<PerfDummyObject>>> holder( |
| MakeGarbageCollected<HeapVector<Member<PerfDummyObject>>>()); |
| for (wtf_size_t i = 0; i < kNumElements; ++i) { |
| holder->push_back(MakeGarbageCollected<PerfDummyObject>()); |
| } |
| PreciselyCollectGarbage(); |
| // Benchmark. |
| base::RepeatingCallback<void()> benchmark = base::BindRepeating( |
| [](const Persistent<HeapVector<Member<PerfDummyObject>>>& holder) { |
| for (wtf_size_t i = 0; i < kNumElements / 2; ++i) { |
| (*holder)[i].Swap((*holder)[kNumElements / 2 + i]); |
| } |
| }, |
| holder); |
| |
| // During GC. |
| IncrementalMarkingTestDriver driver(ThreadState::Current()); |
| driver.Start(); |
| base::TimeDelta during_gc_duration = TimedRun(benchmark); |
| driver.FinishSteps(); |
| PreciselyCollectGarbage(); |
| |
| // Outside GC. |
| base::TimeDelta outside_gc_duration = TimedRun(benchmark); |
| |
| // Cleanup. |
| holder.Clear(); |
| PreciselyCollectGarbage(); |
| |
| // Reporting. |
| auto reporter = SetUpReporter("member_write_performance"); |
| reporter.AddResult(kMetricWritesDuringGcRunsPerS, |
| kNumElements / during_gc_duration.InSecondsF()); |
| reporter.AddResult(kMetricWritesOutsideGcRunsPerS, |
| kNumElements / outside_gc_duration.InSecondsF()); |
| reporter.AddResult(kMetricRelativeSpeedDifferenceUnitless, |
| during_gc_duration / outside_gc_duration); |
| } |
| |
| } // namespace blink |