PR-URL: https://github.com/nodejs/node/pull/58070 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
227 lines
8.0 KiB
C++
227 lines
8.0 KiB
C++
// Copyright 2024 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 "include/v8-context.h"
|
|
#include "include/v8-fast-api-calls.h"
|
|
#include "include/v8-internal.h"
|
|
#include "include/v8-local-handle.h"
|
|
#include "include/v8-persistent-handle.h"
|
|
#include "include/v8-template.h"
|
|
#include "src/base/macros.h"
|
|
#include "test/benchmarks/cpp/benchmark-utils.h"
|
|
#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h"
|
|
|
|
namespace {
|
|
|
|
v8::Local<v8::String> v8_str(const char* x) {
|
|
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x).ToLocalChecked();
|
|
}
|
|
|
|
class FastApiBenchmark : public v8::benchmarking::BenchmarkWithIsolate {
|
|
public:
|
|
static void RegularCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
}
|
|
|
|
static void FastCallback(v8::Local<v8::Value> receiver,
|
|
v8::FastApiCallbackOptions& options) {}
|
|
|
|
static uint32_t FastStringValueView(v8::Local<v8::Value> receiver,
|
|
v8::Local<v8::Value> value,
|
|
v8::FastApiCallbackOptions& options) {
|
|
v8::Local<v8::String> str = value.As<v8::String>();
|
|
v8::String::ValueView view(options.isolate, str);
|
|
return view.length();
|
|
}
|
|
|
|
static uint32_t FastOneByteString(v8::Local<v8::Value> receiver,
|
|
const v8::FastOneByteString& str,
|
|
v8::FastApiCallbackOptions& options) {
|
|
return str.length;
|
|
}
|
|
|
|
static void RegularString(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
v8::Local<v8::String> str = info[0].As<v8::String>();
|
|
v8::String::ValueView view(info.GetIsolate(), str);
|
|
info.GetReturnValue().Set(view.length());
|
|
}
|
|
|
|
void SetUp(::benchmark::State& state) override {
|
|
auto* isolate = v8_isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
auto proxy_template_function = v8::FunctionTemplate::New(isolate);
|
|
auto object_template = proxy_template_function->InstanceTemplate();
|
|
{
|
|
v8::CFunction fast_callback =
|
|
v8::CFunction::Make(FastApiBenchmark::FastCallback);
|
|
|
|
object_template->Set(
|
|
isolate, "fastApiCall",
|
|
v8::FunctionTemplate::New(
|
|
isolate, FastApiBenchmark::RegularCallback,
|
|
v8::Local<v8::Value>(), v8::Local<v8::Signature>(), 1,
|
|
v8::ConstructorBehavior::kThrow,
|
|
v8::SideEffectType::kHasSideEffect, &fast_callback));
|
|
}
|
|
{
|
|
object_template->Set(isolate, "regularApiCall",
|
|
v8::FunctionTemplate::New(
|
|
isolate, FastApiBenchmark::RegularCallback));
|
|
}
|
|
{
|
|
v8::CFunction fast_callback =
|
|
v8::CFunction::Make(FastApiBenchmark::FastOneByteString);
|
|
|
|
object_template->Set(
|
|
isolate, "fastOneByteString",
|
|
v8::FunctionTemplate::New(
|
|
isolate, FastApiBenchmark::RegularString, v8::Local<v8::Value>(),
|
|
v8::Local<v8::Signature>(), 1, v8::ConstructorBehavior::kThrow,
|
|
v8::SideEffectType::kHasSideEffect, &fast_callback));
|
|
}
|
|
{
|
|
v8::CFunction fast_callback =
|
|
v8::CFunction::Make(FastApiBenchmark::FastStringValueView);
|
|
|
|
object_template->Set(
|
|
isolate, "fastStringValueView",
|
|
v8::FunctionTemplate::New(
|
|
isolate, FastApiBenchmark::RegularString, v8::Local<v8::Value>(),
|
|
v8::Local<v8::Signature>(), 1, v8::ConstructorBehavior::kThrow,
|
|
v8::SideEffectType::kHasSideEffect, &fast_callback));
|
|
}
|
|
{
|
|
object_template->Set(
|
|
isolate, "regularString",
|
|
v8::FunctionTemplate::New(isolate, FastApiBenchmark::RegularString));
|
|
}
|
|
|
|
v8::Local<v8::Context> context =
|
|
v8::Context::New(isolate, nullptr, object_template);
|
|
|
|
context_.Reset(isolate, context);
|
|
context->Enter();
|
|
}
|
|
|
|
void TearDown(::benchmark::State& state) override {
|
|
auto* isolate = v8_isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
auto context = context_.Get(isolate);
|
|
context->Exit();
|
|
context_.Reset();
|
|
}
|
|
|
|
v8::Local<v8::Script> CompileBenchmarkScript(const char* source) {
|
|
v8::EscapableHandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::String> v8_source = v8_str(source);
|
|
v8::Local<v8::Script> script =
|
|
v8::Script::Compile(context, v8_source).ToLocalChecked();
|
|
return handle_scope.Escape(script);
|
|
}
|
|
|
|
protected:
|
|
v8::Local<v8::Context> v8_context() { return context_.Get(v8_isolate()); }
|
|
|
|
v8::Global<v8::Context> context_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
BENCHMARK_F(FastApiBenchmark, FastCallToEmptyCallback)(benchmark::State& st) {
|
|
const char* kScript =
|
|
"function invoke() { globalThis.fastApiCall(); }"
|
|
"\%PrepareFunctionForOptimization(invoke);"
|
|
"invoke();"
|
|
"\%OptimizeFunctionOnNextCall(invoke);"
|
|
"for (var i =0; i < 1_000_000; i++) invoke();";
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::Script> script = CompileBenchmarkScript(kScript);
|
|
v8::HandleScope benchmark_handle_scope(v8_isolate());
|
|
for (auto _ : st) {
|
|
USE(_);
|
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
|
benchmark::DoNotOptimize(result);
|
|
}
|
|
}
|
|
|
|
BENCHMARK_F(FastApiBenchmark, RegularCallToEmptyCallback)
|
|
(benchmark::State& st) {
|
|
const char* kScript =
|
|
"function invoke() { globalThis.regularApiCall(); }"
|
|
"\%PrepareFunctionForOptimization(invoke);"
|
|
"invoke();"
|
|
"\%OptimizeFunctionOnNextCall(invoke);"
|
|
"for (var i =0; i < 1_000_000; i++) invoke();";
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::Script> script = CompileBenchmarkScript(kScript);
|
|
v8::HandleScope benchmark_handle_scope(v8_isolate());
|
|
for (auto _ : st) {
|
|
USE(_);
|
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
|
benchmark::DoNotOptimize(result);
|
|
}
|
|
}
|
|
|
|
BENCHMARK_F(FastApiBenchmark, FastOneByteString)(benchmark::State& st) {
|
|
const char* kScript =
|
|
"function invoke() { globalThis.fastOneByteString('Hello World'); }"
|
|
"\%PrepareFunctionForOptimization(invoke);"
|
|
"invoke();"
|
|
"\%OptimizeFunctionOnNextCall(invoke);"
|
|
"for (var i =0; i < 1_000_000; i++) invoke();";
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::Script> script = CompileBenchmarkScript(kScript);
|
|
v8::HandleScope benchmark_handle_scope(v8_isolate());
|
|
for (auto _ : st) {
|
|
USE(_);
|
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
|
benchmark::DoNotOptimize(result);
|
|
}
|
|
}
|
|
|
|
BENCHMARK_F(FastApiBenchmark, FastStringValueView)(benchmark::State& st) {
|
|
const char* kScript =
|
|
"function invoke() { globalThis.fastStringValueView('Hello World'); }"
|
|
"\%PrepareFunctionForOptimization(invoke);"
|
|
"invoke();"
|
|
"\%OptimizeFunctionOnNextCall(invoke);"
|
|
"for (var i =0; i < 1_000_000; i++) invoke();";
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::Script> script = CompileBenchmarkScript(kScript);
|
|
v8::HandleScope benchmark_handle_scope(v8_isolate());
|
|
for (auto _ : st) {
|
|
USE(_);
|
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
|
benchmark::DoNotOptimize(result);
|
|
}
|
|
}
|
|
|
|
BENCHMARK_F(FastApiBenchmark, RegularString)(benchmark::State& st) {
|
|
const char* kScript =
|
|
"function invoke() { globalThis.regularString('Hello World'); }"
|
|
"\%PrepareFunctionForOptimization(invoke);"
|
|
"invoke();"
|
|
"\%OptimizeFunctionOnNextCall(invoke);"
|
|
"for (var i =0; i < 1_000_000; i++) invoke();";
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
v8::Local<v8::Context> context = v8_context();
|
|
v8::Local<v8::Script> script = CompileBenchmarkScript(kScript);
|
|
v8::HandleScope benchmark_handle_scope(v8_isolate());
|
|
for (auto _ : st) {
|
|
USE(_);
|
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
|
benchmark::DoNotOptimize(result);
|
|
}
|
|
}
|