Chromium Code Reviews| 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 15 matching lines...) Expand all Loading... | |
| 26 // PerPageData page_data) | 26 // PerPageData page_data) |
| 27 // The function should return true iff processing succeeded. | 27 // The function should return true iff processing succeeded. |
| 28 // - static const bool NeedSequentialFinalization | 28 // - static const bool NeedSequentialFinalization |
| 29 // - static void FinalizePageSequentially(Heap* heap, | 29 // - static void FinalizePageSequentially(Heap* heap, |
| 30 // bool processing_succeeded, | 30 // bool processing_succeeded, |
| 31 // MemoryChunk* page, | 31 // MemoryChunk* page, |
| 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 cannot dynamically create a semaphore because of a bug in |
| 37 // glibc. See http://crbug.com/609249 and | |
| 38 // https://sourceware.org/bugzilla/show_bug.cgi?id=12674. | |
| 39 // The caller must provide a semaphore with value 0 and ensure that | |
| 40 // the lifetime of the semaphore is the same as the lifetime of the Isolate. | |
| 41 // It is guaranteed that the semaphore value will be 0 after Run() call. | |
| 42 PageParallelJob(Heap* heap, CancelableTaskManager* cancelable_task_manager, | |
| 43 base::Semaphore* semaphore) | |
| 37 : heap_(heap), | 44 : heap_(heap), |
| 38 cancelable_task_manager_(cancelable_task_manager), | 45 cancelable_task_manager_(cancelable_task_manager), |
| 39 items_(nullptr), | 46 items_(nullptr), |
| 40 num_items_(0), | 47 num_items_(0), |
| 41 num_tasks_(0), | 48 num_tasks_(0), |
| 42 pending_tasks_(new base::Semaphore(0)), | 49 pending_tasks_(semaphore) {} |
| 43 finished_tasks_(new base::AtomicNumber<int>(0)) {} | |
| 44 | 50 |
| 45 ~PageParallelJob() { | 51 ~PageParallelJob() { |
| 46 Item* item = items_; | 52 Item* item = items_; |
| 47 while (item != nullptr) { | 53 while (item != nullptr) { |
| 48 Item* next = item->next; | 54 Item* next = item->next; |
| 49 delete item; | 55 delete item; |
| 50 item = next; | 56 item = next; |
| 51 } | 57 } |
| 52 delete pending_tasks_; | |
| 53 delete finished_tasks_; | |
| 54 } | 58 } |
| 55 | 59 |
| 56 void AddPage(MemoryChunk* chunk, typename JobTraits::PerPageData data) { | 60 void AddPage(MemoryChunk* chunk, typename JobTraits::PerPageData data) { |
| 57 Item* item = new Item(chunk, data, items_); | 61 Item* item = new Item(chunk, data, items_); |
| 58 items_ = item; | 62 items_ = item; |
| 59 ++num_items_; | 63 ++num_items_; |
| 60 } | 64 } |
| 61 | 65 |
| 62 int NumberOfPages() { return num_items_; } | 66 int NumberOfPages() { return num_items_; } |
| 63 | 67 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 78 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); | 82 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
| 79 num_tasks_ = Max(1, Min(num_tasks, max_num_tasks)); | 83 num_tasks_ = Max(1, Min(num_tasks, max_num_tasks)); |
| 80 int items_per_task = (num_items_ + num_tasks_ - 1) / num_tasks_; | 84 int items_per_task = (num_items_ + num_tasks_ - 1) / num_tasks_; |
| 81 int start_index = 0; | 85 int start_index = 0; |
| 82 Task* main_task = nullptr; | 86 Task* main_task = nullptr; |
| 83 for (int i = 0; i < num_tasks_; i++, start_index += items_per_task) { | 87 for (int i = 0; i < num_tasks_; i++, start_index += items_per_task) { |
| 84 if (start_index >= num_items_) { | 88 if (start_index >= num_items_) { |
| 85 start_index -= num_items_; | 89 start_index -= num_items_; |
| 86 } | 90 } |
| 87 Task* task = new Task(heap_, items_, num_items_, start_index, | 91 Task* task = new Task(heap_, items_, num_items_, start_index, |
| 88 pending_tasks_, per_task_data_callback(i), this); | 92 pending_tasks_, per_task_data_callback(i)); |
| 89 task_ids[i] = task->id(); | 93 task_ids[i] = task->id(); |
| 90 if (i > 0) { | 94 if (i > 0) { |
| 91 V8::GetCurrentPlatform()->CallOnBackgroundThread( | 95 V8::GetCurrentPlatform()->CallOnBackgroundThread( |
| 92 task, v8::Platform::kShortRunningTask); | 96 task, v8::Platform::kShortRunningTask); |
| 93 } else { | 97 } else { |
| 94 main_task = task; | 98 main_task = task; |
| 95 } | 99 } |
| 96 } | 100 } |
| 97 // Contribute on main thread. | 101 // Contribute on main thread. |
| 98 main_task->Run(); | 102 main_task->Run(); |
| 99 delete main_task; | 103 delete main_task; |
| 100 int aborted_tasks = 0; | |
|
ulan
2016/05/20 11:28:24
All removed lines below are instrumentation code.
| |
| 101 // Wait for background tasks. | 104 // Wait for background tasks. |
| 102 for (int i = 0; i < num_tasks_; i++) { | 105 for (int i = 0; i < num_tasks_; i++) { |
| 103 if (!cancelable_task_manager_->TryAbort(task_ids[i])) { | 106 if (!cancelable_task_manager_->TryAbort(task_ids[i])) { |
| 104 pending_tasks_->Wait(); | 107 pending_tasks_->Wait(); |
| 105 } else { | |
| 106 ++aborted_tasks; | |
| 107 } | 108 } |
| 108 } | 109 } |
| 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_); | |
| 112 if (JobTraits::NeedSequentialFinalization) { | 110 if (JobTraits::NeedSequentialFinalization) { |
| 113 Item* item = items_; | 111 Item* item = items_; |
| 114 while (item != nullptr) { | 112 while (item != nullptr) { |
| 115 bool success = (item->state.Value() == kFinished); | 113 bool success = (item->state.Value() == kFinished); |
| 116 JobTraits::FinalizePageSequentially(heap_, item->chunk, success, | 114 JobTraits::FinalizePageSequentially(heap_, item->chunk, success, |
| 117 item->data); | 115 item->data); |
| 118 item = item->next; | 116 item = item->next; |
| 119 } | 117 } |
| 120 } | 118 } |
| 121 } | 119 } |
| 122 | 120 |
| 123 void NotifyFinishedTask() { finished_tasks_->Increment(1); } | |
| 124 | |
| 125 private: | 121 private: |
| 126 static const int kMaxNumberOfTasks = 10; | 122 static const int kMaxNumberOfTasks = 10; |
| 127 | 123 |
| 128 enum ProcessingState { kAvailable, kProcessing, kFinished, kFailed }; | 124 enum ProcessingState { kAvailable, kProcessing, kFinished, kFailed }; |
| 129 | 125 |
| 130 struct Item : public Malloced { | 126 struct Item : public Malloced { |
| 131 Item(MemoryChunk* chunk, typename JobTraits::PerPageData data, Item* next) | 127 Item(MemoryChunk* chunk, typename JobTraits::PerPageData data, Item* next) |
| 132 : chunk(chunk), state(kAvailable), data(data), next(next) {} | 128 : chunk(chunk), state(kAvailable), data(data), next(next) {} |
| 133 MemoryChunk* chunk; | 129 MemoryChunk* chunk; |
| 134 base::AtomicValue<ProcessingState> state; | 130 base::AtomicValue<ProcessingState> state; |
| 135 typename JobTraits::PerPageData data; | 131 typename JobTraits::PerPageData data; |
| 136 Item* next; | 132 Item* next; |
| 137 }; | 133 }; |
| 138 | 134 |
| 139 class Task : public CancelableTask { | 135 class Task : public CancelableTask { |
| 140 public: | 136 public: |
| 141 Task(Heap* heap, Item* items, int num_items, int start_index, | 137 Task(Heap* heap, Item* items, int num_items, int start_index, |
| 142 base::Semaphore* on_finish, typename JobTraits::PerTaskData data, | 138 base::Semaphore* on_finish, typename JobTraits::PerTaskData data) |
| 143 PageParallelJob<JobTraits>* job) | |
| 144 : CancelableTask(heap->isolate()), | 139 : CancelableTask(heap->isolate()), |
| 145 heap_(heap), | 140 heap_(heap), |
| 146 items_(items), | 141 items_(items), |
| 147 num_items_(num_items), | 142 num_items_(num_items), |
| 148 start_index_(start_index), | 143 start_index_(start_index), |
| 149 on_finish_(on_finish), | 144 on_finish_(on_finish), |
| 150 data_(data), | 145 data_(data) {} |
| 151 job_(job) {} | |
| 152 | 146 |
| 153 virtual ~Task() {} | 147 virtual ~Task() {} |
| 154 | 148 |
| 155 private: | 149 private: |
| 156 // v8::internal::CancelableTask overrides. | 150 // v8::internal::CancelableTask overrides. |
| 157 void RunInternal() override { | 151 void RunInternal() override { |
| 158 // Each task starts at a different index to improve parallelization. | 152 // Each task starts at a different index to improve parallelization. |
| 159 Item* current = items_; | 153 Item* current = items_; |
| 160 int skip = start_index_; | 154 int skip = start_index_; |
| 161 while (skip-- > 0) { | 155 while (skip-- > 0) { |
| 162 current = current->next; | 156 current = current->next; |
| 163 } | 157 } |
| 164 for (int i = 0; i < num_items_; i++) { | 158 for (int i = 0; i < num_items_; i++) { |
| 165 if (current->state.TrySetValue(kAvailable, kProcessing)) { | 159 if (current->state.TrySetValue(kAvailable, kProcessing)) { |
| 166 bool success = JobTraits::ProcessPageInParallel( | 160 bool success = JobTraits::ProcessPageInParallel( |
| 167 heap_, data_, current->chunk, current->data); | 161 heap_, data_, current->chunk, current->data); |
| 168 current->state.SetValue(success ? kFinished : kFailed); | 162 current->state.SetValue(success ? kFinished : kFailed); |
| 169 } | 163 } |
| 170 current = current->next; | 164 current = current->next; |
| 171 // Wrap around if needed. | 165 // Wrap around if needed. |
| 172 if (current == nullptr) { | 166 if (current == nullptr) { |
| 173 current = items_; | 167 current = items_; |
| 174 } | 168 } |
| 175 } | 169 } |
| 176 job_->NotifyFinishedTask(); | 170 on_finish_->Signal(); |
| 177 on_finish_->Signal("PageParallelJob::Task::RunInternal"); | |
| 178 } | 171 } |
| 179 | 172 |
| 180 Heap* heap_; | 173 Heap* heap_; |
| 181 Item* items_; | 174 Item* items_; |
| 182 int num_items_; | 175 int num_items_; |
| 183 int start_index_; | 176 int start_index_; |
| 184 base::Semaphore* on_finish_; | 177 base::Semaphore* on_finish_; |
| 185 typename JobTraits::PerTaskData data_; | 178 typename JobTraits::PerTaskData data_; |
| 186 PageParallelJob<JobTraits>* job_; | |
| 187 DISALLOW_COPY_AND_ASSIGN(Task); | 179 DISALLOW_COPY_AND_ASSIGN(Task); |
| 188 }; | 180 }; |
| 189 | 181 |
| 190 Heap* heap_; | 182 Heap* heap_; |
| 191 CancelableTaskManager* cancelable_task_manager_; | 183 CancelableTaskManager* cancelable_task_manager_; |
| 192 Item* items_; | 184 Item* items_; |
| 193 int num_items_; | 185 int num_items_; |
| 194 int num_tasks_; | 186 int num_tasks_; |
| 195 base::Semaphore* pending_tasks_; | 187 base::Semaphore* pending_tasks_; |
| 196 base::AtomicNumber<int>* finished_tasks_; | |
| 197 DISALLOW_COPY_AND_ASSIGN(PageParallelJob); | 188 DISALLOW_COPY_AND_ASSIGN(PageParallelJob); |
| 198 }; | 189 }; |
| 199 | 190 |
| 200 } // namespace internal | 191 } // namespace internal |
| 201 } // namespace v8 | 192 } // namespace v8 |
| 202 | 193 |
| 203 #endif // V8_HEAP_PAGE_PARALLEL_JOB_ | 194 #endif // V8_HEAP_PAGE_PARALLEL_JOB_ |
| OLD | NEW |