Add a test for OptimizingCompileDispatcher::Flush's non-blocking behavior
R=mtrofin@chromium.org,verwaest@chromium.org BUG= Review-Url: https://codereview.chromium.org/2662883003 Cr-Commit-Position: refs/heads/master@{#42787}
This commit is contained in:
parent
c0f255f075
commit
d651ce314c
@ -31,7 +31,9 @@ class AtomicNumber {
|
|||||||
&value_, -static_cast<base::AtomicWord>(decrement)));
|
&value_, -static_cast<base::AtomicWord>(decrement)));
|
||||||
}
|
}
|
||||||
|
|
||||||
V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); }
|
V8_INLINE T Value() const {
|
||||||
|
return static_cast<T>(base::Acquire_Load(&value_));
|
||||||
|
}
|
||||||
|
|
||||||
V8_INLINE void SetValue(T new_value) {
|
V8_INLINE void SetValue(T new_value) {
|
||||||
base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
|
base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "src/compilation-dependencies.h"
|
#include "src/compilation-dependencies.h"
|
||||||
#include "src/frames.h"
|
#include "src/frames.h"
|
||||||
|
#include "src/globals.h"
|
||||||
#include "src/handles.h"
|
#include "src/handles.h"
|
||||||
#include "src/objects.h"
|
#include "src/objects.h"
|
||||||
#include "src/source-position-table.h"
|
#include "src/source-position-table.h"
|
||||||
@ -28,7 +29,7 @@ class Zone;
|
|||||||
|
|
||||||
// CompilationInfo encapsulates some information known at compile time. It
|
// CompilationInfo encapsulates some information known at compile time. It
|
||||||
// is constructed based on the resources available at compile-time.
|
// is constructed based on the resources available at compile-time.
|
||||||
class CompilationInfo final {
|
class V8_EXPORT_PRIVATE CompilationInfo final {
|
||||||
public:
|
public:
|
||||||
// Various configuration flags for a compilation, as well as some properties
|
// Various configuration flags for a compilation, as well as some properties
|
||||||
// of the compiled code produced by a compilation.
|
// of the compiled code produced by a compilation.
|
||||||
|
@ -33,11 +33,11 @@ void DisposeCompilationJob(CompilationJob* job, bool restore_function_code) {
|
|||||||
|
|
||||||
class OptimizingCompileDispatcher::CompileTask : public v8::Task {
|
class OptimizingCompileDispatcher::CompileTask : public v8::Task {
|
||||||
public:
|
public:
|
||||||
explicit CompileTask(Isolate* isolate) : isolate_(isolate) {
|
explicit CompileTask(Isolate* isolate,
|
||||||
OptimizingCompileDispatcher* dispatcher =
|
OptimizingCompileDispatcher* dispatcher)
|
||||||
isolate_->optimizing_compile_dispatcher();
|
: isolate_(isolate), dispatcher_(dispatcher) {
|
||||||
base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
|
base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
|
||||||
++dispatcher->ref_count_;
|
++dispatcher_->ref_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~CompileTask() {}
|
virtual ~CompileTask() {}
|
||||||
@ -49,30 +49,29 @@ class OptimizingCompileDispatcher::CompileTask : public v8::Task {
|
|||||||
DisallowHandleAllocation no_handles;
|
DisallowHandleAllocation no_handles;
|
||||||
DisallowHandleDereference no_deref;
|
DisallowHandleDereference no_deref;
|
||||||
|
|
||||||
OptimizingCompileDispatcher* dispatcher =
|
|
||||||
isolate_->optimizing_compile_dispatcher();
|
|
||||||
{
|
{
|
||||||
TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
|
TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
|
||||||
|
|
||||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||||
"V8.RecompileConcurrent");
|
"V8.RecompileConcurrent");
|
||||||
|
|
||||||
if (dispatcher->recompilation_delay_ != 0) {
|
if (dispatcher_->recompilation_delay_ != 0) {
|
||||||
base::OS::Sleep(base::TimeDelta::FromMilliseconds(
|
base::OS::Sleep(base::TimeDelta::FromMilliseconds(
|
||||||
dispatcher->recompilation_delay_));
|
dispatcher_->recompilation_delay_));
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatcher->CompileNext(dispatcher->NextInput(true));
|
dispatcher_->CompileNext(dispatcher_->NextInput(true));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
base::LockGuard<base::Mutex> lock_guard(&dispatcher->ref_count_mutex_);
|
base::LockGuard<base::Mutex> lock_guard(&dispatcher_->ref_count_mutex_);
|
||||||
if (--dispatcher->ref_count_ == 0) {
|
if (--dispatcher_->ref_count_ == 0) {
|
||||||
dispatcher->ref_count_zero_.NotifyOne();
|
dispatcher_->ref_count_zero_.NotifyOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
|
OptimizingCompileDispatcher* dispatcher_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CompileTask);
|
DISALLOW_COPY_AND_ASSIGN(CompileTask);
|
||||||
};
|
};
|
||||||
@ -222,14 +221,14 @@ void OptimizingCompileDispatcher::QueueForOptimization(CompilationJob* job) {
|
|||||||
blocked_jobs_++;
|
blocked_jobs_++;
|
||||||
} else {
|
} else {
|
||||||
V8::GetCurrentPlatform()->CallOnBackgroundThread(
|
V8::GetCurrentPlatform()->CallOnBackgroundThread(
|
||||||
new CompileTask(isolate_), v8::Platform::kShortRunningTask);
|
new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptimizingCompileDispatcher::Unblock() {
|
void OptimizingCompileDispatcher::Unblock() {
|
||||||
while (blocked_jobs_ > 0) {
|
while (blocked_jobs_ > 0) {
|
||||||
V8::GetCurrentPlatform()->CallOnBackgroundThread(
|
V8::GetCurrentPlatform()->CallOnBackgroundThread(
|
||||||
new CompileTask(isolate_), v8::Platform::kShortRunningTask);
|
new CompileTask(isolate_, this), v8::Platform::kShortRunningTask);
|
||||||
blocked_jobs_--;
|
blocked_jobs_--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "src/base/platform/mutex.h"
|
#include "src/base/platform/mutex.h"
|
||||||
#include "src/base/platform/platform.h"
|
#include "src/base/platform/platform.h"
|
||||||
#include "src/flags.h"
|
#include "src/flags.h"
|
||||||
|
#include "src/globals.h"
|
||||||
#include "src/list.h"
|
#include "src/list.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -20,7 +21,7 @@ namespace internal {
|
|||||||
class CompilationJob;
|
class CompilationJob;
|
||||||
class SharedFunctionInfo;
|
class SharedFunctionInfo;
|
||||||
|
|
||||||
class OptimizingCompileDispatcher {
|
class V8_EXPORT_PRIVATE OptimizingCompileDispatcher {
|
||||||
public:
|
public:
|
||||||
enum class BlockingBehavior { kBlock, kDontBlock };
|
enum class BlockingBehavior { kBlock, kDontBlock };
|
||||||
|
|
||||||
@ -38,9 +39,9 @@ class OptimizingCompileDispatcher {
|
|||||||
|
|
||||||
~OptimizingCompileDispatcher();
|
~OptimizingCompileDispatcher();
|
||||||
|
|
||||||
void Run();
|
|
||||||
void Stop();
|
void Stop();
|
||||||
void Flush(BlockingBehavior blocking_behavior);
|
void Flush(BlockingBehavior blocking_behavior);
|
||||||
|
// Takes ownership of |job|.
|
||||||
void QueueForOptimization(CompilationJob* job);
|
void QueueForOptimization(CompilationJob* job);
|
||||||
void Unblock();
|
void Unblock();
|
||||||
void InstallOptimizedFunctions();
|
void InstallOptimizedFunctions();
|
||||||
|
@ -154,7 +154,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
|
|||||||
//
|
//
|
||||||
// Each of the three phases can either fail or succeed. The current state of
|
// Each of the three phases can either fail or succeed. The current state of
|
||||||
// the job can be checked using {state()}.
|
// the job can be checked using {state()}.
|
||||||
class CompilationJob {
|
class V8_EXPORT_PRIVATE CompilationJob {
|
||||||
public:
|
public:
|
||||||
enum Status { SUCCEEDED, FAILED };
|
enum Status { SUCCEEDED, FAILED };
|
||||||
enum class State {
|
enum class State {
|
||||||
|
@ -33,6 +33,7 @@ v8_executable("unittests") {
|
|||||||
"compiler-dispatcher/compiler-dispatcher-job-unittest.cc",
|
"compiler-dispatcher/compiler-dispatcher-job-unittest.cc",
|
||||||
"compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc",
|
"compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc",
|
||||||
"compiler-dispatcher/compiler-dispatcher-unittest.cc",
|
"compiler-dispatcher/compiler-dispatcher-unittest.cc",
|
||||||
|
"compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc",
|
||||||
"compiler/branch-elimination-unittest.cc",
|
"compiler/branch-elimination-unittest.cc",
|
||||||
"compiler/bytecode-analysis-unittest.cc",
|
"compiler/bytecode-analysis-unittest.cc",
|
||||||
"compiler/checkpoint-elimination-unittest.cc",
|
"compiler/checkpoint-elimination-unittest.cc",
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2017 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 "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
|
||||||
|
|
||||||
|
#include "src/base/atomic-utils.h"
|
||||||
|
#include "src/base/platform/semaphore.h"
|
||||||
|
#include "src/compilation-info.h"
|
||||||
|
#include "src/compiler.h"
|
||||||
|
#include "src/handles.h"
|
||||||
|
#include "src/isolate.h"
|
||||||
|
#include "src/objects-inl.h"
|
||||||
|
#include "src/parsing/parse-info.h"
|
||||||
|
#include "src/zone/zone.h"
|
||||||
|
#include "test/unittests/compiler-dispatcher/compiler-dispatcher-helper.h"
|
||||||
|
#include "test/unittests/test-utils.h"
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
typedef TestWithContext OptimizingCompileDispatcherTest;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class BlockingCompilationJob : public CompilationJob {
|
||||||
|
public:
|
||||||
|
BlockingCompilationJob(Isolate* isolate, Handle<JSFunction> function)
|
||||||
|
: CompilationJob(isolate, &info_, "BlockingCompilationJob",
|
||||||
|
State::kReadyToExecute),
|
||||||
|
zone_(isolate->allocator(), ZONE_NAME),
|
||||||
|
parse_info_(&zone_, handle(function->shared())),
|
||||||
|
info_(&parse_info_, function),
|
||||||
|
blocking_(false),
|
||||||
|
semaphore_(0) {}
|
||||||
|
~BlockingCompilationJob() override = default;
|
||||||
|
|
||||||
|
bool IsBlocking() const { return blocking_.Value(); }
|
||||||
|
void Signal() { semaphore_.Signal(); }
|
||||||
|
|
||||||
|
// CompilationJob implementation.
|
||||||
|
Status PrepareJobImpl() override {
|
||||||
|
UNREACHABLE();
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status ExecuteJobImpl() override {
|
||||||
|
blocking_.SetValue(true);
|
||||||
|
semaphore_.Wait();
|
||||||
|
blocking_.SetValue(false);
|
||||||
|
return SUCCEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status FinalizeJobImpl() override { return SUCCEEDED; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Zone zone_;
|
||||||
|
ParseInfo parse_info_;
|
||||||
|
CompilationInfo info_;
|
||||||
|
base::AtomicValue<bool> blocking_;
|
||||||
|
base::Semaphore semaphore_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(BlockingCompilationJob);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(OptimizingCompileDispatcherTest, Construct) {
|
||||||
|
OptimizingCompileDispatcher dispatcher(i_isolate());
|
||||||
|
ASSERT_TRUE(OptimizingCompileDispatcher::Enabled());
|
||||||
|
ASSERT_TRUE(dispatcher.IsQueueAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptimizingCompileDispatcherTest, NonBlockingFlush) {
|
||||||
|
Handle<JSFunction> fun = Handle<JSFunction>::cast(
|
||||||
|
RunJS(isolate(), "function f() { function g() {}; return g;}; f();"));
|
||||||
|
BlockingCompilationJob* job = new BlockingCompilationJob(i_isolate(), fun);
|
||||||
|
|
||||||
|
OptimizingCompileDispatcher dispatcher(i_isolate());
|
||||||
|
ASSERT_TRUE(OptimizingCompileDispatcher::Enabled());
|
||||||
|
ASSERT_TRUE(dispatcher.IsQueueAvailable());
|
||||||
|
dispatcher.QueueForOptimization(job);
|
||||||
|
|
||||||
|
// Busy-wait for the job to run on a background thread.
|
||||||
|
while (!job->IsBlocking()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not block.
|
||||||
|
dispatcher.Flush(OptimizingCompileDispatcher::BlockingBehavior::kDontBlock);
|
||||||
|
|
||||||
|
// Unblock the job & finish.
|
||||||
|
job->Signal();
|
||||||
|
dispatcher.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
@ -87,6 +87,7 @@
|
|||||||
'compiler-dispatcher/compiler-dispatcher-job-unittest.cc',
|
'compiler-dispatcher/compiler-dispatcher-job-unittest.cc',
|
||||||
'compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc',
|
'compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc',
|
||||||
'compiler-dispatcher/compiler-dispatcher-unittest.cc',
|
'compiler-dispatcher/compiler-dispatcher-unittest.cc',
|
||||||
|
'compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc',
|
||||||
'counters-unittest.cc',
|
'counters-unittest.cc',
|
||||||
'eh-frame-iterator-unittest.cc',
|
'eh-frame-iterator-unittest.cc',
|
||||||
'eh-frame-writer-unittest.cc',
|
'eh-frame-writer-unittest.cc',
|
||||||
|
Loading…
Reference in New Issue
Block a user