Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: chrome/browser/task_management/sampling/task_manager_impl.cc

Issue 2028753002: Make Task Manager sort more meaningful (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use a default argument instead of a second ctor. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/task_management/sampling/task_manager_impl.cc
diff --git a/chrome/browser/task_management/sampling/task_manager_impl.cc b/chrome/browser/task_management/sampling/task_manager_impl.cc
index 957bf92da4b79511d3b3e17e6b4971dff2b42738..22198b9b89ab7d6f52688112ec27c5b203b95db3 100644
--- a/chrome/browser/task_management/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_management/sampling/task_manager_impl.cc
@@ -4,7 +4,9 @@
#include "chrome/browser/task_management/sampling/task_manager_impl.h"
+#include <algorithm>
#include <string>
+#include <unordered_map>
#include <vector>
#include "base/command_line.h"
@@ -246,21 +248,90 @@ const TaskIdList& TaskManagerImpl::GetTaskIdsList() const {
"task manager for it to start running";
if (sorted_task_ids_.empty()) {
- sorted_task_ids_.reserve(task_groups_by_task_id_.size());
-
- // Ensure browser process group of task IDs are at the beginning of the
- // list.
- auto it = task_groups_by_proc_id_.find(base::GetCurrentProcId());
- DCHECK(it != task_groups_by_proc_id_.end());
- const TaskGroup* browser_group = it->second;
- browser_group->AppendSortedTaskIds(&sorted_task_ids_);
-
+ // |comparator| groups and sorts by subtask-ness (to push all subtasks to be
+ // last), then by process type (e.g. the browser process should be first;
+ // renderer processes should be together), then tab id (processes used by
+ // the same tab should be kept together, and a tab should have a stable
+ // position in the list as it cycles through processes, and tab creation
+ // order is meaningful), and finally by task id (when all else is equal, put
+ // the oldest tasks first).
+ auto comparator = [](const Task* a, const Task* b) -> bool {
+ 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.
+ 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.
+ std::make_tuple(!!b->GetParentTask(), b->GetType(), b->GetTabId(),
+ b->task_id());
+ };
+
+ const size_t num_groups = task_groups_by_proc_id_.size();
+ const size_t num_tasks = task_groups_by_task_id_.size();
+
+ // Populate |tasks_to_visit| with one task from each group.
+ std::vector<const Task*> tasks_to_visit;
+ tasks_to_visit.reserve(num_groups);
+ 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.
for (const auto& groups_pair : task_groups_by_proc_id_) {
- if (groups_pair.second == browser_group)
+ // The first task in the group (per |comparator|) is the one used for
+ // sorting the group relative to other groups.
+ const std::vector<Task*>& tasks = groups_pair.second->tasks();
+ Task* group_task =
+ *std::min_element(tasks.begin(), tasks.end(), comparator);
+ tasks_to_visit.push_back(group_task);
+
+ // Build the parent-to-child map, for use later.
+ for (const Task* task : tasks) {
+ if (task->GetParentTask())
+ children[task->GetParentTask()].push_back(task);
+ else
+ DCHECK(group_task->GetParentTask() == nullptr);
+ }
+ }
+
+ // Now sort |tasks_to_visit| in reverse order (putting the browser process
+ // at back()). We will treat it as a stack from now on.
+ std::sort(tasks_to_visit.rbegin(), tasks_to_visit.rend(), comparator);
+ DCHECK_EQ(Task::BROWSER, tasks_to_visit.back()->GetType());
+
+ // Using |tasks_to_visit| as a stack, and |visited_groups| to track which
+ // groups we've already added, add groups to |sorted_task_ids_| until all
+ // groups have been added.
+ sorted_task_ids_.reserve(num_tasks);
+ 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.
+ visited_groups.reserve(num_groups);
+ std::vector<Task*> current_group_tasks; // Outside loop for fewer mallocs.
+ while (visited_groups.size() < num_groups) {
+ 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.
+ TaskGroup* current_group =
+ GetTaskGroupByTaskId(tasks_to_visit.back()->task_id());
+ tasks_to_visit.pop_back();
+
+ // Mark |current_group| as visited. If this fails, we've already added
+ // the group, and should skip over it.
+ if (!visited_groups.insert(current_group).second)
continue;
- groups_pair.second->AppendSortedTaskIds(&sorted_task_ids_);
+ // Make a copy of |current_group->tasks()|, sort it, and append the ids.
+ current_group_tasks = current_group->tasks();
+ std::sort(current_group_tasks.begin(), current_group_tasks.end(),
+ comparator);
+ 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
+ sorted_task_ids_.push_back(task->task_id());
+ }
+
+ // Find the children of the tasks we just added, and push them into
+ // |tasks_to_visit|, so that we visit them soon. Push in reverse order,
+ // so that we visit them in forward order.
+ for (auto parent_task = current_group_tasks.rbegin();
+ parent_task != current_group_tasks.rend(); ++parent_task) {
+ auto children_it = children.find(*parent_task);
+ if (children_it != children.end()) {
+ 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.
+ std::sort(children.begin(), children.end(), comparator);
+ tasks_to_visit.insert(tasks_to_visit.end(), children.rbegin(),
+ children.rend());
+ }
+ }
}
+ DCHECK_EQ(num_tasks, sorted_task_ids_.size());
}
return sorted_task_ids_;
@@ -272,7 +343,13 @@ TaskIdList TaskManagerImpl::GetIdsOfTasksSharingSameProcess(
"task manager for it to start running";
TaskIdList result;
- GetTaskGroupByTaskId(task_id)->AppendSortedTaskIds(&result);
+ TaskGroup* group = GetTaskGroupByTaskId(task_id);
+ if (group) {
+ result.reserve(group->tasks().size());
+ 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.
+ result.push_back(task->task_id());
+ }
+ }
return result;
}

Powered by Google App Engine
This is Rietveld 408576698