Commit cef8ae24 authored by Dan Elphick's avatar Dan Elphick Committed by Commit Bot

[compile] Collect RuntimeCallStats for AssembleCode

First this plumbs RuntimeCallStats from the OptimizingCompileDispatcher
down through to PipelineCompilationJob which stashes the
RuntimeCallStats on the PipelineData.

Adds new RCS thread-specific counters: OptimizeAssembleCode and
OptimizeBackgroundAssembleCode which are used in
PipelineImpl::AssembleCode.

Bug: v8:10006
Change-Id: Ieef6d32afddf4b0760e204010b09a85dfec92cf3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1926030
Commit-Queue: Dan Elphick <delphick@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65221}
parent 5a5d7d18
...@@ -225,12 +225,13 @@ CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) { ...@@ -225,12 +225,13 @@ CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) {
return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute); return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);
} }
CompilationJob::Status OptimizedCompilationJob::ExecuteJob() { CompilationJob::Status OptimizedCompilationJob::ExecuteJob(
RuntimeCallStats* stats) {
DisallowHeapAccess no_heap_access; DisallowHeapAccess no_heap_access;
// Delegate to the underlying implementation. // Delegate to the underlying implementation.
DCHECK_EQ(state(), State::kReadyToExecute); DCHECK_EQ(state(), State::kReadyToExecute);
ScopedTimer t(&time_taken_to_execute_); ScopedTimer t(&time_taken_to_execute_);
return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize); return UpdateState(ExecuteJobImpl(stats), State::kReadyToFinalize);
} }
CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) { CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) {
...@@ -742,7 +743,8 @@ bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) { ...@@ -742,7 +743,8 @@ bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) {
"V8.OptimizeNonConcurrent"); "V8.OptimizeNonConcurrent");
if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED || if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED ||
job->ExecuteJob() != CompilationJob::SUCCEEDED || job->ExecuteJob(isolate->counters()->runtime_call_stats()) !=
CompilationJob::SUCCEEDED ||
job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) { job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {
if (FLAG_trace_opt) { if (FLAG_trace_opt) {
PrintF("[aborted optimizing "); PrintF("[aborted optimizing ");
......
...@@ -28,6 +28,7 @@ class OptimizedCompilationInfo; ...@@ -28,6 +28,7 @@ class OptimizedCompilationInfo;
class OptimizedCompilationJob; class OptimizedCompilationJob;
class ParseInfo; class ParseInfo;
class Parser; class Parser;
class RuntimeCallStats;
class ScriptData; class ScriptData;
struct ScriptStreamingData; struct ScriptStreamingData;
class TimedHistogram; class TimedHistogram;
...@@ -305,7 +306,7 @@ class OptimizedCompilationJob : public CompilationJob { ...@@ -305,7 +306,7 @@ class OptimizedCompilationJob : public CompilationJob {
// Executes the compile job. Can be called on a background thread if // Executes the compile job. Can be called on a background thread if
// can_execute_on_background_thread() returns true. // can_execute_on_background_thread() returns true.
V8_WARN_UNUSED_RESULT Status ExecuteJob(); V8_WARN_UNUSED_RESULT Status ExecuteJob(RuntimeCallStats* stats);
// Finalizes the compile job. Must be called on the main thread. // Finalizes the compile job. Must be called on the main thread.
V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate); V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);
...@@ -330,7 +331,7 @@ class OptimizedCompilationJob : public CompilationJob { ...@@ -330,7 +331,7 @@ class OptimizedCompilationJob : public CompilationJob {
protected: protected:
// Overridden by the actual implementation. // Overridden by the actual implementation.
virtual Status PrepareJobImpl(Isolate* isolate) = 0; virtual Status PrepareJobImpl(Isolate* isolate) = 0;
virtual Status ExecuteJobImpl() = 0; virtual Status ExecuteJobImpl(RuntimeCallStats* stats) = 0;
virtual Status FinalizeJobImpl(Isolate* isolate) = 0; virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
private: private:
......
...@@ -76,7 +76,8 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask { ...@@ -76,7 +76,8 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask {
dispatcher_->recompilation_delay_)); dispatcher_->recompilation_delay_));
} }
dispatcher_->CompileNext(dispatcher_->NextInput(true)); dispatcher_->CompileNext(dispatcher_->NextInput(true),
runtime_call_stats_scope.Get());
} }
{ {
base::MutexGuard lock_guard(&dispatcher_->ref_count_mutex_); base::MutexGuard lock_guard(&dispatcher_->ref_count_mutex_);
...@@ -122,11 +123,12 @@ OptimizedCompilationJob* OptimizingCompileDispatcher::NextInput( ...@@ -122,11 +123,12 @@ OptimizedCompilationJob* OptimizingCompileDispatcher::NextInput(
return job; return job;
} }
void OptimizingCompileDispatcher::CompileNext(OptimizedCompilationJob* job) { void OptimizingCompileDispatcher::CompileNext(OptimizedCompilationJob* job,
RuntimeCallStats* stats) {
if (!job) return; if (!job) return;
// The function may have already been optimized by OSR. Simply continue. // The function may have already been optimized by OSR. Simply continue.
CompilationJob::Status status = job->ExecuteJob(); CompilationJob::Status status = job->ExecuteJob(stats);
USE(status); // Prevent an unused-variable error. USE(status); // Prevent an unused-variable error.
{ {
......
...@@ -19,6 +19,7 @@ namespace v8 { ...@@ -19,6 +19,7 @@ namespace v8 {
namespace internal { namespace internal {
class OptimizedCompilationJob; class OptimizedCompilationJob;
class RuntimeCallStats;
class SharedFunctionInfo; class SharedFunctionInfo;
class V8_EXPORT_PRIVATE OptimizingCompileDispatcher { class V8_EXPORT_PRIVATE OptimizingCompileDispatcher {
...@@ -57,7 +58,7 @@ class V8_EXPORT_PRIVATE OptimizingCompileDispatcher { ...@@ -57,7 +58,7 @@ class V8_EXPORT_PRIVATE OptimizingCompileDispatcher {
enum ModeFlag { COMPILE, FLUSH }; enum ModeFlag { COMPILE, FLUSH };
void FlushOutputQueue(bool restore_function_code); void FlushOutputQueue(bool restore_function_code);
void CompileNext(OptimizedCompilationJob* job); void CompileNext(OptimizedCompilationJob* job, RuntimeCallStats* stats);
OptimizedCompilationJob* NextInput(bool check_if_flushing = false); OptimizedCompilationJob* NextInput(bool check_if_flushing = false);
inline int InputQueueIndex(int i) { inline int InputQueueIndex(int i) {
......
...@@ -514,6 +514,16 @@ class PipelineData { ...@@ -514,6 +514,16 @@ class PipelineData {
return roots_relative_addressing_enabled_; return roots_relative_addressing_enabled_;
} }
// RuntimeCallStats that is only available during job execution but not
// finalization.
// TODO(delphick): Currently even during execution this can be nullptr, due to
// JSToWasmWrapperCompilationUnit::Execute. Once a table can be extracted
// there, this method can DCHECK that it is never nullptr.
RuntimeCallStats* runtime_call_stats() const { return runtime_call_stats_; }
void set_runtime_call_stats(RuntimeCallStats* stats) {
runtime_call_stats_ = stats;
}
private: private:
Isolate* const isolate_; Isolate* const isolate_;
wasm::WasmEngine* const wasm_engine_ = nullptr; wasm::WasmEngine* const wasm_engine_ = nullptr;
...@@ -585,6 +595,7 @@ class PipelineData { ...@@ -585,6 +595,7 @@ class PipelineData {
// state. Calculated during instruction selection, applied during code // state. Calculated during instruction selection, applied during code
// generation. // generation.
size_t max_unoptimized_frame_height_ = 0; size_t max_unoptimized_frame_height_ = 0;
RuntimeCallStats* runtime_call_stats_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(PipelineData); DISALLOW_COPY_AND_ASSIGN(PipelineData);
}; };
...@@ -946,7 +957,7 @@ class PipelineCompilationJob final : public OptimizedCompilationJob { ...@@ -946,7 +957,7 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
protected: protected:
Status PrepareJobImpl(Isolate* isolate) final; Status PrepareJobImpl(Isolate* isolate) final;
Status ExecuteJobImpl() final; Status ExecuteJobImpl(RuntimeCallStats* stats) final;
Status FinalizeJobImpl(Isolate* isolate) final; Status FinalizeJobImpl(Isolate* isolate) final;
// Registers weak object to optimized code dependencies. // Registers weak object to optimized code dependencies.
...@@ -1061,7 +1072,28 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl( ...@@ -1061,7 +1072,28 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
return SUCCEEDED; return SUCCEEDED;
} }
PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() { namespace {
// Ensure that the RuntimeStats table is set on the PipelineData for duration of
// the Execute phase and unset immediately afterwards.
class PipelineExecuteJobScope {
public:
PipelineExecuteJobScope(PipelineData* data, RuntimeCallStats* stats)
: data_(data) {
data_->set_runtime_call_stats(stats);
}
~PipelineExecuteJobScope() { data_->set_runtime_call_stats(nullptr); }
private:
PipelineData* data_;
};
} // namespace
PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl(
RuntimeCallStats* stats) {
// Ensure that the RuntimeCallStats table is only available during execution
// and not during finalization as that might be on a different thread.
PipelineExecuteJobScope scope(&data_, stats);
if (FLAG_concurrent_inlining) { if (FLAG_concurrent_inlining) {
if (!pipeline_.CreateGraph()) { if (!pipeline_.CreateGraph()) {
return AbortOptimization(BailoutReason::kGraphBuildingFailed); return AbortOptimization(BailoutReason::kGraphBuildingFailed);
...@@ -1077,6 +1109,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() { ...@@ -1077,6 +1109,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() {
if (!success) return FAILED; if (!success) return FAILED;
pipeline_.AssembleCode(linkage_); pipeline_.AssembleCode(linkage_);
return SUCCEEDED; return SUCCEEDED;
} }
...@@ -1154,7 +1187,7 @@ class WasmHeapStubCompilationJob final : public OptimizedCompilationJob { ...@@ -1154,7 +1187,7 @@ class WasmHeapStubCompilationJob final : public OptimizedCompilationJob {
protected: protected:
Status PrepareJobImpl(Isolate* isolate) final; Status PrepareJobImpl(Isolate* isolate) final;
Status ExecuteJobImpl() final; Status ExecuteJobImpl(RuntimeCallStats* stats) final;
Status FinalizeJobImpl(Isolate* isolate) final; Status FinalizeJobImpl(Isolate* isolate) final;
private: private:
...@@ -1188,7 +1221,8 @@ CompilationJob::Status WasmHeapStubCompilationJob::PrepareJobImpl( ...@@ -1188,7 +1221,8 @@ CompilationJob::Status WasmHeapStubCompilationJob::PrepareJobImpl(
UNREACHABLE(); UNREACHABLE();
} }
CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl() { CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl(
RuntimeCallStats* stats) {
std::unique_ptr<PipelineStatistics> pipeline_statistics; std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) { if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics( pipeline_statistics.reset(new PipelineStatistics(
...@@ -3137,6 +3171,9 @@ std::ostream& operator<<(std::ostream& out, ...@@ -3137,6 +3171,9 @@ std::ostream& operator<<(std::ostream& out,
void PipelineImpl::AssembleCode(Linkage* linkage, void PipelineImpl::AssembleCode(Linkage* linkage,
std::unique_ptr<AssemblerBuffer> buffer) { std::unique_ptr<AssemblerBuffer> buffer) {
PipelineData* data = this->data_; PipelineData* data = this->data_;
RuntimeCallTimerScope scope(data_->runtime_call_stats(),
RuntimeCallCounterId::kOptimizeAssembleCode,
RuntimeCallStats::kThreadSpecific);
data->BeginPhaseKind("V8.TFCodeGeneration"); data->BeginPhaseKind("V8.TFCodeGeneration");
data->InitializeCodeGenerator(linkage, std::move(buffer)); data->InitializeCodeGenerator(linkage, std::move(buffer));
......
...@@ -6832,7 +6832,8 @@ MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate, ...@@ -6832,7 +6832,8 @@ MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
Code::JS_TO_JS_FUNCTION, std::move(debug_name), Code::JS_TO_JS_FUNCTION, std::move(debug_name),
AssemblerOptions::Default(isolate))); AssemblerOptions::Default(isolate)));
if (job->ExecuteJob() == CompilationJob::FAILED || if (job->ExecuteJob(isolate->counters()->runtime_call_stats()) ==
CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) { job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return {}; return {};
} }
...@@ -6888,7 +6889,8 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { ...@@ -6888,7 +6889,8 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
Code::C_WASM_ENTRY, std::move(debug_name), Code::C_WASM_ENTRY, std::move(debug_name),
AssemblerOptions::Default(isolate))); AssemblerOptions::Default(isolate)));
if (job->ExecuteJob() == CompilationJob::FAILED || if (job->ExecuteJob(isolate->counters()->runtime_call_stats()) ==
CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) { job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return {}; return {};
} }
......
...@@ -577,7 +577,8 @@ void RuntimeCallStats::Dump(v8::tracing::TracedValue* value) { ...@@ -577,7 +577,8 @@ void RuntimeCallStats::Dump(v8::tracing::TracedValue* value) {
in_use_ = false; in_use_ = false;
} }
WorkerThreadRuntimeCallStats::WorkerThreadRuntimeCallStats() = default; WorkerThreadRuntimeCallStats::WorkerThreadRuntimeCallStats()
: isolate_thread_id_(ThreadId::Current()) {}
WorkerThreadRuntimeCallStats::~WorkerThreadRuntimeCallStats() { WorkerThreadRuntimeCallStats::~WorkerThreadRuntimeCallStats() {
if (tls_key_) base::Thread::DeleteThreadLocalKey(*tls_key_); if (tls_key_) base::Thread::DeleteThreadLocalKey(*tls_key_);
...@@ -591,6 +592,8 @@ base::Thread::LocalStorageKey WorkerThreadRuntimeCallStats::GetKey() { ...@@ -591,6 +592,8 @@ base::Thread::LocalStorageKey WorkerThreadRuntimeCallStats::GetKey() {
RuntimeCallStats* WorkerThreadRuntimeCallStats::NewTable() { RuntimeCallStats* WorkerThreadRuntimeCallStats::NewTable() {
DCHECK(TracingFlags::is_runtime_stats_enabled()); DCHECK(TracingFlags::is_runtime_stats_enabled());
// Never create a new worker table on the isolate's main thread.
DCHECK_NE(ThreadId::Current(), isolate_thread_id_);
std::unique_ptr<RuntimeCallStats> new_table = std::unique_ptr<RuntimeCallStats> new_table =
std::make_unique<RuntimeCallStats>(RuntimeCallStats::kWorkerThread); std::make_unique<RuntimeCallStats>(RuntimeCallStats::kWorkerThread);
RuntimeCallStats* result = new_table.get(); RuntimeCallStats* result = new_table.get();
......
...@@ -1175,6 +1175,10 @@ class WorkerThreadRuntimeCallStats final { ...@@ -1175,6 +1175,10 @@ class WorkerThreadRuntimeCallStats final {
base::Mutex mutex_; base::Mutex mutex_;
std::vector<std::unique_ptr<RuntimeCallStats>> tables_; std::vector<std::unique_ptr<RuntimeCallStats>> tables_;
base::Optional<base::Thread::LocalStorageKey> tls_key_; base::Optional<base::Thread::LocalStorageKey> tls_key_;
// Since this is for creating worker thread runtime-call stats, record the
// main thread ID to ensure we never create a worker RCS table for the main
// thread.
ThreadId isolate_thread_id_;
}; };
// Creating a WorkerThreadRuntimeCallStatsScope will provide a thread-local // Creating a WorkerThreadRuntimeCallStatsScope will provide a thread-local
......
...@@ -276,7 +276,7 @@ JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default; ...@@ -276,7 +276,7 @@ JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
void JSToWasmWrapperCompilationUnit::Execute() { void JSToWasmWrapperCompilationUnit::Execute() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "CompileJSToWasmWrapper"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "CompileJSToWasmWrapper");
CompilationJob::Status status = job_->ExecuteJob(); CompilationJob::Status status = job_->ExecuteJob(nullptr);
CHECK_EQ(status, CompilationJob::SUCCEEDED); CHECK_EQ(status, CompilationJob::SUCCEEDED);
} }
......
// Copyright 2019 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.
// Flags: --allow-natives-syntax --runtime-calls-stats --expose-gc
// Try to exercise the runtime stats code for optimization and GC.
// Optimize some functions both in the foreground and in the background.
function test(x) {
return 1 + Math.sin(x);
}
function testConcurrent(x) {
return 1 + Math.cos(x);
}
%PrepareFunctionForOptimization(test);
test(0.5);
test(0.6);
%OptimizeFunctionOnNextCall(test);
for (var i = 0; i < 100; ++i) {
test(0.7);
}
%PrepareFunctionForOptimization(testConcurrent);
testConcurrent(0.5);
testConcurrent(0.6);
%OptimizeFunctionOnNextCall(testConcurrent, 'concurrent');
for (var i = 0; i < 100; ++i) {
testConcurrent(0.7);
}
%GetOptimizationStatus(testConcurrent, 'sync');
gc();
...@@ -42,7 +42,7 @@ class BlockingCompilationJob : public OptimizedCompilationJob { ...@@ -42,7 +42,7 @@ class BlockingCompilationJob : public OptimizedCompilationJob {
// OptimiziedCompilationJob implementation. // OptimiziedCompilationJob implementation.
Status PrepareJobImpl(Isolate* isolate) override { UNREACHABLE(); } Status PrepareJobImpl(Isolate* isolate) override { UNREACHABLE(); }
Status ExecuteJobImpl() override { Status ExecuteJobImpl(RuntimeCallStats* stats) override {
blocking_.SetValue(true); blocking_.SetValue(true);
semaphore_.Wait(); semaphore_.Wait();
blocking_.SetValue(false); blocking_.SetValue(false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment