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