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 |