// Copyright 2015 the V8 project 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 <stdlib.h> #include <string.h> #include "src/v8.h" #include "src/list.h" #include "src/list-inl.h" #include "test/cctest/cctest.h" using v8::IdleTask; using v8::Task; using v8::Isolate; #include "src/tracing/trace-event.h" #define GET_TRACE_OBJECTS_LIST platform.GetMockTraceObjects() #define GET_TRACE_OBJECT(Index) GET_TRACE_OBJECTS_LIST->at(Index) struct MockTraceObject { char phase; std::string name; uint64_t id; uint64_t bind_id; int num_args; unsigned int flags; MockTraceObject(char phase, std::string name, uint64_t id, uint64_t bind_id, int num_args, int flags) : phase(phase), name(name), id(id), bind_id(bind_id), num_args(num_args), flags(flags) {} }; typedef v8::internal::List<MockTraceObject*> MockTraceObjectList; class MockTracingController : public v8::TracingController { public: MockTracingController() = default; ~MockTracingController() { for (int i = 0; i < trace_object_list_.length(); ++i) { delete trace_object_list_[i]; } trace_object_list_.Clear(); } uint64_t AddTraceEvent( char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, unsigned int flags) override { MockTraceObject* to = new MockTraceObject(phase, std::string(name), id, bind_id, num_args, flags); trace_object_list_.Add(to); return 0; } void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, const char* name, uint64_t handle) override {} const uint8_t* GetCategoryGroupEnabled(const char* name) override { if (strcmp(name, "v8-cat")) { static uint8_t no = 0; return &no; } else { static uint8_t yes = 0x7; return &yes; } } MockTraceObjectList* GetMockTraceObjects() { return &trace_object_list_; } private: MockTraceObjectList trace_object_list_; DISALLOW_COPY_AND_ASSIGN(MockTracingController); }; class MockTracingPlatform : public v8::Platform { public: explicit MockTracingPlatform(v8::Platform* platform) {} virtual ~MockTracingPlatform() {} void CallOnBackgroundThread(Task* task, ExpectedRuntime expected_runtime) override {} void CallOnForegroundThread(Isolate* isolate, Task* task) override {} void CallDelayedOnForegroundThread(Isolate* isolate, Task* task, double delay_in_seconds) override {} double MonotonicallyIncreasingTime() override { return 0.0; } void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {} bool IdleTasksEnabled(Isolate* isolate) override { return false; } v8::TracingController* GetTracingController() override { return &tracing_controller_; } bool PendingIdleTask() { return false; } void PerformIdleTask(double idle_time_in_seconds) {} bool PendingDelayedTask() { return false; } void PerformDelayedTask() {} MockTraceObjectList* GetMockTraceObjects() { return tracing_controller_.GetMockTraceObjects(); } private: MockTracingController tracing_controller_; DISALLOW_COPY_AND_ASSIGN(MockTracingPlatform); }; TEST(TraceEventDisabledCategory) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); // Disabled category, will not add events. TRACE_EVENT_BEGIN0("cat", "e1"); TRACE_EVENT_END0("cat", "e1"); CHECK_EQ(0, GET_TRACE_OBJECTS_LIST->length()); i::V8::SetPlatformForTesting(old_platform); } TEST(TraceEventNoArgs) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); // Enabled category will add 2 events. TRACE_EVENT_BEGIN0("v8-cat", "e1"); TRACE_EVENT_END0("v8-cat", "e1"); CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ('B', GET_TRACE_OBJECT(0)->phase); CHECK_EQ("e1", GET_TRACE_OBJECT(0)->name); CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args); CHECK_EQ('E', GET_TRACE_OBJECT(1)->phase); CHECK_EQ("e1", GET_TRACE_OBJECT(1)->name); CHECK_EQ(0, GET_TRACE_OBJECT(1)->num_args); i::V8::SetPlatformForTesting(old_platform); } TEST(TraceEventWithOneArg) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); TRACE_EVENT_BEGIN1("v8-cat", "e1", "arg1", 42); TRACE_EVENT_END1("v8-cat", "e1", "arg1", 42); TRACE_EVENT_BEGIN1("v8-cat", "e2", "arg1", "abc"); TRACE_EVENT_END1("v8-cat", "e2", "arg1", "abc"); CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args); CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args); CHECK_EQ(1, GET_TRACE_OBJECT(2)->num_args); CHECK_EQ(1, GET_TRACE_OBJECT(3)->num_args); i::V8::SetPlatformForTesting(old_platform); } TEST(TraceEventWithTwoArgs) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); TRACE_EVENT_BEGIN2("v8-cat", "e1", "arg1", 42, "arg2", "abc"); TRACE_EVENT_END2("v8-cat", "e1", "arg1", 42, "arg2", "abc"); TRACE_EVENT_BEGIN2("v8-cat", "e2", "arg1", "abc", "arg2", 43); TRACE_EVENT_END2("v8-cat", "e2", "arg1", "abc", "arg2", 43); CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(2, GET_TRACE_OBJECT(0)->num_args); CHECK_EQ(2, GET_TRACE_OBJECT(1)->num_args); CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args); CHECK_EQ(2, GET_TRACE_OBJECT(3)->num_args); i::V8::SetPlatformForTesting(old_platform); } TEST(ScopedTraceEvent) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); { TRACE_EVENT0("v8-cat", "e"); } CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args); { TRACE_EVENT1("v8-cat", "e1", "arg1", "abc"); } CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args); { TRACE_EVENT2("v8-cat", "e1", "arg1", "abc", "arg2", 42); } CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args); i::V8::SetPlatformForTesting(old_platform); } TEST(TestEventWithFlow) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); static uint64_t bind_id = 21; { TRACE_EVENT_WITH_FLOW0("v8-cat", "f1", bind_id, TRACE_EVENT_FLAG_FLOW_OUT); } { TRACE_EVENT_WITH_FLOW0( "v8-cat", "f2", bind_id, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); } { TRACE_EVENT_WITH_FLOW0("v8-cat", "f3", bind_id, TRACE_EVENT_FLAG_FLOW_IN); } CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(bind_id, GET_TRACE_OBJECT(0)->bind_id); CHECK_EQ(TRACE_EVENT_FLAG_FLOW_OUT, GET_TRACE_OBJECT(0)->flags); CHECK_EQ(bind_id, GET_TRACE_OBJECT(1)->bind_id); CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, GET_TRACE_OBJECT(1)->flags); CHECK_EQ(bind_id, GET_TRACE_OBJECT(2)->bind_id); CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN, GET_TRACE_OBJECT(2)->flags); i::V8::SetPlatformForTesting(old_platform); } TEST(TestEventWithId) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); static uint64_t event_id = 21; TRACE_EVENT_ASYNC_BEGIN0("v8-cat", "a1", event_id); TRACE_EVENT_ASYNC_END0("v8-cat", "a1", event_id); CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, GET_TRACE_OBJECT(0)->phase); CHECK_EQ(event_id, GET_TRACE_OBJECT(0)->id); CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_END, GET_TRACE_OBJECT(1)->phase); CHECK_EQ(event_id, GET_TRACE_OBJECT(1)->id); i::V8::SetPlatformForTesting(old_platform); } TEST(TestEventInContext) { v8::Platform* old_platform = i::V8::GetCurrentPlatform(); MockTracingPlatform platform(old_platform); i::V8::SetPlatformForTesting(&platform); static uint64_t isolate_id = 0x20151021; { TRACE_EVENT_SCOPED_CONTEXT("v8-cat", "Isolate", isolate_id); TRACE_EVENT0("v8-cat", "e"); } CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->length()); CHECK_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, GET_TRACE_OBJECT(0)->phase); CHECK_EQ("Isolate", GET_TRACE_OBJECT(0)->name); CHECK_EQ(isolate_id, GET_TRACE_OBJECT(0)->id); CHECK_EQ(TRACE_EVENT_PHASE_COMPLETE, GET_TRACE_OBJECT(1)->phase); CHECK_EQ("e", GET_TRACE_OBJECT(1)->name); CHECK_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, GET_TRACE_OBJECT(2)->phase); CHECK_EQ("Isolate", GET_TRACE_OBJECT(2)->name); CHECK_EQ(isolate_id, GET_TRACE_OBJECT(2)->id); i::V8::SetPlatformForTesting(old_platform); }