[local-isolate] Move worker RCS scope into LocalIsolate

Rather than requiring the user of a LocalIsolate to pass in a
RuntimeCallStats from a WorkerThreadRuntimeCallStatsScope, create the
scope in the LocalIsolate directly and use its RuntimeCallStats in the
LocalIsolate constructor.

We can't do this for the main thread LocalIsolate, since
WorkerThreadRuntimeCallStatsScope doesn't work on the main thread, so
there we use the main-thread RuntimeCallStats instead.

This flushes out some issues of background-thread LocalIsolates being
used on the main thread, so fix those too, as well as RCS scopes using
background counters for operations that could happen on the main thread.

Change-Id: I21a53be0771f47a03ccdb27d24c2b9d25d8b2d1c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3318664
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78334}
This commit is contained in:
Leszek Swirski 2021-12-08 16:09:20 +01:00 committed by V8 LUCI CQ
parent 96c6986c65
commit 7f121b4f93
18 changed files with 114 additions and 71 deletions

View File

@ -120,17 +120,8 @@ class BaselineBatchCompilerJob {
// Executed in the background thread.
void Compile() {
#ifdef V8_RUNTIME_CALL_STATS
WorkerThreadRuntimeCallStatsScope runtime_call_stats_scope(
isolate_for_local_isolate_->counters()
->worker_thread_runtime_call_stats());
LocalIsolate local_isolate(isolate_for_local_isolate_,
ThreadKind::kBackground,
runtime_call_stats_scope.Get());
#else
LocalIsolate local_isolate(isolate_for_local_isolate_,
ThreadKind::kBackground);
#endif
local_isolate.heap()->AttachPersistentHandles(std::move(handles_));
UnparkedScope unparked_scope(&local_isolate);
LocalHandleScope handle_scope(&local_isolate);

View File

@ -1340,15 +1340,14 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
}
#ifdef V8_RUNTIME_CALL_STATS
RuntimeCallCounterId RuntimeCallCounterIdForCompileBackground(
ParseInfo* parse_info) {
RuntimeCallCounterId RuntimeCallCounterIdForCompile(ParseInfo* parse_info) {
if (parse_info->flags().is_toplevel()) {
if (parse_info->flags().is_eval()) {
return RuntimeCallCounterId::kCompileBackgroundEval;
return RuntimeCallCounterId::kCompileEval;
}
return RuntimeCallCounterId::kCompileBackgroundScript;
return RuntimeCallCounterId::kCompileScript;
}
return RuntimeCallCounterId::kCompileBackgroundFunction;
return RuntimeCallCounterId::kCompileFunction;
}
#endif // V8_RUNTIME_CALL_STATS
@ -1460,11 +1459,8 @@ void SetScriptFieldsFromDetails(Isolate* isolate, Script script,
} // namespace
void BackgroundCompileTask::Run() {
WorkerThreadRuntimeCallStatsScope worker_thread_scope(
worker_thread_runtime_call_stats_);
LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground,
worker_thread_scope.Get());
DCHECK_NE(ThreadId::Current(), isolate_for_local_isolate_->thread_id());
LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&isolate);
LocalHandleScope handle_scope(&isolate);
@ -1473,13 +1469,20 @@ void BackgroundCompileTask::Run() {
Run(&isolate, &reusable_state);
}
void BackgroundCompileTask::RunOnMainThread(Isolate* isolate) {
LocalHandleScope handle_scope(isolate->main_thread_local_isolate());
ReusableUnoptimizedCompileState reusable_state(isolate);
Run(isolate->main_thread_local_isolate(), &reusable_state);
}
void BackgroundCompileTask::Run(
LocalIsolate* isolate, ReusableUnoptimizedCompileState* reusable_state) {
TimedHistogramScope timer(timer_);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"BackgroundCompileTask::Run");
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileBackgroundCompileTask);
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileCompileTask,
RuntimeCallStats::CounterMode::kThreadSpecific);
bool toplevel_script_compilation = flags_.is_toplevel();
@ -1554,8 +1557,8 @@ void BackgroundCompileTask::Run(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileCodeBackground");
RCS_SCOPE(info.runtime_call_stats(),
RuntimeCallCounterIdForCompileBackground(&info));
RCS_SCOPE(isolate, RuntimeCallCounterIdForCompile(&info),
RuntimeCallStats::CounterMode::kThreadSpecific);
MaybeHandle<SharedFunctionInfo> maybe_result;
if (info.literal() != nullptr) {

View File

@ -517,6 +517,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
TimedHistogram* timer, int max_stack_size);
void Run();
void RunOnMainThread(Isolate* isolate);
void Run(LocalIsolate* isolate,
ReusableUnoptimizedCompileState* reusable_state);

View File

@ -12,6 +12,7 @@
#include "src/base/platform/time.h"
#include "src/codegen/compiler.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/flags/flags.h"
#include "src/handles/global-handles-inl.h"
#include "src/heap/parked-scope.h"
@ -266,7 +267,7 @@ bool LazyCompileDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
}
if (job->state == Job::State::kPendingToRunOnForeground) {
job->task->Run();
job->task->RunOnMainThread(isolate_);
job->state = Job::State::kFinalizingNow;
}
@ -400,11 +401,7 @@ void LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.LazyCompileDispatcherDoBackgroundWork");
WorkerThreadRuntimeCallStatsScope worker_thread_scope(
worker_thread_runtime_call_stats_);
LocalIsolate isolate(isolate_, ThreadKind::kBackground,
worker_thread_scope.Get());
LocalIsolate isolate(isolate_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&isolate);
LocalHandleScope handle_scope(&isolate);

View File

@ -58,18 +58,11 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask {
private:
// v8::Task overrides.
void RunInternal() override {
#ifdef V8_RUNTIME_CALL_STATS
WorkerThreadRuntimeCallStatsScope runtime_call_stats_scope(
worker_thread_runtime_call_stats_);
LocalIsolate local_isolate(isolate_, ThreadKind::kBackground,
runtime_call_stats_scope.Get());
#else // V8_RUNTIME_CALL_STATS
LocalIsolate local_isolate(isolate_, ThreadKind::kBackground);
#endif // V8_RUNTIME_CALL_STATS
DCHECK(local_isolate.heap()->IsParked());
{
RCS_SCOPE(runtime_call_stats_scope.Get(),
RCS_SCOPE(&local_isolate,
RuntimeCallCounterId::kOptimizeBackgroundDispatcherJob);
TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);

View File

@ -14,8 +14,7 @@
namespace v8 {
namespace internal {
LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind,
RuntimeCallStats* runtime_call_stats)
LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind)
: HiddenLocalFactory(isolate),
heap_(isolate->heap(), kind),
isolate_(isolate),
@ -23,16 +22,20 @@ LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind,
thread_id_(ThreadId::Current()),
stack_limit_(kind == ThreadKind::kMain
? isolate->stack_guard()->real_climit()
: GetCurrentStackPosition() - FLAG_stack_size * KB),
runtime_call_stats_(kind == ThreadKind::kMain &&
runtime_call_stats == nullptr
? isolate->counters()->runtime_call_stats()
: runtime_call_stats)
: GetCurrentStackPosition() - FLAG_stack_size * KB)
#ifdef V8_INTL_SUPPORT
,
default_locale_(isolate->DefaultLocale())
#endif
{
#ifdef V8_RUNTIME_CALL_STATS
if (kind == ThreadKind::kMain) {
runtime_call_stats_ = isolate->counters()->runtime_call_stats();
} else {
rcs_scope_.emplace(isolate->counters()->worker_thread_runtime_call_stats());
runtime_call_stats_ = rcs_scope_->Get();
}
#endif
}
LocalIsolate::~LocalIsolate() {

View File

@ -13,6 +13,7 @@
#include "src/handles/maybe-handles.h"
#include "src/heap/local-factory.h"
#include "src/heap/local-heap.h"
#include "src/logging/runtime-call-stats.h"
namespace v8 {
@ -43,8 +44,7 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
public:
using HandleScopeType = LocalHandleScope;
explicit LocalIsolate(Isolate* isolate, ThreadKind kind,
RuntimeCallStats* runtime_call_stats = nullptr);
explicit LocalIsolate(Isolate* isolate, ThreadKind kind);
~LocalIsolate();
// Kinda sketchy.
@ -110,7 +110,11 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
LocalLogger* logger() const { return logger_.get(); }
ThreadId thread_id() const { return thread_id_; }
Address stack_limit() const { return stack_limit_; }
#ifdef V8_RUNTIME_CALL_STATS
RuntimeCallStats* runtime_call_stats() const { return runtime_call_stats_; }
#else
RuntimeCallStats* runtime_call_stats() const { return nullptr; }
#endif
bigint::Processor* bigint_processor() {
if (!bigint_processor_) InitializeBigIntProcessor();
return bigint_processor_;
@ -155,8 +159,12 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
ThreadId const thread_id_;
Address const stack_limit_;
RuntimeCallStats* runtime_call_stats_;
bigint::Processor* bigint_processor_{nullptr};
#ifdef V8_RUNTIME_CALL_STATS
base::Optional<WorkerThreadRuntimeCallStatsScope> rcs_scope_;
RuntimeCallStats* runtime_call_stats_;
#endif
#ifdef V8_INTL_SUPPORT
std::string default_locale_;
#endif

View File

@ -58,10 +58,16 @@ LocalHandleScope::~LocalHandleScope() {
template <typename T>
Handle<T> LocalHandleScope::CloseAndEscape(Handle<T> handle_value) {
HandleScopeData* current = &local_heap_->handles()->scope_;
HandleScopeData* current;
T value = *handle_value;
// Throw away all handles in the current scope.
CloseScope(local_heap_, prev_next_, prev_limit_);
if (local_heap_->is_main_thread()) {
current = local_heap_->heap()->isolate()->handle_scope_data();
CloseMainThreadScope(local_heap_, prev_next_, prev_limit_);
} else {
current = &local_heap_->handles()->scope_;
CloseScope(local_heap_, prev_next_, prev_limit_);
}
// Allocate one handle in the parent scope.
DCHECK(current->level > current->sealed_level);
Handle<T> result(value, local_heap_);

View File

@ -257,8 +257,8 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
Handle<SharedFunctionInfo> shared_info, LocalIsolate* isolate) {
RCS_SCOPE(parse_info()->runtime_call_stats(),
RuntimeCallCounterId::kCompileBackgroundIgnitionFinalization);
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileIgnitionFinalization,
RuntimeCallStats::kThreadSpecific);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileIgnitionFinalization");
return DoFinalizeJobImpl(shared_info, isolate);

View File

@ -30,11 +30,17 @@ RuntimeCallTimerScope::RuntimeCallTimerScope(Isolate* isolate,
stats_->Enter(&timer_, counter_id);
}
RuntimeCallTimerScope::RuntimeCallTimerScope(LocalIsolate* isolate,
RuntimeCallCounterId counter_id) {
RuntimeCallTimerScope::RuntimeCallTimerScope(
LocalIsolate* isolate, RuntimeCallCounterId counter_id,
RuntimeCallStats::CounterMode mode) {
if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
DCHECK_NOT_NULL(isolate->runtime_call_stats());
stats_ = isolate->runtime_call_stats();
if (mode == RuntimeCallStats::CounterMode::kThreadSpecific) {
counter_id = stats_->CounterIdForThread(counter_id);
}
DCHECK(stats_->IsCounterAppropriateForThread(counter_id));
stats_->Enter(&timer_, counter_id);
}

View File

@ -323,8 +323,7 @@ void WorkerThreadRuntimeCallStats::AddToMainTable(
}
WorkerThreadRuntimeCallStatsScope::WorkerThreadRuntimeCallStatsScope(
WorkerThreadRuntimeCallStats* worker_stats)
: table_(nullptr) {
WorkerThreadRuntimeCallStats* worker_stats) {
if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
table_ = reinterpret_cast<RuntimeCallStats*>(

View File

@ -314,6 +314,7 @@ class RuntimeCallTimer final {
ADD_THREAD_SPECIFIC_COUNTER(V, Compile, RewriteReturnResult) \
ADD_THREAD_SPECIFIC_COUNTER(V, Compile, ScopeAnalysis) \
ADD_THREAD_SPECIFIC_COUNTER(V, Compile, Script) \
ADD_THREAD_SPECIFIC_COUNTER(V, Compile, CompileTask) \
\
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateFPRegisters) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateGeneralRegisters) \
@ -390,7 +391,6 @@ class RuntimeCallTimer final {
V(CodeGenerationFromStringsCallbacks) \
V(CompileBackgroundBaselinePreVisit) \
V(CompileBackgroundBaselineVisit) \
V(CompileBackgroundCompileTask) \
V(CompileBaseline) \
V(CompileBaselineFinalization) \
V(CompileBaselinePreVisit) \
@ -683,14 +683,20 @@ class WorkerThreadRuntimeCallStats final {
// when it is destroyed.
class V8_NODISCARD WorkerThreadRuntimeCallStatsScope final {
public:
WorkerThreadRuntimeCallStatsScope() = default;
explicit WorkerThreadRuntimeCallStatsScope(
WorkerThreadRuntimeCallStats* off_thread_stats);
~WorkerThreadRuntimeCallStatsScope();
WorkerThreadRuntimeCallStatsScope(WorkerThreadRuntimeCallStatsScope&&) =
delete;
WorkerThreadRuntimeCallStatsScope(const WorkerThreadRuntimeCallStatsScope&) =
delete;
RuntimeCallStats* Get() const { return table_; }
private:
RuntimeCallStats* table_;
RuntimeCallStats* table_ = nullptr;
};
#define CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats, counter_id) \
@ -713,7 +719,9 @@ class V8_NODISCARD RuntimeCallTimerScope {
inline RuntimeCallTimerScope(Isolate* isolate,
RuntimeCallCounterId counter_id);
inline RuntimeCallTimerScope(LocalIsolate* isolate,
RuntimeCallCounterId counter_id);
RuntimeCallCounterId counter_id,
RuntimeCallStats::CounterMode mode =
RuntimeCallStats::CounterMode::kExact);
inline RuntimeCallTimerScope(RuntimeCallStats* stats,
RuntimeCallCounterId counter_id,
RuntimeCallStats::CounterMode mode =

View File

@ -3292,7 +3292,8 @@ void Parser::UpdateStatistics(
void Parser::ParseOnBackground(LocalIsolate* isolate, ParseInfo* info,
int start_position, int end_position,
int function_literal_id) {
RCS_SCOPE(runtime_call_stats_, RuntimeCallCounterId::kParseBackgroundProgram);
RCS_SCOPE(isolate, RuntimeCallCounterId::kParseProgram,
RuntimeCallStats::CounterMode::kThreadSpecific);
parsing_on_main_thread_ = false;
DCHECK_NULL(info->literal());

View File

@ -8,6 +8,7 @@
#include "src/ast/scopes.h"
#include "src/ast/variables.h"
#include "src/base/logging.h"
#include "src/base/platform/wrappers.h"
#include "src/handles/handles.h"
#include "src/objects/objects-inl.h"
@ -529,7 +530,8 @@ class OnHeapProducedPreparseData final : public ProducedPreparseData {
Handle<PreparseData> Serialize(LocalIsolate* isolate) final {
DCHECK(!data_->is_null());
DCHECK(isolate->heap()->ContainsLocalHandle(data_.location()));
DCHECK_IMPLIES(!isolate->is_main_thread(),
isolate->heap()->ContainsLocalHandle(data_.location()));
return data_;
}

View File

@ -528,6 +528,25 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin(
return CompileRunWithOrigin(v8_str(source), origin_url);
}
// Run a ScriptStreamingTask in a separate thread.
class StreamerThread : public v8::base::Thread {
public:
static void StartThreadForTaskAndJoin(
v8::ScriptCompiler::ScriptStreamingTask* task) {
StreamerThread thread(task);
CHECK(thread.Start());
thread.Join();
}
explicit StreamerThread(v8::ScriptCompiler::ScriptStreamingTask* task)
: Thread(Thread::Options()), task_(task) {}
void Run() override { task_->Run(); }
private:
v8::ScriptCompiler::ScriptStreamingTask* task_;
};
// Takes a JSFunction and runs it through the test version of the optimizing
// pipeline, allocating the temporary compilation artifacts in a given Zone.
// For possible {flags} values, look at OptimizedCompilationInfo::Flag. If

View File

@ -23800,9 +23800,9 @@ void RunStreamingTest(const char** chunks, v8::ScriptType type,
v8::ScriptCompiler::ScriptStreamingTask* task =
v8::ScriptCompiler::StartStreaming(isolate, &source, type);
// TestSourceStream::GetMoreData won't block, so it's OK to just run the
// task here in the main thread.
task->Run();
// TestSourceStream::GetMoreData won't block, so it's OK to just join the
// background task.
StreamerThread::StartThreadForTaskAndJoin(task);
delete task;
// Possible errors are only produced while compiling.
@ -24125,7 +24125,9 @@ TEST(StreamingWithDebuggingEnabledLate) {
v8::ScriptCompiler::ScriptStreamingTask* task =
v8::ScriptCompiler::StartStreaming(isolate, &source);
task->Run();
// TestSourceStream::GetMoreData won't block, so it's OK to just join the
// background task.
StreamerThread::StartThreadForTaskAndJoin(task);
delete task;
CHECK(!try_catch.HasCaught());
@ -24235,7 +24237,10 @@ TEST(StreamingWithHarmonyScopes) {
v8::ScriptCompiler::StreamedSource::ONE_BYTE);
v8::ScriptCompiler::ScriptStreamingTask* task =
v8::ScriptCompiler::StartStreaming(isolate, &source);
task->Run();
// TestSourceStream::GetMoreData won't block, so it's OK to just join the
// background task.
StreamerThread::StartThreadForTaskAndJoin(task);
delete task;
// Parsing should succeed (the script will be parsed and compiled in a context

View File

@ -976,8 +976,9 @@ TEST(ProfilerEnabledDuringBackgroundCompile) {
std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task(
v8::ScriptCompiler::StartStreaming(isolate, &streamed_source));
// Run the background compilation task on the main thread.
task->Run();
// Run the background compilation task. DummySourceStream::GetMoreData won't
// block, so it's OK to just join the background task.
StreamerThread::StartThreadForTaskAndJoin(task.get());
// Enable the CPU profiler.
auto* cpu_profiler = v8::CpuProfiler::New(isolate, v8::kStandardNaming);

View File

@ -79,7 +79,7 @@ TEST_F(BackgroundCompileTaskTest, SyntaxError) {
std::unique_ptr<BackgroundCompileTask> task(
NewBackgroundCompileTask(isolate(), shared));
task->Run();
task->RunOnMainThread(isolate());
ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask(
task.get(), isolate(), Compiler::KEEP_EXCEPTION));
ASSERT_TRUE(isolate()->has_pending_exception());
@ -105,7 +105,7 @@ TEST_F(BackgroundCompileTaskTest, CompileAndRun) {
std::unique_ptr<BackgroundCompileTask> task(
NewBackgroundCompileTask(isolate(), shared));
task->Run();
task->RunOnMainThread(isolate());
ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
task.get(), isolate(), Compiler::KEEP_EXCEPTION));
ASSERT_TRUE(shared->is_compiled());
@ -131,7 +131,7 @@ TEST_F(BackgroundCompileTaskTest, CompileFailure) {
std::unique_ptr<BackgroundCompileTask> task(
NewBackgroundCompileTask(isolate(), shared, 100));
task->Run();
task->RunOnMainThread(isolate());
ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask(
task.get(), isolate(), Compiler::KEEP_EXCEPTION));
ASSERT_TRUE(isolate()->has_pending_exception());
@ -201,7 +201,7 @@ TEST_F(BackgroundCompileTaskTest, EagerInnerFunctions) {
std::unique_ptr<BackgroundCompileTask> task(
NewBackgroundCompileTask(isolate(), shared));
task->Run();
task->RunOnMainThread(isolate());
ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
task.get(), isolate(), Compiler::KEEP_EXCEPTION));
ASSERT_TRUE(shared->is_compiled());
@ -231,7 +231,7 @@ TEST_F(BackgroundCompileTaskTest, LazyInnerFunctions) {
// There's already a task for this SFI.
task->Run();
task->RunOnMainThread(isolate());
ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask(
task.get(), isolate(), Compiler::KEEP_EXCEPTION));
ASSERT_TRUE(shared->is_compiled());