[Heap]: Implement IndexGenerator for Jobs use cases.
Dynamic index generation used as starting seend boosts performance for Jobs that have many work items. This is taken from https://source.chromium.org/chromium/chromium/src/+/master:base/task/job_perftest.cc;l=30?q=job_perftest&ss=chromium Change-Id: Ie1ba432808f07498f90ab4c0af419b8f9b72e342 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2405799 Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#69854}
This commit is contained in:
parent
30c57eb930
commit
0d813976ea
2
BUILD.gn
2
BUILD.gn
@ -2595,6 +2595,8 @@ v8_source_set("v8_base_without_compiler") {
|
|||||||
"src/heap/incremental-marking-job.h",
|
"src/heap/incremental-marking-job.h",
|
||||||
"src/heap/incremental-marking.cc",
|
"src/heap/incremental-marking.cc",
|
||||||
"src/heap/incremental-marking.h",
|
"src/heap/incremental-marking.h",
|
||||||
|
"src/heap/index-generator.cc",
|
||||||
|
"src/heap/index-generator.h",
|
||||||
"src/heap/invalidated-slots-inl.h",
|
"src/heap/invalidated-slots-inl.h",
|
||||||
"src/heap/invalidated-slots.cc",
|
"src/heap/invalidated-slots.cc",
|
||||||
"src/heap/invalidated-slots.h",
|
"src/heap/invalidated-slots.h",
|
||||||
|
48
src/heap/index-generator.cc
Normal file
48
src/heap/index-generator.cc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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 "src/heap/index-generator.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
IndexGenerator::IndexGenerator(size_t size) : size_(size) {
|
||||||
|
if (size == 0) return;
|
||||||
|
base::MutexGuard guard(&lock_);
|
||||||
|
pending_indices_.push(0);
|
||||||
|
ranges_to_split_.push({0, size_});
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Optional<size_t> IndexGenerator::GetNext() {
|
||||||
|
base::MutexGuard guard(&lock_);
|
||||||
|
if (!pending_indices_.empty()) {
|
||||||
|
// Return any pending index first.
|
||||||
|
auto index = pending_indices_.top();
|
||||||
|
pending_indices_.pop();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
if (ranges_to_split_.empty()) return base::nullopt;
|
||||||
|
|
||||||
|
// Split the oldest running range in 2 and return the middle index as
|
||||||
|
// starting point.
|
||||||
|
auto range = ranges_to_split_.front();
|
||||||
|
ranges_to_split_.pop();
|
||||||
|
size_t size = range.second - range.first;
|
||||||
|
size_t mid = range.first + size / 2;
|
||||||
|
// Both sides of the range are added to |ranges_to_split_| so they may be
|
||||||
|
// further split if possible.
|
||||||
|
if (mid - range.first > 1) ranges_to_split_.push({range.first, mid});
|
||||||
|
if (range.second - mid > 1) ranges_to_split_.push({mid, range.second});
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexGenerator::GiveBack(size_t index) {
|
||||||
|
base::MutexGuard guard(&lock_);
|
||||||
|
// Add |index| to pending indices so GetNext() may return it before anything
|
||||||
|
// else.
|
||||||
|
pending_indices_.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
43
src/heap/index-generator.h
Normal file
43
src/heap/index-generator.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef V8_HEAP_INDEX_GENERATOR_H_
|
||||||
|
#define V8_HEAP_INDEX_GENERATOR_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <queue>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
#include "src/base/macros.h"
|
||||||
|
#include "src/base/optional.h"
|
||||||
|
#include "src/base/platform/mutex.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// A thread-safe data structure that generates heuristic starting points in a
|
||||||
|
// range to process items in parallel.
|
||||||
|
class V8_EXPORT_PRIVATE IndexGenerator {
|
||||||
|
public:
|
||||||
|
explicit IndexGenerator(size_t size);
|
||||||
|
IndexGenerator(const IndexGenerator&) = delete;
|
||||||
|
IndexGenerator& operator=(const IndexGenerator&) = delete;
|
||||||
|
|
||||||
|
base::Optional<size_t> GetNext();
|
||||||
|
void GiveBack(size_t index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
base::Mutex lock_;
|
||||||
|
// Pending indices that are ready to be handed out, prioritized over
|
||||||
|
// |pending_ranges_| when non-empty.
|
||||||
|
std::stack<size_t> pending_indices_;
|
||||||
|
// Pending [start, end] (exclusive) ranges to split and hand out indices from.
|
||||||
|
std::queue<std::pair<size_t, size_t>> ranges_to_split_;
|
||||||
|
const size_t size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // V8_HEAP_INDEX_GENERATOR_H_
|
@ -279,6 +279,7 @@ v8_source_set("unittests_sources") {
|
|||||||
"heap/heap-controller-unittest.cc",
|
"heap/heap-controller-unittest.cc",
|
||||||
"heap/heap-unittest.cc",
|
"heap/heap-unittest.cc",
|
||||||
"heap/heap-utils.h",
|
"heap/heap-utils.h",
|
||||||
|
"heap/index-generator-unittest.cc",
|
||||||
"heap/item-parallel-job-unittest.cc",
|
"heap/item-parallel-job-unittest.cc",
|
||||||
"heap/js-member-unittest.cc",
|
"heap/js-member-unittest.cc",
|
||||||
"heap/list-unittest.cc",
|
"heap/list-unittest.cc",
|
||||||
|
50
test/unittests/heap/index-generator-unittest.cc
Normal file
50
test/unittests/heap/index-generator-unittest.cc
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// 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 "src/heap/index-generator.h"
|
||||||
|
|
||||||
|
#include "test/unittests/test-utils.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
TEST(IndexGeneratorTest, Empty) {
|
||||||
|
IndexGenerator gen(0);
|
||||||
|
|
||||||
|
EXPECT_EQ(base::nullopt, gen.GetNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IndexGeneratorTest, GetNext) {
|
||||||
|
IndexGenerator gen(11);
|
||||||
|
|
||||||
|
EXPECT_EQ(0U, gen.GetNext());
|
||||||
|
EXPECT_EQ(5U, gen.GetNext());
|
||||||
|
EXPECT_EQ(2U, gen.GetNext());
|
||||||
|
EXPECT_EQ(8U, gen.GetNext());
|
||||||
|
EXPECT_EQ(1U, gen.GetNext());
|
||||||
|
EXPECT_EQ(3U, gen.GetNext());
|
||||||
|
EXPECT_EQ(6U, gen.GetNext());
|
||||||
|
EXPECT_EQ(9U, gen.GetNext());
|
||||||
|
EXPECT_EQ(4U, gen.GetNext());
|
||||||
|
EXPECT_EQ(7U, gen.GetNext());
|
||||||
|
EXPECT_EQ(10U, gen.GetNext());
|
||||||
|
EXPECT_EQ(base::nullopt, gen.GetNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IndexGeneratorTest, GiveBack) {
|
||||||
|
IndexGenerator gen(4);
|
||||||
|
|
||||||
|
EXPECT_EQ(0U, gen.GetNext());
|
||||||
|
EXPECT_EQ(2U, gen.GetNext());
|
||||||
|
EXPECT_EQ(1U, gen.GetNext());
|
||||||
|
gen.GiveBack(2);
|
||||||
|
gen.GiveBack(0);
|
||||||
|
EXPECT_EQ(0U, gen.GetNext());
|
||||||
|
EXPECT_EQ(2U, gen.GetNext());
|
||||||
|
EXPECT_EQ(3U, gen.GetNext());
|
||||||
|
EXPECT_EQ(base::nullopt, gen.GetNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
Loading…
Reference in New Issue
Block a user