[heap] Rename WorkStealingBag to Worklist.
Change-Id: I5d5df00a38b7196001fb91e2642914271d8e66d0 Reviewed-on: https://chromium-review.googlesource.com/544932 Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#46164}
This commit is contained in:
parent
217d654c9b
commit
b00de2a927
2
BUILD.gn
2
BUILD.gn
@ -1650,7 +1650,7 @@ v8_source_set("v8_base") {
|
||||
"src/heap/spaces.h",
|
||||
"src/heap/store-buffer.cc",
|
||||
"src/heap/store-buffer.h",
|
||||
"src/heap/workstealing-bag.h",
|
||||
"src/heap/worklist.h",
|
||||
"src/ic/access-compiler-data.h",
|
||||
"src/ic/access-compiler.cc",
|
||||
"src/ic/access-compiler.h",
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "src/heap/objects-visiting-inl.h"
|
||||
#include "src/heap/objects-visiting.h"
|
||||
#include "src/heap/spaces-inl.h"
|
||||
#include "src/heap/workstealing-bag.h"
|
||||
#include "src/heap/worklist.h"
|
||||
#include "src/ic/ic.h"
|
||||
#include "src/ic/stub-cache.h"
|
||||
#include "src/tracing/tracing-category-observer.h"
|
||||
@ -2205,10 +2205,9 @@ void MarkCompactCollector::RecordObjectStats() {
|
||||
|
||||
class YoungGenerationMarkingVisitor final : public NewSpaceVisitor {
|
||||
public:
|
||||
YoungGenerationMarkingVisitor(Heap* heap,
|
||||
WorkStealingBag* global_marking_deque,
|
||||
YoungGenerationMarkingVisitor(Heap* heap, Worklist* global_worklist,
|
||||
int task_id)
|
||||
: heap_(heap), marking_deque_(global_marking_deque, task_id) {}
|
||||
: heap_(heap), worklist_(global_worklist, task_id) {}
|
||||
|
||||
void VisitPointers(HeapObject* host, Object** start, Object** end) final {
|
||||
for (Object** p = start; p < end; p++) {
|
||||
@ -2236,12 +2235,12 @@ class YoungGenerationMarkingVisitor final : public NewSpaceVisitor {
|
||||
if (ObjectMarking::WhiteToGrey<AccessMode::ATOMIC>(object,
|
||||
marking_state(object))) {
|
||||
// Marking deque overflow is unsupported for the young generation.
|
||||
CHECK(marking_deque_.Push(object));
|
||||
CHECK(worklist_.Push(object));
|
||||
}
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
LocalWorkStealingBag marking_deque_;
|
||||
WorklistView worklist_;
|
||||
};
|
||||
|
||||
class MinorMarkCompactCollector::RootMarkingVisitor : public RootVisitor {
|
||||
@ -2297,7 +2296,7 @@ class YoungGenerationMarkingTask : public ItemParallelJob::Task {
|
||||
public:
|
||||
YoungGenerationMarkingTask(Isolate* isolate,
|
||||
MinorMarkCompactCollector* collector,
|
||||
WorkStealingBag* marking_deque, int task_id)
|
||||
Worklist* marking_deque, int task_id)
|
||||
: ItemParallelJob::Task(isolate),
|
||||
collector_(collector),
|
||||
marking_deque_(marking_deque, task_id),
|
||||
@ -2370,7 +2369,7 @@ class YoungGenerationMarkingTask : public ItemParallelJob::Task {
|
||||
}
|
||||
|
||||
MinorMarkCompactCollector* collector_;
|
||||
LocalWorkStealingBag marking_deque_;
|
||||
WorklistView marking_deque_;
|
||||
YoungGenerationMarkingVisitor visitor_;
|
||||
std::unordered_map<Page*, intptr_t, Page::Hasher> local_live_bytes_;
|
||||
};
|
||||
@ -2534,16 +2533,16 @@ class MinorMarkCompactCollector::RootMarkingVisitorSeedOnly
|
||||
|
||||
MinorMarkCompactCollector::MinorMarkCompactCollector(Heap* heap)
|
||||
: MarkCompactCollectorBase(heap),
|
||||
marking_deque_(new WorkStealingBag()),
|
||||
worklist_(new Worklist()),
|
||||
main_marking_visitor_(
|
||||
new YoungGenerationMarkingVisitor(heap, marking_deque_, kMainMarker)),
|
||||
new YoungGenerationMarkingVisitor(heap, worklist_, kMainMarker)),
|
||||
page_parallel_job_semaphore_(0) {
|
||||
static_assert(kNumMarkers <= WorkStealingBag::kMaxNumTasks,
|
||||
static_assert(kNumMarkers <= Worklist::kMaxNumTasks,
|
||||
"more marker tasks than marking deque can handle");
|
||||
}
|
||||
|
||||
MinorMarkCompactCollector::~MinorMarkCompactCollector() {
|
||||
delete marking_deque_;
|
||||
delete worklist_;
|
||||
delete main_marking_visitor_;
|
||||
}
|
||||
|
||||
@ -2599,11 +2598,11 @@ void MinorMarkCompactCollector::MarkRootSetInParallel() {
|
||||
static_cast<int>(heap()->new_space()->Capacity()) / Page::kPageSize;
|
||||
const int num_tasks = NumberOfParallelMarkingTasks(new_space_pages);
|
||||
for (int i = 0; i < num_tasks; i++) {
|
||||
job.AddTask(new YoungGenerationMarkingTask(isolate(), this,
|
||||
marking_deque(), i));
|
||||
job.AddTask(
|
||||
new YoungGenerationMarkingTask(isolate(), this, worklist(), i));
|
||||
}
|
||||
job.Run();
|
||||
DCHECK(marking_deque()->IsGlobalEmpty());
|
||||
DCHECK(worklist()->IsGlobalEmpty());
|
||||
}
|
||||
}
|
||||
old_to_new_slots_ = static_cast<int>(slots.Value());
|
||||
@ -2640,9 +2639,9 @@ void MinorMarkCompactCollector::ProcessMarkingDeque() {
|
||||
}
|
||||
|
||||
void MinorMarkCompactCollector::EmptyMarkingDeque() {
|
||||
LocalWorkStealingBag local_marking_deque(marking_deque(), kMainMarker);
|
||||
WorklistView worklist_view(worklist(), kMainMarker);
|
||||
HeapObject* object = nullptr;
|
||||
while (local_marking_deque.Pop(&object)) {
|
||||
while (worklist_view.Pop(&object)) {
|
||||
DCHECK(!object->IsFiller());
|
||||
DCHECK(object->IsHeapObject());
|
||||
DCHECK(heap()->Contains(object));
|
||||
@ -2652,7 +2651,7 @@ void MinorMarkCompactCollector::EmptyMarkingDeque() {
|
||||
object, marking_state(object))));
|
||||
main_marking_visitor()->Visit(object);
|
||||
}
|
||||
DCHECK(local_marking_deque.IsLocalEmpty());
|
||||
DCHECK(worklist_view.IsLocalEmpty());
|
||||
}
|
||||
|
||||
void MinorMarkCompactCollector::CollectGarbage() {
|
||||
|
@ -23,14 +23,14 @@ namespace internal {
|
||||
class EvacuationJobTraits;
|
||||
class HeapObjectVisitor;
|
||||
class ItemParallelJob;
|
||||
class LocalWorkStealingBag;
|
||||
class WorklistView;
|
||||
class MarkCompactCollector;
|
||||
class MinorMarkCompactCollector;
|
||||
class MarkingVisitor;
|
||||
class MigrationObserver;
|
||||
class RecordMigratedSlotVisitor;
|
||||
class ThreadLocalTop;
|
||||
class WorkStealingBag;
|
||||
class Worklist;
|
||||
class YoungGenerationMarkingVisitor;
|
||||
|
||||
#ifdef V8_CONCURRENT_MARKING
|
||||
@ -352,7 +352,7 @@ class MinorMarkCompactCollector final : public MarkCompactCollectorBase {
|
||||
static const int kNumMarkers = 8;
|
||||
static const int kMainMarker = 0;
|
||||
|
||||
inline WorkStealingBag* marking_deque() { return marking_deque_; }
|
||||
inline Worklist* worklist() { return worklist_; }
|
||||
|
||||
inline YoungGenerationMarkingVisitor* main_marking_visitor() {
|
||||
return main_marking_visitor_;
|
||||
@ -372,7 +372,7 @@ class MinorMarkCompactCollector final : public MarkCompactCollectorBase {
|
||||
|
||||
int NumberOfParallelMarkingTasks(int pages);
|
||||
|
||||
WorkStealingBag* marking_deque_;
|
||||
Worklist* worklist_;
|
||||
YoungGenerationMarkingVisitor* main_marking_visitor_;
|
||||
base::Semaphore page_parallel_job_semaphore_;
|
||||
List<Page*> new_space_evacuation_pages_;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_HEAP_WORKSTEALING_BAG_
|
||||
#define V8_HEAP_WORKSTEALING_BAG_
|
||||
#ifndef V8_HEAP_WORKLIST_
|
||||
#define V8_HEAP_WORKLIST_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
@ -18,26 +18,26 @@ namespace internal {
|
||||
|
||||
class HeapObject;
|
||||
|
||||
// A concurrent work stealing bag based on segments. Each tasks gets private
|
||||
// A concurrent worklist based on segments. Each tasks gets private
|
||||
// push and pop segments. Empty pop segments are swapped with their
|
||||
// corresponding push segments. Full push segments are published to a global
|
||||
// pool of segments and replaced with empty segments.
|
||||
//
|
||||
// Work stealing is best effort, i.e., there is no way to inform other tasks
|
||||
// of the need of items.
|
||||
class WorkStealingBag {
|
||||
class Worklist {
|
||||
public:
|
||||
static const int kMaxNumTasks = 8;
|
||||
static const int kSegmentCapacity = 64;
|
||||
|
||||
WorkStealingBag() {
|
||||
Worklist() {
|
||||
for (int i = 0; i < kMaxNumTasks; i++) {
|
||||
private_push_segment_[i] = new Segment();
|
||||
private_pop_segment_[i] = new Segment();
|
||||
}
|
||||
}
|
||||
|
||||
~WorkStealingBag() {
|
||||
~Worklist() {
|
||||
CHECK(IsGlobalEmpty());
|
||||
for (int i = 0; i < kMaxNumTasks; i++) {
|
||||
DCHECK_NOT_NULL(private_push_segment_[i]);
|
||||
@ -90,14 +90,14 @@ class WorkStealingBag {
|
||||
}
|
||||
|
||||
private:
|
||||
FRIEND_TEST(WorkStealingBag, SegmentCreate);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentPush);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentPushPop);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentIsEmpty);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentIsFull);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentClear);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentFullPushFails);
|
||||
FRIEND_TEST(WorkStealingBag, SegmentEmptyPopFails);
|
||||
FRIEND_TEST(Worklist, SegmentCreate);
|
||||
FRIEND_TEST(Worklist, SegmentPush);
|
||||
FRIEND_TEST(Worklist, SegmentPushPop);
|
||||
FRIEND_TEST(Worklist, SegmentIsEmpty);
|
||||
FRIEND_TEST(Worklist, SegmentIsFull);
|
||||
FRIEND_TEST(Worklist, SegmentClear);
|
||||
FRIEND_TEST(Worklist, SegmentFullPushFails);
|
||||
FRIEND_TEST(Worklist, SegmentEmptyPopFails);
|
||||
|
||||
class Segment {
|
||||
public:
|
||||
@ -154,26 +154,26 @@ class WorkStealingBag {
|
||||
std::vector<Segment*> global_pool_;
|
||||
};
|
||||
|
||||
class LocalWorkStealingBag {
|
||||
class WorklistView {
|
||||
public:
|
||||
LocalWorkStealingBag(WorkStealingBag* bag, int task_id)
|
||||
: bag_(bag), task_id_(task_id) {}
|
||||
WorklistView(Worklist* worklist, int task_id)
|
||||
: worklist_(worklist), task_id_(task_id) {}
|
||||
|
||||
// Pushes an object onto the bag.
|
||||
bool Push(HeapObject* object) { return bag_->Push(task_id_, object); }
|
||||
// Pushes an object onto the worklist.
|
||||
bool Push(HeapObject* object) { return worklist_->Push(task_id_, object); }
|
||||
|
||||
// Pops an object from the bag.
|
||||
bool Pop(HeapObject** object) { return bag_->Pop(task_id_, object); }
|
||||
// Pops an object from the worklist.
|
||||
bool Pop(HeapObject** object) { return worklist_->Pop(task_id_, object); }
|
||||
|
||||
// Returns true if the local portion of the bag is empty.
|
||||
bool IsLocalEmpty() { return bag_->IsLocalEmpty(task_id_); }
|
||||
// Returns true if the local portion of the worklist is empty.
|
||||
bool IsLocalEmpty() { return worklist_->IsLocalEmpty(task_id_); }
|
||||
|
||||
// Returns true if the bag is empty. Can only be used from the main thread
|
||||
// without concurrent access.
|
||||
bool IsGlobalEmpty() { return bag_->IsGlobalEmpty(); }
|
||||
// Returns true if the worklist is empty. Can only be used from the main
|
||||
// thread without concurrent access.
|
||||
bool IsGlobalEmpty() { return worklist_->IsGlobalEmpty(); }
|
||||
|
||||
private:
|
||||
WorkStealingBag* bag_;
|
||||
Worklist* worklist_;
|
||||
int task_id_;
|
||||
};
|
||||
|
@ -1107,7 +1107,7 @@
|
||||
'heap/spaces.h',
|
||||
'heap/store-buffer.cc',
|
||||
'heap/store-buffer.h',
|
||||
'heap/workstealing-bag.h',
|
||||
'heap/worklist.h',
|
||||
'intl.cc',
|
||||
'intl.h',
|
||||
'icu_util.cc',
|
||||
|
@ -113,7 +113,7 @@ v8_executable("unittests") {
|
||||
"heap/slot-set-unittest.cc",
|
||||
"heap/spaces-unittest.cc",
|
||||
"heap/unmapper-unittest.cc",
|
||||
"heap/workstealing-bag-unittest.cc",
|
||||
"heap/worklist-unittest.cc",
|
||||
"interpreter/bytecode-array-builder-unittest.cc",
|
||||
"interpreter/bytecode-array-iterator-unittest.cc",
|
||||
"interpreter/bytecode-array-random-iterator-unittest.cc",
|
||||
|
196
test/unittests/heap/worklist-unittest.cc
Normal file
196
test/unittests/heap/worklist-unittest.cc
Normal file
@ -0,0 +1,196 @@
|
||||
// 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/heap/worklist.h"
|
||||
|
||||
#include "test/unittests/test-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class HeapObject {};
|
||||
|
||||
TEST(Worklist, SegmentCreate) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentPush) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_EQ(1u, segment.Size());
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentPushPop) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_EQ(1u, segment.Size());
|
||||
HeapObject dummy;
|
||||
HeapObject* object = &dummy;
|
||||
EXPECT_TRUE(segment.Pop(&object));
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_EQ(nullptr, object);
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentIsEmpty) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_FALSE(segment.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentIsFull) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
EXPECT_TRUE(segment.IsFull());
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentClear) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_FALSE(segment.IsEmpty());
|
||||
segment.Clear();
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentFullPushFails) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
EXPECT_TRUE(segment.IsFull());
|
||||
EXPECT_FALSE(segment.Push(nullptr));
|
||||
}
|
||||
|
||||
TEST(Worklist, SegmentEmptyPopFails) {
|
||||
Worklist::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
HeapObject* object;
|
||||
EXPECT_FALSE(segment.Pop(&object));
|
||||
}
|
||||
|
||||
TEST(Worklist, CreateEmpty) {
|
||||
Worklist worklist;
|
||||
WorklistView worklist_view(&worklist, 0);
|
||||
EXPECT_TRUE(worklist_view.IsLocalEmpty());
|
||||
EXPECT_TRUE(worklist.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(Worklist, LocalPushPop) {
|
||||
Worklist worklist;
|
||||
WorklistView worklist_view(&worklist, 0);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(worklist_view.Push(&dummy));
|
||||
EXPECT_FALSE(worklist_view.IsLocalEmpty());
|
||||
EXPECT_TRUE(worklist_view.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
}
|
||||
|
||||
TEST(Worklist, LocalIsBasedOnId) {
|
||||
Worklist worklist;
|
||||
// Use the same id.
|
||||
WorklistView worklist_view1(&worklist, 0);
|
||||
WorklistView worklist_view2(&worklist, 0);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy));
|
||||
EXPECT_FALSE(worklist_view1.IsLocalEmpty());
|
||||
EXPECT_FALSE(worklist_view2.IsLocalEmpty());
|
||||
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_TRUE(worklist_view1.IsLocalEmpty());
|
||||
EXPECT_TRUE(worklist_view2.IsLocalEmpty());
|
||||
}
|
||||
|
||||
TEST(Worklist, LocalPushStaysPrivate) {
|
||||
Worklist worklist;
|
||||
WorklistView worklist_view1(&worklist, 0);
|
||||
WorklistView worklist_view2(&worklist, 1);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(worklist.IsGlobalEmpty());
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy));
|
||||
EXPECT_FALSE(worklist.IsGlobalEmpty());
|
||||
EXPECT_FALSE(worklist_view2.Pop(&retrieved));
|
||||
EXPECT_EQ(nullptr, retrieved);
|
||||
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_TRUE(worklist.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(Worklist, SingleSegmentSteal) {
|
||||
Worklist worklist;
|
||||
WorklistView worklist_view1(&worklist, 0);
|
||||
WorklistView worklist_view2(&worklist, 1);
|
||||
HeapObject dummy;
|
||||
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy));
|
||||
}
|
||||
HeapObject* retrieved = nullptr;
|
||||
// One more push/pop to publish the full segment.
|
||||
EXPECT_TRUE(worklist_view1.Push(nullptr));
|
||||
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
|
||||
EXPECT_EQ(nullptr, retrieved);
|
||||
// Stealing.
|
||||
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
|
||||
}
|
||||
EXPECT_TRUE(worklist.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(Worklist, MultipleSegmentsStolen) {
|
||||
Worklist worklist;
|
||||
WorklistView worklist_view1(&worklist, 0);
|
||||
WorklistView worklist_view2(&worklist, 1);
|
||||
WorklistView worklist_view3(&worklist, 2);
|
||||
HeapObject dummy1;
|
||||
HeapObject dummy2;
|
||||
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy1));
|
||||
}
|
||||
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy2));
|
||||
}
|
||||
HeapObject* retrieved = nullptr;
|
||||
HeapObject dummy3;
|
||||
// One more push/pop to publish the full segment.
|
||||
EXPECT_TRUE(worklist_view1.Push(&dummy3));
|
||||
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy3, retrieved);
|
||||
// Stealing.
|
||||
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
|
||||
HeapObject* const expect_bag2 = retrieved;
|
||||
EXPECT_TRUE(worklist_view3.Pop(&retrieved));
|
||||
HeapObject* const expect_bag3 = retrieved;
|
||||
EXPECT_NE(expect_bag2, expect_bag3);
|
||||
EXPECT_TRUE(expect_bag2 == &dummy1 || expect_bag2 == &dummy2);
|
||||
EXPECT_TRUE(expect_bag3 == &dummy1 || expect_bag3 == &dummy2);
|
||||
for (size_t i = 1; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
|
||||
EXPECT_EQ(expect_bag2, retrieved);
|
||||
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
|
||||
}
|
||||
for (size_t i = 1; i < Worklist::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(worklist_view3.Pop(&retrieved));
|
||||
EXPECT_EQ(expect_bag3, retrieved);
|
||||
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
|
||||
}
|
||||
EXPECT_TRUE(worklist.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,196 +0,0 @@
|
||||
// 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/heap/workstealing-bag.h"
|
||||
|
||||
#include "test/unittests/test-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class HeapObject {};
|
||||
|
||||
TEST(WorkStealingBag, SegmentCreate) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentPush) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_EQ(1u, segment.Size());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentPushPop) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_EQ(1u, segment.Size());
|
||||
HeapObject dummy;
|
||||
HeapObject* object = &dummy;
|
||||
EXPECT_TRUE(segment.Pop(&object));
|
||||
EXPECT_EQ(0u, segment.Size());
|
||||
EXPECT_EQ(nullptr, object);
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentIsEmpty) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_FALSE(segment.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentIsFull) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
EXPECT_TRUE(segment.IsFull());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentClear) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
EXPECT_FALSE(segment.IsEmpty());
|
||||
segment.Clear();
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentFullPushFails) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_FALSE(segment.IsFull());
|
||||
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
|
||||
EXPECT_TRUE(segment.Push(nullptr));
|
||||
}
|
||||
EXPECT_TRUE(segment.IsFull());
|
||||
EXPECT_FALSE(segment.Push(nullptr));
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SegmentEmptyPopFails) {
|
||||
WorkStealingBag::Segment segment;
|
||||
EXPECT_TRUE(segment.IsEmpty());
|
||||
HeapObject* object;
|
||||
EXPECT_FALSE(segment.Pop(&object));
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, CreateEmpty) {
|
||||
WorkStealingBag marking_bag;
|
||||
LocalWorkStealingBag local_marking_bag(&marking_bag, 0);
|
||||
EXPECT_TRUE(local_marking_bag.IsLocalEmpty());
|
||||
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, LocalPushPop) {
|
||||
WorkStealingBag marking_bag;
|
||||
LocalWorkStealingBag local_marking_bag(&marking_bag, 0);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(local_marking_bag.Push(&dummy));
|
||||
EXPECT_FALSE(local_marking_bag.IsLocalEmpty());
|
||||
EXPECT_TRUE(local_marking_bag.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, LocalIsBasedOnId) {
|
||||
WorkStealingBag marking_bag;
|
||||
// Use the same id.
|
||||
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
|
||||
LocalWorkStealingBag local_marking_bag2(&marking_bag, 0);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
|
||||
EXPECT_FALSE(local_marking_bag1.IsLocalEmpty());
|
||||
EXPECT_FALSE(local_marking_bag2.IsLocalEmpty());
|
||||
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_TRUE(local_marking_bag1.IsLocalEmpty());
|
||||
EXPECT_TRUE(local_marking_bag2.IsLocalEmpty());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, LocalPushStaysPrivate) {
|
||||
WorkStealingBag marking_bag;
|
||||
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
|
||||
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
|
||||
HeapObject dummy;
|
||||
HeapObject* retrieved = nullptr;
|
||||
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
|
||||
EXPECT_FALSE(marking_bag.IsGlobalEmpty());
|
||||
EXPECT_FALSE(local_marking_bag2.Pop(&retrieved));
|
||||
EXPECT_EQ(nullptr, retrieved);
|
||||
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, SingleSegmentSteal) {
|
||||
WorkStealingBag marking_bag;
|
||||
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
|
||||
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
|
||||
HeapObject dummy;
|
||||
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
|
||||
}
|
||||
HeapObject* retrieved = nullptr;
|
||||
// One more push/pop to publish the full segment.
|
||||
EXPECT_TRUE(local_marking_bag1.Push(nullptr));
|
||||
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
|
||||
EXPECT_EQ(nullptr, retrieved);
|
||||
// Stealing.
|
||||
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy, retrieved);
|
||||
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
|
||||
}
|
||||
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
TEST(WorkStealingBag, MultipleSegmentsStolen) {
|
||||
WorkStealingBag marking_bag;
|
||||
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
|
||||
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
|
||||
LocalWorkStealingBag local_marking_bag3(&marking_bag, 2);
|
||||
HeapObject dummy1;
|
||||
HeapObject dummy2;
|
||||
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy1));
|
||||
}
|
||||
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy2));
|
||||
}
|
||||
HeapObject* retrieved = nullptr;
|
||||
HeapObject dummy3;
|
||||
// One more push/pop to publish the full segment.
|
||||
EXPECT_TRUE(local_marking_bag1.Push(&dummy3));
|
||||
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
|
||||
EXPECT_EQ(&dummy3, retrieved);
|
||||
// Stealing.
|
||||
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
|
||||
HeapObject* const expect_bag2 = retrieved;
|
||||
EXPECT_TRUE(local_marking_bag3.Pop(&retrieved));
|
||||
HeapObject* const expect_bag3 = retrieved;
|
||||
EXPECT_NE(expect_bag2, expect_bag3);
|
||||
EXPECT_TRUE(expect_bag2 == &dummy1 || expect_bag2 == &dummy2);
|
||||
EXPECT_TRUE(expect_bag3 == &dummy1 || expect_bag3 == &dummy2);
|
||||
for (size_t i = 1; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
|
||||
EXPECT_EQ(expect_bag2, retrieved);
|
||||
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
|
||||
}
|
||||
for (size_t i = 1; i < WorkStealingBag::kSegmentCapacity; i++) {
|
||||
EXPECT_TRUE(local_marking_bag3.Pop(&retrieved));
|
||||
EXPECT_EQ(expect_bag3, retrieved);
|
||||
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
|
||||
}
|
||||
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -110,7 +110,7 @@
|
||||
'heap/slot-set-unittest.cc',
|
||||
'heap/spaces-unittest.cc',
|
||||
'heap/unmapper-unittest.cc',
|
||||
'heap/workstealing-bag-unittest.cc',
|
||||
'heap/worklist-unittest.cc',
|
||||
'interpreter/bytecodes-unittest.cc',
|
||||
'interpreter/bytecode-array-builder-unittest.cc',
|
||||
'interpreter/bytecode-array-iterator-unittest.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user