|
|
|
@ -10,6 +10,8 @@
|
|
|
|
|
#include "src/handles-inl.h"
|
|
|
|
|
#include "src/objects-inl.h"
|
|
|
|
|
#include "src/tracing/tracing-category-observer.h"
|
|
|
|
|
|
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
@ -44,50 +46,103 @@ class AggregatedMemoryHistogramTest : public ::testing::Test {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static base::TimeTicks runtime_call_stats_test_time_ = base::TimeTicks();
|
|
|
|
|
// Time source used for the RuntimeCallTimer during tests. We cannot rely on
|
|
|
|
|
// the native timer since it's too unpredictable on the build bots.
|
|
|
|
|
static base::TimeTicks RuntimeCallStatsTestNow() {
|
|
|
|
|
return runtime_call_stats_test_time_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class RuntimeCallStatsTest : public ::testing::Test {
|
|
|
|
|
class RuntimeCallStatsTest : public TestWithNativeContext {
|
|
|
|
|
public:
|
|
|
|
|
RuntimeCallStatsTest() {
|
|
|
|
|
FLAG_runtime_stats =
|
|
|
|
|
v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE;
|
|
|
|
|
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
|
|
|
|
|
// We need to set {time_} to a non-zero value since it would otherwise
|
|
|
|
|
// cause runtime call timers to think they are uninitialized.
|
|
|
|
|
Sleep(1);
|
|
|
|
|
stats()->Reset();
|
|
|
|
|
}
|
|
|
|
|
virtual ~RuntimeCallStatsTest() {
|
|
|
|
|
|
|
|
|
|
~RuntimeCallStatsTest() {
|
|
|
|
|
// Disable RuntimeCallStats before tearing down the isolate to prevent
|
|
|
|
|
// printing the tests table. Comment the following line for debugging
|
|
|
|
|
// purposes.
|
|
|
|
|
FLAG_runtime_stats = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void SetUpTestCase() {
|
|
|
|
|
TestWithIsolate::SetUpTestCase();
|
|
|
|
|
// Use a custom time source to precisly emulate system time.
|
|
|
|
|
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TearDownTestCase() {
|
|
|
|
|
TestWithIsolate::TearDownTestCase();
|
|
|
|
|
// Restore the original time source.
|
|
|
|
|
RuntimeCallTimer::Now = &base::TimeTicks::HighResolutionNow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RuntimeCallStats* stats() { return &stats_; }
|
|
|
|
|
RuntimeCallStats* stats() {
|
|
|
|
|
return isolate()->counters()->runtime_call_stats();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print current RuntimeCallStats table. For debugging purposes.
|
|
|
|
|
void PrintStats() { stats()->Print(); }
|
|
|
|
|
|
|
|
|
|
RuntimeCallStats::CounterId counter_id() {
|
|
|
|
|
return &RuntimeCallStats::TestCounter1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RuntimeCallStats::CounterId counter_id2() {
|
|
|
|
|
return &RuntimeCallStats::TestCounter2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RuntimeCallStats::CounterId counter_id3() {
|
|
|
|
|
return &RuntimeCallStats::TestCounter3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RuntimeCallCounter* js_counter() { return &stats()->JS_Execution; }
|
|
|
|
|
RuntimeCallCounter* counter() { return &(stats()->*counter_id()); }
|
|
|
|
|
RuntimeCallCounter* counter2() { return &(stats()->*counter_id2()); }
|
|
|
|
|
RuntimeCallCounter* counter3() { return &(stats()->*counter_id3()); }
|
|
|
|
|
|
|
|
|
|
void Sleep(int32_t milliseconds) {
|
|
|
|
|
base::TimeDelta delta = base::TimeDelta::FromMilliseconds(milliseconds);
|
|
|
|
|
void Sleep(int64_t microseconds) {
|
|
|
|
|
base::TimeDelta delta = base::TimeDelta::FromMicroseconds(microseconds);
|
|
|
|
|
time_ += delta;
|
|
|
|
|
runtime_call_stats_test_time_ =
|
|
|
|
|
base::TimeTicks::FromInternalValue(time_.InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
RuntimeCallStats stats_;
|
|
|
|
|
base::TimeDelta time_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Temporarily use the native time to modify the test time.
|
|
|
|
|
class ElapsedTimeScope {
|
|
|
|
|
public:
|
|
|
|
|
explicit ElapsedTimeScope(RuntimeCallStatsTest* test) : test_(test) {
|
|
|
|
|
timer_.Start();
|
|
|
|
|
}
|
|
|
|
|
~ElapsedTimeScope() { test_->Sleep(timer_.Elapsed().InMicroseconds()); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
base::ElapsedTimer timer_;
|
|
|
|
|
RuntimeCallStatsTest* test_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Temporarily use the default time source.
|
|
|
|
|
class NativeTimeScope {
|
|
|
|
|
public:
|
|
|
|
|
NativeTimeScope() {
|
|
|
|
|
CHECK_EQ(RuntimeCallTimer::Now, &RuntimeCallStatsTestNow);
|
|
|
|
|
RuntimeCallTimer::Now = &base::TimeTicks::HighResolutionNow;
|
|
|
|
|
}
|
|
|
|
|
~NativeTimeScope() {
|
|
|
|
|
CHECK_EQ(RuntimeCallTimer::Now, &base::TimeTicks::HighResolutionNow);
|
|
|
|
|
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -257,7 +312,7 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimer) {
|
|
|
|
|
Sleep(50);
|
|
|
|
|
EXPECT_FALSE(timer.IsStarted());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
|
|
|
|
@ -290,8 +345,8 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
|
|
|
|
|
EXPECT_FALSE(timer2.IsStarted());
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(&timer, stats()->current_timer());
|
|
|
|
|
|
|
|
|
|
Sleep(100);
|
|
|
|
@ -300,8 +355,8 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
|
|
|
|
|
EXPECT_FALSE(timer.IsStarted());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(150, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(150, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(nullptr, stats()->current_timer());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -329,14 +384,14 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerRecursive) {
|
|
|
|
|
EXPECT_FALSE(timer2.IsStarted());
|
|
|
|
|
EXPECT_TRUE(timer.IsStarted());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
Sleep(100);
|
|
|
|
|
|
|
|
|
|
RuntimeCallStats::Leave(stats(), &timer);
|
|
|
|
|
EXPECT_FALSE(timer.IsStarted());
|
|
|
|
|
EXPECT_EQ(2, counter()->count());
|
|
|
|
|
EXPECT_EQ(150, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(150, counter()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScope) {
|
|
|
|
@ -346,13 +401,13 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScope) {
|
|
|
|
|
}
|
|
|
|
|
Sleep(100);
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMicroseconds());
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(2, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScopeRecursive) {
|
|
|
|
@ -360,16 +415,16 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScopeRecursive) {
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMicroseconds());
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(2, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, RenameTimer) {
|
|
|
|
@ -378,8 +433,8 @@ TEST_F(RuntimeCallStatsTest, RenameTimer) {
|
|
|
|
|
Sleep(50);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMicroseconds());
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(100);
|
|
|
|
@ -387,13 +442,13 @@ TEST_F(RuntimeCallStatsTest, RenameTimer) {
|
|
|
|
|
CHANGE_CURRENT_RUNTIME_COUNTER(stats(), TestCounter2);
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
|
|
|
|
@ -402,9 +457,9 @@ TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(0, counter3()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter3()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter3()->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
@ -415,9 +470,9 @@ TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(0, counter3()->count());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter3()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, counter3()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
|
|
|
|
@ -425,11 +480,11 @@ TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(100);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter()->time().InMicroseconds());
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id2());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(0, counter2()->time().InMicroseconds());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
|
|
|
|
|
// This calls Snapshot on the current active timer and sychronizes and
|
|
|
|
@ -438,35 +493,35 @@ TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
|
|
|
|
|
stats()->Print(out);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMicroseconds());
|
|
|
|
|
// Calling Print several times shouldn't have a (big) impact on the
|
|
|
|
|
// measured times.
|
|
|
|
|
stats()->Print(out);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(50, counter2()->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
Sleep(50);
|
|
|
|
|
stats()->Print(out);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(100, counter2()->time().InMicroseconds());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
}
|
|
|
|
|
Sleep(50);
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(150, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(150, counter2()->time().InMicroseconds());
|
|
|
|
|
Sleep(50);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(200, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(150, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(200, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(150, counter2()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, NestedScopes) {
|
|
|
|
@ -497,9 +552,124 @@ TEST_F(RuntimeCallStatsTest, NestedScopes) {
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(2, counter2()->count());
|
|
|
|
|
EXPECT_EQ(2, counter3()->count());
|
|
|
|
|
EXPECT_EQ(250, counter()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(300, counter2()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(100, counter3()->time().InMilliseconds());
|
|
|
|
|
EXPECT_EQ(250, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(300, counter2()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(100, counter3()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, BasicJavaScript) {
|
|
|
|
|
RuntimeCallCounter* counter = &stats()->JS_Execution;
|
|
|
|
|
EXPECT_EQ(0, counter->count());
|
|
|
|
|
EXPECT_EQ(0, counter->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
NativeTimeScope native_timer_scope;
|
|
|
|
|
RunJS("function f() { return 1; }");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, counter->count());
|
|
|
|
|
int64_t time = counter->time().InMicroseconds();
|
|
|
|
|
EXPECT_LT(0, time);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
NativeTimeScope native_timer_scope;
|
|
|
|
|
RunJS("f()");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(2, counter->count());
|
|
|
|
|
EXPECT_LE(time, counter->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, FunctionLengthGetter) {
|
|
|
|
|
RuntimeCallCounter* getter_counter = &stats()->FunctionLengthGetter;
|
|
|
|
|
RuntimeCallCounter* js_counter = &stats()->JS_Execution;
|
|
|
|
|
EXPECT_EQ(0, getter_counter->count());
|
|
|
|
|
EXPECT_EQ(0, js_counter->count());
|
|
|
|
|
EXPECT_EQ(0, getter_counter->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(0, js_counter->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
NativeTimeScope native_timer_scope;
|
|
|
|
|
RunJS("function f(array) { return array.length; }");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(0, getter_counter->count());
|
|
|
|
|
EXPECT_EQ(1, js_counter->count());
|
|
|
|
|
EXPECT_EQ(0, getter_counter->time().InMicroseconds());
|
|
|
|
|
int64_t js_time = js_counter->time().InMicroseconds();
|
|
|
|
|
EXPECT_LT(0, js_time);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
NativeTimeScope native_timer_scope;
|
|
|
|
|
RunJS("f.length");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, getter_counter->count());
|
|
|
|
|
EXPECT_EQ(2, js_counter->count());
|
|
|
|
|
EXPECT_LE(0, getter_counter->time().InMicroseconds());
|
|
|
|
|
EXPECT_LT(js_time, js_counter->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
NativeTimeScope native_timer_scope;
|
|
|
|
|
RunJS("for (let i = 0; i < 50; i++) { f.length }");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(51, getter_counter->count());
|
|
|
|
|
EXPECT_EQ(3, js_counter->count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
static RuntimeCallStatsTest* current_test;
|
|
|
|
|
static const int kCustomCallbackTime = 1234;
|
|
|
|
|
static void CustomCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
|
|
|
RuntimeCallTimerScope scope(current_test->stats(),
|
|
|
|
|
current_test->counter_id2());
|
|
|
|
|
current_test->Sleep(kCustomCallbackTime);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
TEST_F(RuntimeCallStatsTest, CustomCallback) {
|
|
|
|
|
current_test = this;
|
|
|
|
|
// Set up a function template with a custom callback.
|
|
|
|
|
v8::Isolate* isolate = v8_isolate();
|
|
|
|
|
v8::HandleScope scope(isolate);
|
|
|
|
|
|
|
|
|
|
v8::Local<v8::ObjectTemplate> object_template =
|
|
|
|
|
v8::ObjectTemplate::New(isolate);
|
|
|
|
|
object_template->Set(isolate, "callback",
|
|
|
|
|
v8::FunctionTemplate::New(isolate, CustomCallback));
|
|
|
|
|
v8::Local<v8::Object> object =
|
|
|
|
|
object_template->NewInstance(v8_context()).ToLocalChecked();
|
|
|
|
|
SetGlobalProperty("custom_object", object);
|
|
|
|
|
|
|
|
|
|
// TODO(cbruni): Check api accessor timer (one above the custom callback).
|
|
|
|
|
EXPECT_EQ(0, js_counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter()->count());
|
|
|
|
|
EXPECT_EQ(0, counter2()->count());
|
|
|
|
|
{
|
|
|
|
|
RuntimeCallTimerScope scope(stats(), counter_id());
|
|
|
|
|
Sleep(100);
|
|
|
|
|
RunJS("custom_object.callback();");
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(1, js_counter()->count());
|
|
|
|
|
// Given that no native timers are used, only the two scopes explitly
|
|
|
|
|
// mentioned above will track the time.
|
|
|
|
|
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(1, counter2()->count());
|
|
|
|
|
EXPECT_EQ(kCustomCallbackTime, counter2()->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
RunJS("for (let i = 0; i < 9; i++) { custom_object.callback() };");
|
|
|
|
|
EXPECT_EQ(2, js_counter()->count());
|
|
|
|
|
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(10, counter2()->count());
|
|
|
|
|
EXPECT_EQ(kCustomCallbackTime * 10, counter2()->time().InMicroseconds());
|
|
|
|
|
|
|
|
|
|
RunJS("for (let i = 0; i < 4000; i++) { custom_object.callback() };");
|
|
|
|
|
EXPECT_EQ(3, js_counter()->count());
|
|
|
|
|
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(1, counter()->count());
|
|
|
|
|
EXPECT_EQ(100, counter()->time().InMicroseconds());
|
|
|
|
|
EXPECT_EQ(4010, counter2()->count());
|
|
|
|
|
EXPECT_EQ(kCustomCallbackTime * 4010, counter2()->time().InMicroseconds());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|