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) {
return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);
}
CompilationJob::Status OptimizedCompilationJob::ExecuteJob() {
CompilationJob::Status OptimizedCompilationJob::ExecuteJob(
RuntimeCallStats* stats) {
DisallowHeapAccess no_heap_access;
// Delegate to the underlying implementation.
DCHECK_EQ(state(), State::kReadyToExecute);
ScopedTimer t(&time_taken_to_execute_);
return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize);
return UpdateState(ExecuteJobImpl(stats), State::kReadyToFinalize);
}
CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) {
......@@ -742,7 +743,8 @@ bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) {
"V8.OptimizeNonConcurrent");
if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED ||
job->ExecuteJob() != CompilationJob::SUCCEEDED ||
job->ExecuteJob(isolate->counters()->runtime_call_stats()) !=
CompilationJob::SUCCEEDED ||
job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {
if (FLAG_trace_opt) {
PrintF("[aborted optimizing ");
......
......@@ -28,6 +28,7 @@ class OptimizedCompilationInfo;
class OptimizedCompilationJob;
class ParseInfo;
class Parser;
class RuntimeCallStats;
class ScriptData;
struct ScriptStreamingData;
class TimedHistogram;
......@@ -305,7 +306,7 @@ class OptimizedCompilationJob : public CompilationJob {
// Executes the compile job. Can be called on a background thread if
// 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.
V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);
......@@ -330,7 +331,7 @@ class OptimizedCompilationJob : public CompilationJob {
protected:
// Overridden by the actual implementation.
virtual Status PrepareJobImpl(Isolate* isolate) = 0;
virtual Status ExecuteJobImpl() = 0;
virtual Status ExecuteJobImpl(RuntimeCallStats* stats) = 0;
virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
private:
......
......@@ -76,7 +76,8 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask {
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_);
......@@ -122,11 +123,12 @@ OptimizedCompilationJob* OptimizingCompileDispatcher::NextInput(
return job;
}
void OptimizingCompileDispatcher::CompileNext(OptimizedCompilationJob* job) {
void OptimizingCompileDispatcher::CompileNext(OptimizedCompilationJob* job,
RuntimeCallStats* stats) {
if (!job) return;
// 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.
{
......
......@@ -19,6 +19,7 @@ namespace v8 {
namespace internal {
class OptimizedCompilationJob;
class RuntimeCallStats;
class SharedFunctionInfo;
class V8_EXPORT_PRIVATE OptimizingCompileDispatcher {
......@@ -57,7 +58,7 @@ class V8_EXPORT_PRIVATE OptimizingCompileDispatcher {
enum ModeFlag { COMPILE, FLUSH };
void FlushOutputQueue(bool restore_function_code);
void CompileNext(OptimizedCompilationJob* job);
void CompileNext(OptimizedCompilationJob* job, RuntimeCallStats* stats);
OptimizedCompilationJob* NextInput(bool check_if_flushing = false);
inline int InputQueueIndex(int i) {
......
......@@ -514,6 +514,16 @@ class PipelineData {
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:
Isolate* const isolate_;
wasm::WasmEngine* const wasm_engine_ = nullptr;
......@@ -585,6 +595,7 @@ class PipelineData {
// state. Calculated during instruction selection, applied during code
// generation.
size_t max_unoptimized_frame_height_ = 0;
RuntimeCallStats* runtime_call_stats_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(PipelineData);
};
......@@ -946,7 +957,7 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
protected:
Status PrepareJobImpl(Isolate* isolate) final;
Status ExecuteJobImpl() final;
Status ExecuteJobImpl(RuntimeCallStats* stats) final;
Status FinalizeJobImpl(Isolate* isolate) final;
// Registers weak object to optimized code dependencies.
......@@ -1061,7 +1072,28 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
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 (!pipeline_.CreateGraph()) {
return AbortOptimization(BailoutReason::kGraphBuildingFailed);
......@@ -1077,6 +1109,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() {
if (!success) return FAILED;
pipeline_.AssembleCode(linkage_);
return SUCCEEDED;
}
......@@ -1154,7 +1187,7 @@ class WasmHeapStubCompilationJob final : public OptimizedCompilationJob {
protected:
Status PrepareJobImpl(Isolate* isolate) final;
Status ExecuteJobImpl() final;
Status ExecuteJobImpl(RuntimeCallStats* stats) final;
Status FinalizeJobImpl(Isolate* isolate) final;
private:
......@@ -1188,7 +1221,8 @@ CompilationJob::Status WasmHeapStubCompilationJob::PrepareJobImpl(
UNREACHABLE();
}
CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl() {
CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl(
RuntimeCallStats* stats) {
std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics(
......@@ -3137,6 +3171,9 @@ std::ostream& operator<<(std::ostream& out,
void PipelineImpl::AssembleCode(Linkage* linkage,
std::unique_ptr<AssemblerBuffer> buffer) {
PipelineData* data = this->data_;
RuntimeCallTimerScope scope(data_->runtime_call_stats(),
RuntimeCallCounterId::kOptimizeAssembleCode,
RuntimeCallStats::kThreadSpecific);
data->BeginPhaseKind("V8.TFCodeGeneration");
data->InitializeCodeGenerator(linkage, std::move(buffer));
......
......@@ -6832,7 +6832,8 @@ MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
Code::JS_TO_JS_FUNCTION, std::move(debug_name),
AssemblerOptions::Default(isolate)));
if (job->ExecuteJob() == CompilationJob::FAILED ||
if (job->ExecuteJob(isolate->counters()->runtime_call_stats()) ==
CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return {};
}
......@@ -6888,7 +6889,8 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
Code::C_WASM_ENTRY, std::move(debug_name),
AssemblerOptions::Default(isolate)));
if (job->ExecuteJob() == CompilationJob::FAILED ||
if (job->ExecuteJob(isolate->counters()->runtime_call_stats()) ==
CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return {};
}
......
......@@ -577,7 +577,8 @@ void RuntimeCallStats::Dump(v8::tracing::TracedValue* value) {
in_use_ = false;
}
WorkerThreadRuntimeCallStats::WorkerThreadRuntimeCallStats() = default;
WorkerThreadRuntimeCallStats::WorkerThreadRuntimeCallStats()
: isolate_thread_id_(ThreadId::Current()) {}
WorkerThreadRuntimeCallStats::~WorkerThreadRuntimeCallStats() {
if (tls_key_) base::Thread::DeleteThreadLocalKey(*tls_key_);
......@@ -591,6 +592,8 @@ base::Thread::LocalStorageKey WorkerThreadRuntimeCallStats::GetKey() {
RuntimeCallStats* WorkerThreadRuntimeCallStats::NewTable() {
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::make_unique<RuntimeCallStats>(RuntimeCallStats::kWorkerThread);
RuntimeCallStats* result = new_table.get();
......
......@@ -1175,6 +1175,10 @@ class WorkerThreadRuntimeCallStats final {
base::Mutex mutex_;
std::vector<std::unique_ptr<RuntimeCallStats>> tables_;
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
......
......@@ -276,7 +276,7 @@ JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
void JSToWasmWrapperCompilationUnit::Execute() {
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);
}
......
// 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 {
// OptimiziedCompilationJob implementation.
Status PrepareJobImpl(Isolate* isolate) override { UNREACHABLE(); }
Status ExecuteJobImpl() override {
Status ExecuteJobImpl(RuntimeCallStats* stats) override {
blocking_.SetValue(true);
semaphore_.Wait();
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