[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:
Etienne Pierre-doray 2020-09-11 14:39:53 -04:00 committed by Commit Bot
parent 30c57eb930
commit 0d813976ea
5 changed files with 144 additions and 0 deletions

View File

@ -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",

View 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

View 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_

View File

@ -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",

View 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