2020-04-15 10:49:38 +00:00
|
|
|
// Copyright 2020 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 <memory>
|
|
|
|
|
|
|
|
#include "src/api/api.h"
|
|
|
|
#include "src/base/platform/condition-variable.h"
|
|
|
|
#include "src/base/platform/mutex.h"
|
|
|
|
#include "src/base/platform/semaphore.h"
|
|
|
|
#include "src/common/globals.h"
|
|
|
|
#include "src/handles/handles-inl.h"
|
|
|
|
#include "src/handles/local-handles-inl.h"
|
|
|
|
#include "src/handles/persistent-handles.h"
|
|
|
|
#include "src/heap/concurrent-allocator-inl.h"
|
|
|
|
#include "src/heap/heap.h"
|
|
|
|
#include "src/heap/local-heap.h"
|
|
|
|
#include "src/heap/safepoint.h"
|
|
|
|
#include "src/objects/heap-number.h"
|
2020-05-26 12:27:52 +00:00
|
|
|
#include "src/objects/heap-object.h"
|
2020-04-15 10:49:38 +00:00
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "test/cctest/heap/heap-utils.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
2020-05-26 12:27:52 +00:00
|
|
|
void CreateFixedArray(Heap* heap, Address start, int size) {
|
|
|
|
HeapObject object = HeapObject::FromAddress(start);
|
|
|
|
object.set_map_after_allocation(ReadOnlyRoots(heap).fixed_array_map(),
|
|
|
|
SKIP_WRITE_BARRIER);
|
|
|
|
FixedArray array = FixedArray::cast(object);
|
|
|
|
int length = (size - FixedArray::kHeaderSize) / kTaggedSize;
|
|
|
|
array.set_length(length);
|
|
|
|
MemsetTagged(array.data_start(), ReadOnlyRoots(heap).undefined_value(),
|
|
|
|
length);
|
|
|
|
}
|
|
|
|
|
2020-04-30 10:03:24 +00:00
|
|
|
const int kNumIterations = 2000;
|
2020-05-26 12:27:52 +00:00
|
|
|
const int kSmallObjectSize = 10 * kTaggedSize;
|
|
|
|
const int kMediumObjectSize = 8 * KB;
|
2020-04-15 10:49:38 +00:00
|
|
|
|
|
|
|
class ConcurrentAllocationThread final : public v8::base::Thread {
|
|
|
|
public:
|
2020-04-30 10:03:24 +00:00
|
|
|
explicit ConcurrentAllocationThread(Heap* heap, std::atomic<int>* pending)
|
2020-04-15 10:49:38 +00:00
|
|
|
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
2020-04-30 10:03:24 +00:00
|
|
|
heap_(heap),
|
|
|
|
pending_(pending) {}
|
2020-04-15 10:49:38 +00:00
|
|
|
|
|
|
|
void Run() override {
|
|
|
|
LocalHeap local_heap(heap_);
|
|
|
|
ConcurrentAllocator* allocator = local_heap.old_space_allocator();
|
|
|
|
|
2020-04-30 10:03:24 +00:00
|
|
|
for (int i = 0; i < kNumIterations; i++) {
|
|
|
|
Address address = allocator->AllocateOrFail(
|
2020-05-26 12:27:52 +00:00
|
|
|
kSmallObjectSize, AllocationAlignment::kWordAligned,
|
2020-04-30 10:03:24 +00:00
|
|
|
AllocationOrigin::kRuntime);
|
2020-05-26 12:27:52 +00:00
|
|
|
CreateFixedArray(heap_, address, kSmallObjectSize);
|
|
|
|
address = allocator->AllocateOrFail(kMediumObjectSize,
|
2020-04-30 10:03:24 +00:00
|
|
|
AllocationAlignment::kWordAligned,
|
|
|
|
AllocationOrigin::kRuntime);
|
2020-05-26 12:27:52 +00:00
|
|
|
CreateFixedArray(heap_, address, kMediumObjectSize);
|
2020-05-08 08:18:37 +00:00
|
|
|
if (i % 10 == 0) {
|
|
|
|
local_heap.Safepoint();
|
|
|
|
}
|
2020-04-15 10:49:38 +00:00
|
|
|
}
|
2020-04-30 10:03:24 +00:00
|
|
|
|
|
|
|
pending_->fetch_sub(1);
|
2020-04-15 10:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Heap* heap_;
|
2020-04-30 10:03:24 +00:00
|
|
|
std::atomic<int>* pending_;
|
2020-04-15 10:49:38 +00:00
|
|
|
};
|
|
|
|
|
2020-04-30 10:03:24 +00:00
|
|
|
UNINITIALIZED_TEST(ConcurrentAllocationInOldSpace) {
|
2020-05-08 08:18:37 +00:00
|
|
|
FLAG_max_old_space_size = 32;
|
2020-04-15 10:49:38 +00:00
|
|
|
FLAG_concurrent_allocation = true;
|
2020-06-02 20:28:29 +00:00
|
|
|
FLAG_local_heaps = true;
|
2020-04-30 10:03:24 +00:00
|
|
|
|
|
|
|
v8::Isolate::CreateParams create_params;
|
|
|
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
|
|
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
|
|
|
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
|
|
|
|
|
2020-04-15 10:49:38 +00:00
|
|
|
std::vector<std::unique_ptr<ConcurrentAllocationThread>> threads;
|
|
|
|
|
|
|
|
const int kThreads = 4;
|
|
|
|
|
2020-04-30 10:03:24 +00:00
|
|
|
std::atomic<int> pending(kThreads);
|
|
|
|
|
2020-04-15 10:49:38 +00:00
|
|
|
for (int i = 0; i < kThreads; i++) {
|
2020-04-30 10:03:24 +00:00
|
|
|
auto thread = std::make_unique<ConcurrentAllocationThread>(
|
|
|
|
i_isolate->heap(), &pending);
|
2020-04-15 10:49:38 +00:00
|
|
|
CHECK(thread->Start());
|
|
|
|
threads.push_back(std::move(thread));
|
|
|
|
}
|
|
|
|
|
2020-04-30 10:03:24 +00:00
|
|
|
while (pending > 0) {
|
|
|
|
v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), isolate);
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:49:38 +00:00
|
|
|
for (auto& thread : threads) {
|
|
|
|
thread->Join();
|
|
|
|
}
|
2020-04-30 10:03:24 +00:00
|
|
|
|
|
|
|
isolate->Dispose();
|
2020-04-15 10:49:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 12:27:52 +00:00
|
|
|
const int kWhiteIterations = 1000;
|
|
|
|
|
|
|
|
class ConcurrentBlackAllocationThread final : public v8::base::Thread {
|
|
|
|
public:
|
|
|
|
explicit ConcurrentBlackAllocationThread(
|
|
|
|
Heap* heap, std::vector<Address>* objects, base::Semaphore* sema_white,
|
|
|
|
base::Semaphore* sema_marking_started)
|
|
|
|
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
|
|
|
heap_(heap),
|
|
|
|
objects_(objects),
|
|
|
|
sema_white_(sema_white),
|
|
|
|
sema_marking_started_(sema_marking_started) {}
|
|
|
|
|
|
|
|
void Run() override {
|
|
|
|
LocalHeap local_heap(heap_);
|
|
|
|
ConcurrentAllocator* allocator = local_heap.old_space_allocator();
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumIterations; i++) {
|
|
|
|
if (i == kWhiteIterations) {
|
|
|
|
ParkedScope scope(&local_heap);
|
|
|
|
sema_white_->Signal();
|
|
|
|
sema_marking_started_->Wait();
|
|
|
|
}
|
|
|
|
Address address = allocator->AllocateOrFail(
|
|
|
|
kSmallObjectSize, AllocationAlignment::kWordAligned,
|
|
|
|
AllocationOrigin::kRuntime);
|
|
|
|
objects_->push_back(address);
|
|
|
|
CreateFixedArray(heap_, address, kSmallObjectSize);
|
|
|
|
address = allocator->AllocateOrFail(kMediumObjectSize,
|
|
|
|
AllocationAlignment::kWordAligned,
|
|
|
|
AllocationOrigin::kRuntime);
|
|
|
|
objects_->push_back(address);
|
|
|
|
CreateFixedArray(heap_, address, kMediumObjectSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Heap* heap_;
|
|
|
|
std::vector<Address>* objects_;
|
|
|
|
base::Semaphore* sema_white_;
|
|
|
|
base::Semaphore* sema_marking_started_;
|
|
|
|
};
|
|
|
|
|
|
|
|
UNINITIALIZED_TEST(ConcurrentBlackAllocation) {
|
|
|
|
FLAG_concurrent_allocation = true;
|
2020-06-02 20:28:29 +00:00
|
|
|
FLAG_local_heaps = true;
|
2020-05-26 12:27:52 +00:00
|
|
|
|
|
|
|
v8::Isolate::CreateParams create_params;
|
|
|
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
|
|
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
|
|
|
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
|
|
|
|
Heap* heap = i_isolate->heap();
|
|
|
|
|
|
|
|
std::vector<Address> objects;
|
|
|
|
|
|
|
|
base::Semaphore sema_white(0);
|
|
|
|
base::Semaphore sema_marking_started(0);
|
|
|
|
|
|
|
|
auto thread = std::make_unique<ConcurrentBlackAllocationThread>(
|
|
|
|
heap, &objects, &sema_white, &sema_marking_started);
|
|
|
|
CHECK(thread->Start());
|
|
|
|
|
|
|
|
sema_white.Wait();
|
|
|
|
heap->StartIncrementalMarking(i::Heap::kNoGCFlags,
|
|
|
|
i::GarbageCollectionReason::kTesting);
|
|
|
|
sema_marking_started.Signal();
|
|
|
|
|
|
|
|
thread->Join();
|
|
|
|
|
|
|
|
const int kObjectsAllocatedPerIteration = 2;
|
|
|
|
|
|
|
|
for (int i = 0; i < kNumIterations * kObjectsAllocatedPerIteration; i++) {
|
|
|
|
Address address = objects[i];
|
|
|
|
HeapObject object = HeapObject::FromAddress(address);
|
|
|
|
|
|
|
|
if (i < kWhiteIterations * kObjectsAllocatedPerIteration) {
|
|
|
|
CHECK(heap->incremental_marking()->marking_state()->IsWhite(object));
|
|
|
|
} else {
|
|
|
|
CHECK(heap->incremental_marking()->marking_state()->IsBlack(object));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isolate->Dispose();
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:49:38 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|