OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_HEAP_PAGE_PARALLEL_JOB_ | 5 #ifndef V8_HEAP_PAGE_PARALLEL_JOB_ |
6 #define V8_HEAP_PAGE_PARALLEL_JOB_ | 6 #define V8_HEAP_PAGE_PARALLEL_JOB_ |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/cancelable-task.h" | 9 #include "src/cancelable-task.h" |
10 #include "src/utils.h" | 10 #include "src/utils.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 // PerPageData page_data) | 32 // PerPageData page_data) |
33 template <typename JobTraits> | 33 template <typename JobTraits> |
34 class PageParallelJob { | 34 class PageParallelJob { |
35 public: | 35 public: |
36 PageParallelJob(Heap* heap, CancelableTaskManager* cancelable_task_manager) | 36 PageParallelJob(Heap* heap, CancelableTaskManager* cancelable_task_manager) |
37 : heap_(heap), | 37 : heap_(heap), |
38 cancelable_task_manager_(cancelable_task_manager), | 38 cancelable_task_manager_(cancelable_task_manager), |
39 items_(nullptr), | 39 items_(nullptr), |
40 num_items_(0), | 40 num_items_(0), |
41 num_tasks_(0), | 41 num_tasks_(0), |
42 pending_tasks_(new base::Semaphore(0)) {} | 42 pending_tasks_(new base::Semaphore(0)), |
| 43 finished_tasks_(new base::AtomicNumber<int>(0)) {} |
43 | 44 |
44 ~PageParallelJob() { | 45 ~PageParallelJob() { |
45 Item* item = items_; | 46 Item* item = items_; |
46 while (item != nullptr) { | 47 while (item != nullptr) { |
47 Item* next = item->next; | 48 Item* next = item->next; |
48 delete item; | 49 delete item; |
49 item = next; | 50 item = next; |
50 } | 51 } |
51 delete pending_tasks_; | 52 delete pending_tasks_; |
| 53 delete finished_tasks_; |
52 } | 54 } |
53 | 55 |
54 void AddPage(MemoryChunk* chunk, typename JobTraits::PerPageData data) { | 56 void AddPage(MemoryChunk* chunk, typename JobTraits::PerPageData data) { |
55 Item* item = new Item(chunk, data, items_); | 57 Item* item = new Item(chunk, data, items_); |
56 items_ = item; | 58 items_ = item; |
57 ++num_items_; | 59 ++num_items_; |
58 } | 60 } |
59 | 61 |
60 int NumberOfPages() { return num_items_; } | 62 int NumberOfPages() { return num_items_; } |
61 | 63 |
(...skipping 14 matching lines...) Expand all Loading... |
76 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); | 78 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
77 num_tasks_ = Max(1, Min(num_tasks, max_num_tasks)); | 79 num_tasks_ = Max(1, Min(num_tasks, max_num_tasks)); |
78 int items_per_task = (num_items_ + num_tasks_ - 1) / num_tasks_; | 80 int items_per_task = (num_items_ + num_tasks_ - 1) / num_tasks_; |
79 int start_index = 0; | 81 int start_index = 0; |
80 Task* main_task = nullptr; | 82 Task* main_task = nullptr; |
81 for (int i = 0; i < num_tasks_; i++, start_index += items_per_task) { | 83 for (int i = 0; i < num_tasks_; i++, start_index += items_per_task) { |
82 if (start_index >= num_items_) { | 84 if (start_index >= num_items_) { |
83 start_index -= num_items_; | 85 start_index -= num_items_; |
84 } | 86 } |
85 Task* task = new Task(heap_, items_, num_items_, start_index, | 87 Task* task = new Task(heap_, items_, num_items_, start_index, |
86 pending_tasks_, per_task_data_callback(i)); | 88 pending_tasks_, per_task_data_callback(i), this); |
87 task_ids[i] = task->id(); | 89 task_ids[i] = task->id(); |
88 if (i > 0) { | 90 if (i > 0) { |
89 V8::GetCurrentPlatform()->CallOnBackgroundThread( | 91 V8::GetCurrentPlatform()->CallOnBackgroundThread( |
90 task, v8::Platform::kShortRunningTask); | 92 task, v8::Platform::kShortRunningTask); |
91 } else { | 93 } else { |
92 main_task = task; | 94 main_task = task; |
93 } | 95 } |
94 } | 96 } |
95 // Contribute on main thread. | 97 // Contribute on main thread. |
96 main_task->Run(); | 98 main_task->Run(); |
97 delete main_task; | 99 delete main_task; |
| 100 int aborted_tasks = 0; |
98 // Wait for background tasks. | 101 // Wait for background tasks. |
99 for (int i = 0; i < num_tasks_; i++) { | 102 for (int i = 0; i < num_tasks_; i++) { |
100 if (!cancelable_task_manager_->TryAbort(task_ids[i])) { | 103 if (!cancelable_task_manager_->TryAbort(task_ids[i])) { |
101 pending_tasks_->Wait(); | 104 pending_tasks_->Wait(); |
| 105 } else { |
| 106 ++aborted_tasks; |
102 } | 107 } |
103 } | 108 } |
| 109 int finished_tasks = finished_tasks_->Value(); |
| 110 // TODO(ulan): Remove this check after investigation of crbug.com/609249. |
| 111 CHECK_EQ(aborted_tasks + finished_tasks, num_tasks_); |
104 if (JobTraits::NeedSequentialFinalization) { | 112 if (JobTraits::NeedSequentialFinalization) { |
105 Item* item = items_; | 113 Item* item = items_; |
106 while (item != nullptr) { | 114 while (item != nullptr) { |
107 bool success = (item->state.Value() == kFinished); | 115 bool success = (item->state.Value() == kFinished); |
108 JobTraits::FinalizePageSequentially(heap_, item->chunk, success, | 116 JobTraits::FinalizePageSequentially(heap_, item->chunk, success, |
109 item->data); | 117 item->data); |
110 item = item->next; | 118 item = item->next; |
111 } | 119 } |
112 } | 120 } |
113 } | 121 } |
114 | 122 |
| 123 void NotifyFinishedTask() { finished_tasks_->Increment(1); } |
| 124 |
115 private: | 125 private: |
116 static const int kMaxNumberOfTasks = 10; | 126 static const int kMaxNumberOfTasks = 10; |
117 | 127 |
118 enum ProcessingState { kAvailable, kProcessing, kFinished, kFailed }; | 128 enum ProcessingState { kAvailable, kProcessing, kFinished, kFailed }; |
119 | 129 |
120 struct Item : public Malloced { | 130 struct Item : public Malloced { |
121 Item(MemoryChunk* chunk, typename JobTraits::PerPageData data, Item* next) | 131 Item(MemoryChunk* chunk, typename JobTraits::PerPageData data, Item* next) |
122 : chunk(chunk), state(kAvailable), data(data), next(next) {} | 132 : chunk(chunk), state(kAvailable), data(data), next(next) {} |
123 MemoryChunk* chunk; | 133 MemoryChunk* chunk; |
124 base::AtomicValue<ProcessingState> state; | 134 base::AtomicValue<ProcessingState> state; |
125 typename JobTraits::PerPageData data; | 135 typename JobTraits::PerPageData data; |
126 Item* next; | 136 Item* next; |
127 }; | 137 }; |
128 | 138 |
129 class Task : public CancelableTask { | 139 class Task : public CancelableTask { |
130 public: | 140 public: |
131 Task(Heap* heap, Item* items, int num_items, int start_index, | 141 Task(Heap* heap, Item* items, int num_items, int start_index, |
132 base::Semaphore* on_finish, typename JobTraits::PerTaskData data) | 142 base::Semaphore* on_finish, typename JobTraits::PerTaskData data, |
| 143 PageParallelJob<JobTraits>* job) |
133 : CancelableTask(heap->isolate()), | 144 : CancelableTask(heap->isolate()), |
134 heap_(heap), | 145 heap_(heap), |
135 items_(items), | 146 items_(items), |
136 num_items_(num_items), | 147 num_items_(num_items), |
137 start_index_(start_index), | 148 start_index_(start_index), |
138 on_finish_(on_finish), | 149 on_finish_(on_finish), |
139 data_(data) {} | 150 data_(data), |
| 151 job_(job) {} |
140 | 152 |
141 virtual ~Task() {} | 153 virtual ~Task() {} |
142 | 154 |
143 private: | 155 private: |
144 // v8::internal::CancelableTask overrides. | 156 // v8::internal::CancelableTask overrides. |
145 void RunInternal() override { | 157 void RunInternal() override { |
146 // Each task starts at a different index to improve parallelization. | 158 // Each task starts at a different index to improve parallelization. |
147 Item* current = items_; | 159 Item* current = items_; |
148 int skip = start_index_; | 160 int skip = start_index_; |
149 while (skip-- > 0) { | 161 while (skip-- > 0) { |
150 current = current->next; | 162 current = current->next; |
151 } | 163 } |
152 for (int i = 0; i < num_items_; i++) { | 164 for (int i = 0; i < num_items_; i++) { |
153 if (current->state.TrySetValue(kAvailable, kProcessing)) { | 165 if (current->state.TrySetValue(kAvailable, kProcessing)) { |
154 bool success = JobTraits::ProcessPageInParallel( | 166 bool success = JobTraits::ProcessPageInParallel( |
155 heap_, data_, current->chunk, current->data); | 167 heap_, data_, current->chunk, current->data); |
156 current->state.SetValue(success ? kFinished : kFailed); | 168 current->state.SetValue(success ? kFinished : kFailed); |
157 } | 169 } |
158 current = current->next; | 170 current = current->next; |
159 // Wrap around if needed. | 171 // Wrap around if needed. |
160 if (current == nullptr) { | 172 if (current == nullptr) { |
161 current = items_; | 173 current = items_; |
162 } | 174 } |
163 } | 175 } |
| 176 job_->NotifyFinishedTask(); |
164 on_finish_->Signal("PageParallelJob::Task::RunInternal"); | 177 on_finish_->Signal("PageParallelJob::Task::RunInternal"); |
165 } | 178 } |
166 | 179 |
167 Heap* heap_; | 180 Heap* heap_; |
168 Item* items_; | 181 Item* items_; |
169 int num_items_; | 182 int num_items_; |
170 int start_index_; | 183 int start_index_; |
171 base::Semaphore* on_finish_; | 184 base::Semaphore* on_finish_; |
172 typename JobTraits::PerTaskData data_; | 185 typename JobTraits::PerTaskData data_; |
| 186 PageParallelJob<JobTraits>* job_; |
173 DISALLOW_COPY_AND_ASSIGN(Task); | 187 DISALLOW_COPY_AND_ASSIGN(Task); |
174 }; | 188 }; |
175 | 189 |
176 Heap* heap_; | 190 Heap* heap_; |
177 CancelableTaskManager* cancelable_task_manager_; | 191 CancelableTaskManager* cancelable_task_manager_; |
178 Item* items_; | 192 Item* items_; |
179 int num_items_; | 193 int num_items_; |
180 int num_tasks_; | 194 int num_tasks_; |
181 base::Semaphore* pending_tasks_; | 195 base::Semaphore* pending_tasks_; |
| 196 base::AtomicNumber<int>* finished_tasks_; |
182 DISALLOW_COPY_AND_ASSIGN(PageParallelJob); | 197 DISALLOW_COPY_AND_ASSIGN(PageParallelJob); |
183 }; | 198 }; |
184 | 199 |
185 } // namespace internal | 200 } // namespace internal |
186 } // namespace v8 | 201 } // namespace v8 |
187 | 202 |
188 #endif // V8_HEAP_PAGE_PARALLEL_JOB_ | 203 #endif // V8_HEAP_PAGE_PARALLEL_JOB_ |
OLD | NEW |