Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium 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 #include "chrome/browser/task_management/sampling/task_manager_impl.h" | 5 #include "chrome/browser/task_management/sampling/task_manager_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include <string> | 8 #include <string> |
| 9 #include <unordered_map> | |
| 8 #include <vector> | 10 #include <vector> |
| 9 | 11 |
| 10 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 11 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 12 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 13 #include "chrome/browser/task_management/providers/browser_process_task_provider .h" | 15 #include "chrome/browser/task_management/providers/browser_process_task_provider .h" |
| 14 #include "chrome/browser/task_management/providers/child_process_task_provider.h " | 16 #include "chrome/browser/task_management/providers/child_process_task_provider.h " |
| 15 #include "chrome/browser/task_management/providers/web_contents/web_contents_tas k_provider.h" | 17 #include "chrome/browser/task_management/providers/web_contents/web_contents_tas k_provider.h" |
| 16 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 17 #include "content/public/browser/gpu_data_manager.h" | 19 #include "content/public/browser/gpu_data_manager.h" |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 *stats = task->GetWebCacheStats(); | 241 *stats = task->GetWebCacheStats(); |
| 240 | 242 |
| 241 return true; | 243 return true; |
| 242 } | 244 } |
| 243 | 245 |
| 244 const TaskIdList& TaskManagerImpl::GetTaskIdsList() const { | 246 const TaskIdList& TaskManagerImpl::GetTaskIdsList() const { |
| 245 DCHECK(is_running_) << "Task manager is not running. You must observe the " | 247 DCHECK(is_running_) << "Task manager is not running. You must observe the " |
| 246 "task manager for it to start running"; | 248 "task manager for it to start running"; |
| 247 | 249 |
| 248 if (sorted_task_ids_.empty()) { | 250 if (sorted_task_ids_.empty()) { |
| 249 sorted_task_ids_.reserve(task_groups_by_task_id_.size()); | 251 // |comparator| groups and sorts by subtask-ness (to push all subtasks to be |
| 252 // last), then by process type (e.g. the browser process should be first; | |
| 253 // renderer processes should be together), then tab id (processes used by | |
| 254 // the same tab should be kept together, and a tab should have a stable | |
| 255 // position in the list as it cycles through processes, and tab creation | |
| 256 // order is meaningful), and finally by task id (when all else is equal, put | |
| 257 // the oldest tasks first). | |
| 258 auto comparator = [](const Task* a, const Task* b) -> bool { | |
| 259 return std::make_tuple(!!a->GetParentTask(), a->GetType(), a->GetTabId(), | |
|
afakhry
2016/06/06 18:11:59
First, using a tuple is brilliant.
Second, how ab
ncarter (slow)
2016/06/20 17:40:00
Done.
| |
| 260 a->task_id()) < | |
|
ncarter (slow)
2016/06/08 21:37:50
FYI using tuples for lexicographic comparison is a
afakhry
2016/06/09 13:33:53
Thanks for sharing! I liked the std::tie example.
| |
| 261 std::make_tuple(!!b->GetParentTask(), b->GetType(), b->GetTabId(), | |
| 262 b->task_id()); | |
| 263 }; | |
| 250 | 264 |
| 251 // Ensure browser process group of task IDs are at the beginning of the | 265 const size_t num_groups = task_groups_by_proc_id_.size(); |
| 252 // list. | 266 const size_t num_tasks = task_groups_by_task_id_.size(); |
| 253 auto it = task_groups_by_proc_id_.find(base::GetCurrentProcId()); | |
| 254 DCHECK(it != task_groups_by_proc_id_.end()); | |
| 255 const TaskGroup* browser_group = it->second; | |
| 256 browser_group->AppendSortedTaskIds(&sorted_task_ids_); | |
| 257 | 267 |
| 268 // Populate |tasks_to_visit| with one task from each group. | |
| 269 std::vector<const Task*> tasks_to_visit; | |
| 270 tasks_to_visit.reserve(num_groups); | |
| 271 std::unordered_map<const Task*, std::vector<const Task*>> children; | |
|
afakhry
2016/06/06 18:11:59
Optional: Tracking the children here using a prior
ncarter (slow)
2016/06/08 21:37:50
Interesting idea. They're essentially the same und
afakhry
2016/06/09 13:33:53
Yes, they're definitely the same algorithm. The su
ncarter (slow)
2016/06/20 17:39:59
Thanks for this suggestion. My overall sense is th
afakhry
2016/06/22 13:49:46
Acknowledged.
| |
| 258 for (const auto& groups_pair : task_groups_by_proc_id_) { | 272 for (const auto& groups_pair : task_groups_by_proc_id_) { |
| 259 if (groups_pair.second == browser_group) | 273 // The first task in the group (per |comparator|) is the one used for |
| 274 // sorting the group relative to other groups. | |
| 275 const std::vector<Task*>& tasks = groups_pair.second->tasks(); | |
| 276 Task* group_task = | |
| 277 *std::min_element(tasks.begin(), tasks.end(), comparator); | |
| 278 tasks_to_visit.push_back(group_task); | |
| 279 | |
| 280 // Build the parent-to-child map, for use later. | |
| 281 for (const Task* task : tasks) { | |
| 282 if (task->GetParentTask()) | |
| 283 children[task->GetParentTask()].push_back(task); | |
| 284 else | |
| 285 DCHECK(group_task->GetParentTask() == nullptr); | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 // Now sort |tasks_to_visit| in reverse order (putting the browser process | |
| 290 // at back()). We will treat it as a stack from now on. | |
| 291 std::sort(tasks_to_visit.rbegin(), tasks_to_visit.rend(), comparator); | |
| 292 DCHECK_EQ(Task::BROWSER, tasks_to_visit.back()->GetType()); | |
| 293 | |
| 294 // Using |tasks_to_visit| as a stack, and |visited_groups| to track which | |
| 295 // groups we've already added, add groups to |sorted_task_ids_| until all | |
| 296 // groups have been added. | |
| 297 sorted_task_ids_.reserve(num_tasks); | |
| 298 std::unordered_set<TaskGroup*> visited_groups; | |
|
afakhry
2016/06/03 17:53:42
Do you need to #include <unordered_set>?
ncarter (slow)
2016/06/20 17:39:59
Done.
| |
| 299 visited_groups.reserve(num_groups); | |
| 300 std::vector<Task*> current_group_tasks; // Outside loop for fewer mallocs. | |
| 301 while (visited_groups.size() < num_groups) { | |
| 302 CHECK(!tasks_to_visit.empty()); | |
|
afakhry
2016/06/06 18:11:59
I think a DCHECK() is enough here.
ncarter (slow)
2016/06/20 17:40:00
Done.
| |
| 303 TaskGroup* current_group = | |
| 304 GetTaskGroupByTaskId(tasks_to_visit.back()->task_id()); | |
| 305 tasks_to_visit.pop_back(); | |
| 306 | |
| 307 // Mark |current_group| as visited. If this fails, we've already added | |
| 308 // the group, and should skip over it. | |
| 309 if (!visited_groups.insert(current_group).second) | |
| 260 continue; | 310 continue; |
| 261 | 311 |
| 262 groups_pair.second->AppendSortedTaskIds(&sorted_task_ids_); | 312 // Make a copy of |current_group->tasks()|, sort it, and append the ids. |
| 313 current_group_tasks = current_group->tasks(); | |
| 314 std::sort(current_group_tasks.begin(), current_group_tasks.end(), | |
| 315 comparator); | |
| 316 for (Task* task : current_group_tasks) { | |
|
afakhry
2016/06/03 17:53:42
const auto& ?
afakhry
2016/06/03 17:53:42
Nit: Remove curly braces.
ncarter (slow)
2016/06/20 17:39:59
Done.
ncarter (slow)
2016/06/20 17:40:00
I prefer Task* here, since it makes it clearer to
afakhry
2016/06/22 13:49:46
It may or may not. const auto& is generally prefer
| |
| 317 sorted_task_ids_.push_back(task->task_id()); | |
| 318 } | |
| 319 | |
| 320 // Find the children of the tasks we just added, and push them into | |
| 321 // |tasks_to_visit|, so that we visit them soon. Push in reverse order, | |
| 322 // so that we visit them in forward order. | |
| 323 for (auto parent_task = current_group_tasks.rbegin(); | |
| 324 parent_task != current_group_tasks.rend(); ++parent_task) { | |
| 325 auto children_it = children.find(*parent_task); | |
| 326 if (children_it != children.end()) { | |
| 327 std::vector<const Task*>& children = children_it->second; | |
|
afakhry
2016/06/03 17:53:42
This children vector hides the outer children unor
ncarter (slow)
2016/06/08 21:37:50
YUCK. Thanks for pointing this out, it was an acci
afakhry
2016/06/09 13:33:53
I think you got lucky as you were only accessing |
ncarter (slow)
2016/06/20 17:40:00
Done.
| |
| 328 std::sort(children.begin(), children.end(), comparator); | |
| 329 tasks_to_visit.insert(tasks_to_visit.end(), children.rbegin(), | |
| 330 children.rend()); | |
| 331 } | |
| 332 } | |
| 263 } | 333 } |
| 334 DCHECK_EQ(num_tasks, sorted_task_ids_.size()); | |
| 264 } | 335 } |
| 265 | 336 |
| 266 return sorted_task_ids_; | 337 return sorted_task_ids_; |
| 267 } | 338 } |
| 268 | 339 |
| 269 TaskIdList TaskManagerImpl::GetIdsOfTasksSharingSameProcess( | 340 TaskIdList TaskManagerImpl::GetIdsOfTasksSharingSameProcess( |
| 270 TaskId task_id) const { | 341 TaskId task_id) const { |
| 271 DCHECK(is_running_) << "Task manager is not running. You must observe the " | 342 DCHECK(is_running_) << "Task manager is not running. You must observe the " |
| 272 "task manager for it to start running"; | 343 "task manager for it to start running"; |
| 273 | 344 |
| 274 TaskIdList result; | 345 TaskIdList result; |
| 275 GetTaskGroupByTaskId(task_id)->AppendSortedTaskIds(&result); | 346 TaskGroup* group = GetTaskGroupByTaskId(task_id); |
| 347 if (group) { | |
| 348 result.reserve(group->tasks().size()); | |
| 349 for (Task* task : group->tasks()) { | |
|
afakhry
2016/06/03 17:53:42
Nit: the curly braces.
afakhry
2016/06/03 17:53:42
Also const auto& ?
ncarter (slow)
2016/06/20 17:39:59
I prefer 'Task*' to 'const auto&' here; it's is fe
ncarter (slow)
2016/06/20 17:40:00
Done.
afakhry
2016/06/22 13:49:46
Acknowledged.
| |
| 350 result.push_back(task->task_id()); | |
| 351 } | |
| 352 } | |
| 276 return result; | 353 return result; |
| 277 } | 354 } |
| 278 | 355 |
| 279 size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id) const { | 356 size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id) const { |
| 280 return GetTaskGroupByTaskId(task_id)->num_tasks(); | 357 return GetTaskGroupByTaskId(task_id)->num_tasks(); |
| 281 } | 358 } |
| 282 | 359 |
| 283 void TaskManagerImpl::TaskAdded(Task* task) { | 360 void TaskManagerImpl::TaskAdded(Task* task) { |
| 284 DCHECK(task); | 361 DCHECK(task); |
| 285 | 362 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 groups_itr.second->AreBackgroundCalculationsDone(); | 522 groups_itr.second->AreBackgroundCalculationsDone(); |
| 446 } | 523 } |
| 447 if (are_all_processes_data_ready) { | 524 if (are_all_processes_data_ready) { |
| 448 NotifyObserversOnRefreshWithBackgroundCalculations(GetTaskIdsList()); | 525 NotifyObserversOnRefreshWithBackgroundCalculations(GetTaskIdsList()); |
| 449 for (const auto& groups_itr : task_groups_by_proc_id_) | 526 for (const auto& groups_itr : task_groups_by_proc_id_) |
| 450 groups_itr.second->ClearCurrentBackgroundCalculationsFlags(); | 527 groups_itr.second->ClearCurrentBackgroundCalculationsFlags(); |
| 451 } | 528 } |
| 452 } | 529 } |
| 453 | 530 |
| 454 } // namespace task_management | 531 } // namespace task_management |
| OLD | NEW |