v8/test/cctest/test-trace-event.cc
Dan Elphick d1b27019d3 [include] Split out v8.h
This moves every single class/function out of include/v8.h into a
separate header in include/, which v8.h then includes so that
externally nothing appears to have changed.

Every include of v8.h from inside v8 has been changed to a more
fine-grained include.

Previously inline functions defined at the bottom of v8.h would call
private non-inline functions in the V8 class. Since that class is now
in v8-initialization.h and is rarely included (as that would create
dependency cycles), this is not possible and so those methods have been
moved out of the V8 class into the namespace v8::api_internal.

None of the previous files in include/ now #include v8.h, which means
if embedders were relying on this transitive dependency then it will
give compile failures.

v8-inspector.h does depend on v8-scripts.h for the time being to ensure
that Chrome continue to compile but that change will be reverted once
those transitive #includes in chrome are changed to include it directly.

Full design:
https://docs.google.com/document/d/1rTD--I8hCAr-Rho1WTumZzFKaDpEp0IJ8ejZtk4nJdA/edit?usp=sharing

Bug: v8:11965
Change-Id: I53b84b29581632710edc80eb11f819c2097a2877
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3097448
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76424}
2021-08-23 09:35:06 +00:00

387 lines
13 KiB
C++

// 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 "include/v8-function.h"
#include "src/init/v8.h"
#include "src/tracing/trace-event.h"
#include "test/cctest/cctest.h"
namespace {
struct MockTraceObject {
char phase;
std::string name;
uint64_t id;
uint64_t bind_id;
int num_args;
unsigned int flags;
int64_t timestamp;
MockTraceObject(char phase, std::string name, uint64_t id, uint64_t bind_id,
int num_args, int flags, int64_t timestamp)
: phase(phase),
name(name),
id(id),
bind_id(bind_id),
num_args(num_args),
flags(flags),
timestamp(timestamp) {}
};
class MockTracingController : public v8::TracingController {
public:
MockTracingController() = default;
MockTracingController(const MockTracingController&) = delete;
MockTracingController& operator=(const MockTracingController&) = delete;
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 {
return AddTraceEventWithTimestamp(
phase, category_enabled_flag, name, scope, id, bind_id, num_args,
arg_names, arg_types, arg_values, arg_convertables, flags, 0);
}
uint64_t AddTraceEventWithTimestamp(
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, int64_t timestamp) override {
std::unique_ptr<MockTraceObject> to = std::make_unique<MockTraceObject>(
phase, std::string(name), id, bind_id, num_args, flags, timestamp);
trace_objects_.push_back(std::move(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 (strncmp(name, "v8-cat", 6)) {
static uint8_t no = 0;
return &no;
} else {
static uint8_t yes = 0x7;
return &yes;
}
}
const std::vector<std::unique_ptr<MockTraceObject>>& GetMockTraceObjects()
const {
return trace_objects_;
}
private:
std::vector<std::unique_ptr<MockTraceObject>> trace_objects_;
};
class MockTracingPlatform : public TestPlatform {
public:
MockTracingPlatform() {
// Now that it's completely constructed, make this the current platform.
i::V8::SetPlatformForTesting(this);
}
~MockTracingPlatform() override = default;
v8::TracingController* GetTracingController() override {
return &tracing_controller_;
}
size_t NumberOfTraceObjects() {
return tracing_controller_.GetMockTraceObjects().size();
}
MockTraceObject* GetTraceObject(size_t index) {
return tracing_controller_.GetMockTraceObjects().at(index).get();
}
private:
MockTracingController tracing_controller_;
};
} // namespace
TEST(TraceEventDisabledCategory) {
MockTracingPlatform platform;
// Disabled category, will not add events.
TRACE_EVENT_BEGIN0("cat", "e1");
TRACE_EVENT_END0("cat", "e1");
CHECK_EQ(0, platform.NumberOfTraceObjects());
}
TEST(TraceEventNoArgs) {
MockTracingPlatform platform;
// Enabled category will add 2 events.
TRACE_EVENT_BEGIN0("v8-cat", "e1");
TRACE_EVENT_END0("v8-cat", "e1");
CHECK_EQ(2, platform.NumberOfTraceObjects());
CHECK_EQ('B', platform.GetTraceObject(0)->phase);
CHECK_EQ("e1", platform.GetTraceObject(0)->name);
CHECK_EQ(0, platform.GetTraceObject(0)->num_args);
CHECK_EQ('E', platform.GetTraceObject(1)->phase);
CHECK_EQ("e1", platform.GetTraceObject(1)->name);
CHECK_EQ(0, platform.GetTraceObject(1)->num_args);
}
TEST(TraceEventWithOneArg) {
MockTracingPlatform 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, platform.NumberOfTraceObjects());
CHECK_EQ(1, platform.GetTraceObject(0)->num_args);
CHECK_EQ(1, platform.GetTraceObject(1)->num_args);
CHECK_EQ(1, platform.GetTraceObject(2)->num_args);
CHECK_EQ(1, platform.GetTraceObject(3)->num_args);
}
TEST(TraceEventWithTwoArgs) {
MockTracingPlatform 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, platform.NumberOfTraceObjects());
CHECK_EQ(2, platform.GetTraceObject(0)->num_args);
CHECK_EQ(2, platform.GetTraceObject(1)->num_args);
CHECK_EQ(2, platform.GetTraceObject(2)->num_args);
CHECK_EQ(2, platform.GetTraceObject(3)->num_args);
}
TEST(ScopedTraceEvent) {
MockTracingPlatform platform;
{ TRACE_EVENT0("v8-cat", "e"); }
CHECK_EQ(1, platform.NumberOfTraceObjects());
CHECK_EQ(0, platform.GetTraceObject(0)->num_args);
{ TRACE_EVENT1("v8-cat", "e1", "arg1", "abc"); }
CHECK_EQ(2, platform.NumberOfTraceObjects());
CHECK_EQ(1, platform.GetTraceObject(1)->num_args);
{ TRACE_EVENT2("v8-cat", "e1", "arg1", "abc", "arg2", 42); }
CHECK_EQ(3, platform.NumberOfTraceObjects());
CHECK_EQ(2, platform.GetTraceObject(2)->num_args);
}
TEST(TestEventWithFlow) {
MockTracingPlatform 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, platform.NumberOfTraceObjects());
CHECK_EQ(bind_id, platform.GetTraceObject(0)->bind_id);
CHECK_EQ(TRACE_EVENT_FLAG_FLOW_OUT, platform.GetTraceObject(0)->flags);
CHECK_EQ(bind_id, platform.GetTraceObject(1)->bind_id);
CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
platform.GetTraceObject(1)->flags);
CHECK_EQ(bind_id, platform.GetTraceObject(2)->bind_id);
CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN, platform.GetTraceObject(2)->flags);
}
TEST(TestEventWithId) {
MockTracingPlatform 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, platform.NumberOfTraceObjects());
CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, platform.GetTraceObject(0)->phase);
CHECK_EQ(event_id, platform.GetTraceObject(0)->id);
CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_END, platform.GetTraceObject(1)->phase);
CHECK_EQ(event_id, platform.GetTraceObject(1)->id);
}
TEST(TestEventWithTimestamp) {
MockTracingPlatform platform;
TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("v8-cat", "0arg",
TRACE_EVENT_SCOPE_GLOBAL, 1729);
TRACE_EVENT_INSTANT_WITH_TIMESTAMP1("v8-cat", "1arg",
TRACE_EVENT_SCOPE_GLOBAL, 4104, "val", 1);
TRACE_EVENT_MARK_WITH_TIMESTAMP2("v8-cat", "mark", 13832, "a", 1, "b", 2);
TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0("v8-cat", "begin", 5,
20683);
TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0("v8-cat", "end", 5,
32832);
CHECK_EQ(5, platform.NumberOfTraceObjects());
CHECK_EQ(1729, platform.GetTraceObject(0)->timestamp);
CHECK_EQ(0, platform.GetTraceObject(0)->num_args);
CHECK_EQ(4104, platform.GetTraceObject(1)->timestamp);
CHECK_EQ(1, platform.GetTraceObject(1)->num_args);
CHECK_EQ(13832, platform.GetTraceObject(2)->timestamp);
CHECK_EQ(2, platform.GetTraceObject(2)->num_args);
CHECK_EQ(20683, platform.GetTraceObject(3)->timestamp);
CHECK_EQ(32832, platform.GetTraceObject(4)->timestamp);
}
TEST(BuiltinsIsTraceCategoryEnabled) {
CcTest::InitializeVM();
MockTracingPlatform platform;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
CHECK(!binding.IsEmpty());
auto undefined = v8::Undefined(isolate);
auto isTraceCategoryEnabled =
binding->Get(env.local(), v8_str("isTraceCategoryEnabled"))
.ToLocalChecked()
.As<v8::Function>();
{
// Test with an enabled category
v8::Local<v8::Value> argv[] = {v8_str("v8-cat")};
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(result->BooleanValue(isolate));
}
{
// Test with a disabled category
v8::Local<v8::Value> argv[] = {v8_str("cat")};
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(!result->BooleanValue(isolate));
}
{
// Test with an enabled utf8 category
v8::Local<v8::Value> argv[] = {v8_str("v8-cat\u20ac")};
auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(result->BooleanValue(isolate));
}
}
TEST(BuiltinsTrace) {
CcTest::InitializeVM();
MockTracingPlatform platform;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
CHECK(!binding.IsEmpty());
auto undefined = v8::Undefined(isolate);
auto trace = binding->Get(env.local(), v8_str("trace"))
.ToLocalChecked()
.As<v8::Function>();
// Test with disabled category
{
v8::Local<v8::String> category = v8_str("cat");
v8::Local<v8::String> name = v8_str("name");
v8::Local<v8::Value> argv[] = {
v8::Integer::New(isolate, 'b'), // phase
category, name, v8::Integer::New(isolate, 0), // id
undefined // data
};
auto result = trace->Call(env.local(), undefined, 5, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(!result->BooleanValue(isolate));
CHECK_EQ(0, platform.NumberOfTraceObjects());
}
// Test with enabled category
{
v8::Local<v8::String> category = v8_str("v8-cat");
v8::Local<v8::String> name = v8_str("name");
v8::Local<v8::Object> data = v8::Object::New(isolate);
data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
v8::Local<v8::Value> argv[] = {
v8::Integer::New(isolate, 'b'), // phase
category, name, v8::Integer::New(isolate, 123), // id
data // data arg
};
auto result = trace->Call(env.local(), undefined, 5, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(result->BooleanValue(isolate));
CHECK_EQ(1, platform.NumberOfTraceObjects());
CHECK_EQ(123, platform.GetTraceObject(0)->id);
CHECK_EQ('b', platform.GetTraceObject(0)->phase);
CHECK_EQ("name", platform.GetTraceObject(0)->name);
CHECK_EQ(1, platform.GetTraceObject(0)->num_args);
}
// Test with enabled utf8 category
{
v8::Local<v8::String> category = v8_str("v8-cat\u20ac");
v8::Local<v8::String> name = v8_str("name\u20ac");
v8::Local<v8::Object> data = v8::Object::New(isolate);
data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
v8::Local<v8::Value> argv[] = {
v8::Integer::New(isolate, 'b'), // phase
category, name, v8::Integer::New(isolate, 123), // id
data // data arg
};
auto result = trace->Call(env.local(), undefined, 5, argv)
.ToLocalChecked()
.As<v8::Boolean>();
CHECK(result->BooleanValue(isolate));
CHECK_EQ(2, platform.NumberOfTraceObjects());
CHECK_EQ(123, platform.GetTraceObject(1)->id);
CHECK_EQ('b', platform.GetTraceObject(1)->phase);
CHECK_EQ("name\u20ac", platform.GetTraceObject(1)->name);
CHECK_EQ(1, platform.GetTraceObject(1)->num_args);
}
}