Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/item-parallel-job.h"
6 :
7 : #include "src/base/platform/semaphore.h"
8 : #include "src/counters.h"
9 : #include "src/v8.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 521398 : ItemParallelJob::Task::Task(Isolate* isolate) : CancelableTask(isolate) {}
15 :
16 0 : void ItemParallelJob::Task::SetupInternal(base::Semaphore* on_finish,
17 : std::vector<Item*>* items,
18 : size_t start_index) {
19 521398 : on_finish_ = on_finish;
20 521398 : items_ = items;
21 :
22 521398 : if (start_index < items->size()) {
23 515152 : cur_index_ = start_index;
24 : } else {
25 6246 : items_considered_ = items_->size();
26 : }
27 0 : }
28 :
29 439195 : void ItemParallelJob::Task::RunInternal() {
30 439195 : RunInParallel();
31 439526 : on_finish_->Signal();
32 439403 : }
33 :
34 234412 : ItemParallelJob::ItemParallelJob(CancelableTaskManager* cancelable_task_manager,
35 : base::Semaphore* pending_tasks)
36 : : cancelable_task_manager_(cancelable_task_manager),
37 234412 : pending_tasks_(pending_tasks) {}
38 :
39 703236 : ItemParallelJob::~ItemParallelJob() {
40 1847576 : for (size_t i = 0; i < items_.size(); i++) {
41 806582 : Item* item = items_[i];
42 806582 : CHECK(item->IsFinished());
43 806582 : delete item;
44 : }
45 234412 : }
46 :
47 223538 : void ItemParallelJob::Run() {
48 : DCHECK_GT(tasks_.size(), 0);
49 : const size_t num_items = items_.size();
50 : const size_t num_tasks = tasks_.size();
51 :
52 447076 : TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
53 : "ItemParallelJob::Run", TRACE_EVENT_SCOPE_THREAD,
54 : "num_tasks", static_cast<int>(num_tasks), "num_items",
55 : static_cast<int>(num_items));
56 :
57 : // Some jobs have more tasks than items (when the items are mere coarse
58 : // grain tasks that generate work dynamically for a second phase which all
59 : // tasks participate in). Some jobs even have 0 items to preprocess but
60 : // still have multiple tasks.
61 : // TODO(gab): Figure out a cleaner scheme for this.
62 : const size_t num_tasks_processing_items = Min(num_items, tasks_.size());
63 :
64 : // In the event of an uneven workload, distribute an extra item to the first
65 : // |items_remainder| tasks.
66 : const size_t items_remainder = num_tasks_processing_items > 0
67 : ? num_items % num_tasks_processing_items
68 223538 : : 0;
69 : // Base |items_per_task|, will be bumped by 1 for the first
70 : // |items_remainder| tasks.
71 : const size_t items_per_task = num_tasks_processing_items > 0
72 : ? num_items / num_tasks_processing_items
73 223538 : : 0;
74 : CancelableTaskManager::Id* task_ids =
75 223538 : new CancelableTaskManager::Id[num_tasks];
76 : std::unique_ptr<Task> main_task;
77 1787732 : for (size_t i = 0, start_index = 0; i < num_tasks;
78 521398 : i++, start_index += items_per_task + (i < items_remainder ? 1 : 0)) {
79 : auto task = std::move(tasks_[i]);
80 : DCHECK(task);
81 :
82 : // By definition there are less |items_remainder| to distribute then
83 : // there are tasks processing items so this cannot overflow while we are
84 : // assigning work items.
85 : DCHECK_IMPLIES(start_index >= num_items, i >= num_tasks_processing_items);
86 :
87 521398 : task->SetupInternal(pending_tasks_, &items_, start_index);
88 521398 : task_ids[i] = task->id();
89 521398 : if (i > 0) {
90 893580 : V8::GetCurrentPlatform()->CallBlockingTaskOnWorkerThread(std::move(task));
91 : } else {
92 : main_task = std::move(task);
93 : }
94 : }
95 :
96 : // Contribute on main thread.
97 : DCHECK(main_task);
98 223538 : main_task->Run();
99 :
100 : // Wait for background tasks.
101 1266334 : for (size_t i = 0; i < num_tasks; i++) {
102 521398 : if (cancelable_task_manager_->TryAbort(task_ids[i]) !=
103 : TryAbortResult::kTaskAborted) {
104 439637 : pending_tasks_->Wait();
105 : }
106 : }
107 223538 : delete[] task_ids;
108 223538 : }
109 :
110 : } // namespace internal
111 121996 : } // namespace v8
|