blob: 5c9eaf0919d075754dd111b613dc4e1a0523c3bd [file] [log] [blame]
// Copyright 2017 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 "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
#include "base/test/simple_test_tick_clock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
namespace {
RuntimeCallStats::CounterId test_counter_1_id =
RuntimeCallStats::CounterId::kTestCounter1;
RuntimeCallStats::CounterId test_counter_2_id =
RuntimeCallStats::CounterId::kTestCounter2;
} // namespace
class RuntimeCallStatsTest : public testing::Test {
public:
void SetUp() override {
// Add one millisecond because RuntimeCallTimer uses |start_ticks_| =
// base::TimeTicks() to represent that the timer is not running.
clock_.SetNowTicks(base::TimeTicks() +
base::TimeDelta::FromMilliseconds(1));
}
void TearDown() override {
features_backup_.Restore();
}
void AdvanceClock(int milliseconds) {
clock_.Advance(base::TimeDelta::FromMilliseconds(milliseconds));
}
const base::TickClock* clock() { return &clock_; }
private:
RuntimeEnabledFeatures::Backup features_backup_;
base::SimpleTestTickClock clock_;
};
TEST_F(RuntimeCallStatsTest, InitialCountShouldBeZero) {
RuntimeCallCounter counter("counter");
EXPECT_EQ(0ul, counter.GetCount());
}
TEST_F(RuntimeCallStatsTest, StatsCounterNameIsCorrect) {
RuntimeCallStats stats(clock());
EXPECT_STREQ("Blink_TestCounter1",
stats.GetCounter(test_counter_1_id)->GetName());
}
TEST_F(RuntimeCallStatsTest, TestBindingsCountersForMethods) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* method_counter =
stats.GetCounter(RuntimeCallStats::CounterId::kBindingsMethodTestCounter);
EXPECT_STREQ("Blink_BindingsMethodTestCounter", method_counter->GetName());
}
TEST_F(RuntimeCallStatsTest, TestBindingsCountersForReadOnlyAttributes) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* getter_counter =
stats.GetCounter(RuntimeCallStats::CounterId::
kBindingsReadOnlyAttributeTestCounter_Getter);
EXPECT_STREQ("Blink_BindingsReadOnlyAttributeTestCounter_Getter",
getter_counter->GetName());
}
TEST_F(RuntimeCallStatsTest, TestBindingsCountersForAttributes) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* getter_counter = stats.GetCounter(
RuntimeCallStats::CounterId::kBindingsAttributeTestCounter_Getter);
RuntimeCallCounter* setter_counter = stats.GetCounter(
RuntimeCallStats::CounterId::kBindingsAttributeTestCounter_Setter);
EXPECT_STREQ("Blink_BindingsAttributeTestCounter_Getter",
getter_counter->GetName());
EXPECT_STREQ("Blink_BindingsAttributeTestCounter_Setter",
setter_counter->GetName());
}
TEST_F(RuntimeCallStatsTest, CountIsUpdatedAfterLeave) {
RuntimeCallTimer timer(clock());
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
stats.Enter(&timer, test_counter_1_id);
EXPECT_EQ(0ul, counter->GetCount());
stats.Leave(&timer);
EXPECT_EQ(1ul, counter->GetCount());
}
TEST_F(RuntimeCallStatsTest, TimeIsUpdatedAfterLeave) {
RuntimeCallStats stats(clock());
RuntimeCallTimer timer(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
stats.Enter(&timer, test_counter_1_id);
AdvanceClock(50);
stats.Leave(&timer);
EXPECT_EQ(50, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, CountAndTimeAreUpdatedAfterMultipleExecutions) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
const unsigned func_duration = 20;
const unsigned loops = 5;
RuntimeCallStatsTest* test = this;
auto func = [&stats, test]() {
RuntimeCallTimer timer(test->clock());
stats.Enter(&timer, test_counter_1_id);
test->AdvanceClock(func_duration);
stats.Leave(&timer);
};
for (unsigned i = 0; i < loops; i++)
func();
EXPECT_EQ((uint64_t)loops, counter->GetCount());
EXPECT_EQ(loops * func_duration, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, NestedTimersTest) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* outer_counter = stats.GetCounter(test_counter_1_id);
RuntimeCallCounter* inner_counter = stats.GetCounter(test_counter_2_id);
const unsigned inner_func_duration = 50;
const unsigned outer_func_duration = 20;
RuntimeCallStatsTest* test = this;
auto inner_func = [&stats, test]() {
RuntimeCallTimer timer(test->clock());
stats.Enter(&timer, test_counter_2_id);
test->AdvanceClock(inner_func_duration);
stats.Leave(&timer);
};
auto outer_func = [&stats, &inner_func, test]() {
RuntimeCallTimer timer(test->clock());
stats.Enter(&timer, test_counter_1_id);
inner_func();
test->AdvanceClock(outer_func_duration);
stats.Leave(&timer);
};
outer_func();
EXPECT_EQ(1ul, outer_counter->GetCount());
EXPECT_EQ(1ul, inner_counter->GetCount());
EXPECT_EQ(outer_func_duration, outer_counter->GetTime().InMilliseconds());
EXPECT_EQ(inner_func_duration, inner_counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScopeTest) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
RuntimeCallStatsTest* test = this;
auto func = [&stats, test]() {
RuntimeCallTimerScope scope(&stats, test_counter_1_id);
test->AdvanceClock(50);
};
func();
EXPECT_EQ(1ul, counter->GetCount());
EXPECT_EQ(50, counter->GetTime().InMilliseconds());
func();
EXPECT_EQ(2ul, counter->GetCount());
EXPECT_EQ(100, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, RecursiveFunctionWithScopeTest) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
RuntimeCallStatsTest* test = this;
std::function<void(int)> recursive_func;
recursive_func = [&stats, &recursive_func, test](int x) {
RuntimeCallTimerScope scope(&stats, test_counter_1_id);
if (x <= 0)
return;
test->AdvanceClock(50);
recursive_func(x - 1);
};
recursive_func(5);
EXPECT_EQ(6ul, counter->GetCount());
EXPECT_EQ(250, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, ReuseTimer) {
RuntimeCallStats stats(clock());
RuntimeCallTimer timer(clock());
RuntimeCallCounter* counter1 = stats.GetCounter(test_counter_1_id);
RuntimeCallCounter* counter2 = stats.GetCounter(test_counter_2_id);
stats.Enter(&timer, test_counter_1_id);
AdvanceClock(50);
stats.Leave(&timer);
timer.Reset();
stats.Enter(&timer, test_counter_2_id);
AdvanceClock(25);
stats.Leave(&timer);
EXPECT_EQ(1ul, counter1->GetCount());
EXPECT_EQ(1ul, counter2->GetCount());
EXPECT_EQ(50, counter1->GetTime().InMilliseconds());
EXPECT_EQ(25, counter2->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, ResetCallStats) {
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter1 = stats.GetCounter(test_counter_1_id);
RuntimeCallCounter* counter2 = stats.GetCounter(test_counter_2_id);
{
RuntimeCallTimerScope scope1(&stats, test_counter_1_id);
RuntimeCallTimerScope scope2(&stats, test_counter_2_id);
}
EXPECT_EQ(1ul, counter1->GetCount());
EXPECT_EQ(1ul, counter2->GetCount());
stats.Reset();
EXPECT_EQ(0ul, counter1->GetCount());
EXPECT_EQ(0ul, counter2->GetCount());
}
TEST_F(RuntimeCallStatsTest, TestEnterAndLeaveMacrosWithCallStatsDisabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(false);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
RuntimeCallTimer timer(clock());
RUNTIME_CALL_STATS_ENTER_WITH_RCS(&stats, &timer, test_counter_1_id);
AdvanceClock(25);
RUNTIME_CALL_STATS_LEAVE_WITH_RCS(&stats, &timer);
EXPECT_EQ(0ul, counter->GetCount());
EXPECT_EQ(0, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, TestEnterAndLeaveMacrosWithCallStatsEnabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(true);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
RuntimeCallTimer timer(clock());
RUNTIME_CALL_STATS_ENTER_WITH_RCS(&stats, &timer, test_counter_1_id);
AdvanceClock(25);
RUNTIME_CALL_STATS_LEAVE_WITH_RCS(&stats, &timer);
EXPECT_EQ(1ul, counter->GetCount());
EXPECT_EQ(25, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, TestScopeMacroWithCallStatsDisabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(false);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
{
RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(&stats, test_counter_1_id);
AdvanceClock(25);
}
EXPECT_EQ(0ul, counter->GetCount());
EXPECT_EQ(0, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, TestScopeMacroWithCallStatsEnabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(true);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
{
RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(&stats, test_counter_1_id);
AdvanceClock(25);
}
EXPECT_EQ(1ul, counter->GetCount());
EXPECT_EQ(25, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, TestScopeWithOptionalMacroWithCallStatsDisabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(false);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
{
base::Optional<RuntimeCallTimerScope> scope;
RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS(scope, &stats,
test_counter_1_id);
AdvanceClock(25);
}
EXPECT_EQ(0ul, counter->GetCount());
EXPECT_EQ(0, counter->GetTime().InMilliseconds());
}
TEST_F(RuntimeCallStatsTest, TestScopeWithOptionalMacroWithCallStatsEnabled) {
ScopedBlinkRuntimeCallStatsForTest blink_runtime_call_stats(true);
RuntimeCallStats stats(clock());
RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id);
{
base::Optional<RuntimeCallTimerScope> scope;
RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS(scope, &stats,
test_counter_1_id);
AdvanceClock(25);
}
EXPECT_EQ(1ul, counter->GetCount());
EXPECT_EQ(25, counter->GetTime().InMilliseconds());
}
} // namespace blink