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
3 // found in the LICENSE file.
5 #include "chrome/browser/task_management/sampling/task_manager_impl.h"
7 #include "base/stl_util.h"
8 #include "chrome/browser/task_management/providers/browser_process_task_provider.h"
9 #include "chrome/browser/task_management/providers/child_process_task_provider.h"
10 #include "chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/gpu_data_manager.h"
14 namespace task_management
{
18 inline scoped_refptr
<base::SequencedTaskRunner
> GetBlockingPoolRunner() {
19 base::SequencedWorkerPool
* blocking_pool
=
20 content::BrowserThread::GetBlockingPool();
21 base::SequencedWorkerPool::SequenceToken token
=
22 blocking_pool
->GetSequenceToken();
24 DCHECK(token
.IsValid());
26 return blocking_pool
->GetSequencedTaskRunner(token
);
29 base::LazyInstance
<TaskManagerImpl
> lazy_task_manager_instance
=
30 LAZY_INSTANCE_INITIALIZER
;
34 TaskManagerImpl::TaskManagerImpl()
35 : blocking_pool_runner_(GetBlockingPoolRunner()),
37 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
39 task_providers_
.push_back(new BrowserProcessTaskProvider());
40 task_providers_
.push_back(new ChildProcessTaskProvider());
41 task_providers_
.push_back(new WebContentsTaskProvider());
43 content::GpuDataManager::GetInstance()->AddObserver(this);
46 TaskManagerImpl::~TaskManagerImpl() {
47 content::GpuDataManager::GetInstance()->RemoveObserver(this);
49 STLDeleteValues(&task_groups_by_proc_id_
);
53 TaskManagerImpl
* TaskManagerImpl::GetInstance() {
54 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
56 return lazy_task_manager_instance
.Pointer();
59 void TaskManagerImpl::ActivateTask(TaskId task_id
) {
60 GetTaskByTaskId(task_id
)->Activate();
63 double TaskManagerImpl::GetCpuUsage(TaskId task_id
) const {
64 return GetTaskGroupByTaskId(task_id
)->cpu_usage();
67 int64
TaskManagerImpl::GetPhysicalMemoryUsage(TaskId task_id
) const {
68 return GetTaskGroupByTaskId(task_id
)->physical_bytes();
71 int64
TaskManagerImpl::GetPrivateMemoryUsage(TaskId task_id
) const {
72 return GetTaskGroupByTaskId(task_id
)->private_bytes();
75 int64
TaskManagerImpl::GetSharedMemoryUsage(TaskId task_id
) const {
76 return GetTaskGroupByTaskId(task_id
)->shared_bytes();
79 int64
TaskManagerImpl::GetGpuMemoryUsage(TaskId task_id
,
80 bool* has_duplicates
) const {
81 const TaskGroup
* task_group
= GetTaskGroupByTaskId(task_id
);
83 *has_duplicates
= task_group
->gpu_memory_has_duplicates();
84 return task_group
->gpu_memory();
87 int TaskManagerImpl::GetIdleWakeupsPerSecond(TaskId task_id
) const {
88 return GetTaskGroupByTaskId(task_id
)->idle_wakeups_per_second();
91 int TaskManagerImpl::GetNaClDebugStubPort(TaskId task_id
) const {
92 #if !defined(DISABLE_NACL)
93 return GetTaskGroupByTaskId(task_id
)->nacl_debug_stub_port();
96 #endif // !defined(DISABLE_NACL)
99 void TaskManagerImpl::GetGDIHandles(TaskId task_id
,
103 const TaskGroup
* task_group
= GetTaskGroupByTaskId(task_id
);
104 *current
= task_group
->gdi_current_handles();
105 *peak
= task_group
->gdi_peak_handles();
109 #endif // defined(OS_WIN)
112 void TaskManagerImpl::GetUSERHandles(TaskId task_id
,
116 const TaskGroup
* task_group
= GetTaskGroupByTaskId(task_id
);
117 *current
= task_group
->user_current_handles();
118 *peak
= task_group
->user_peak_handles();
122 #endif // defined(OS_WIN)
125 const base::string16
& TaskManagerImpl::GetTitle(TaskId task_id
) const {
126 return GetTaskByTaskId(task_id
)->title();
129 base::string16
TaskManagerImpl::GetProfileName(TaskId task_id
) const {
130 return GetTaskByTaskId(task_id
)->GetProfileName();
133 const gfx::ImageSkia
& TaskManagerImpl::GetIcon(TaskId task_id
) const {
134 return GetTaskByTaskId(task_id
)->icon();
137 const base::ProcessHandle
& TaskManagerImpl::GetProcessHandle(
138 TaskId task_id
) const {
139 return GetTaskGroupByTaskId(task_id
)->process_handle();
142 const base::ProcessId
& TaskManagerImpl::GetProcessId(TaskId task_id
) const {
143 return GetTaskGroupByTaskId(task_id
)->process_id();
146 Task::Type
TaskManagerImpl::GetType(TaskId task_id
) const {
147 return GetTaskByTaskId(task_id
)->GetType();
150 int64
TaskManagerImpl::GetNetworkUsage(TaskId task_id
) const {
151 return GetTaskByTaskId(task_id
)->network_usage();
154 int64
TaskManagerImpl::GetSqliteMemoryUsed(TaskId task_id
) const {
155 return GetTaskByTaskId(task_id
)->GetSqliteMemoryUsed();
158 bool TaskManagerImpl::GetV8Memory(TaskId task_id
,
161 const Task
* task
= GetTaskByTaskId(task_id
);
162 if (!task
->ReportsV8Memory())
165 *allocated
= task
->GetV8MemoryAllocated();
166 *used
= task
->GetV8MemoryUsed();
171 bool TaskManagerImpl::GetWebCacheStats(
173 blink::WebCache::ResourceTypeStats
* stats
) const {
174 const Task
* task
= GetTaskByTaskId(task_id
);
175 if (!task
->ReportsWebCacheStats())
178 *stats
= task
->GetWebCacheStats();
183 const TaskIdList
& TaskManagerImpl::GetTaskIdsList() const {
184 DCHECK(is_running_
) << "Task manager is not running. You must observe the "
185 "task manager for it to start running";
187 if (sorted_task_ids_
.empty()) {
188 sorted_task_ids_
.reserve(task_groups_by_task_id_
.size());
190 // Ensure browser process group of task IDs are at the beginning of the
192 const TaskGroup
* browser_group
=
193 task_groups_by_proc_id_
.at(base::GetCurrentProcId());
194 browser_group
->AppendSortedTaskIds(&sorted_task_ids_
);
196 for (const auto& groups_pair
: task_groups_by_proc_id_
) {
197 if (groups_pair
.second
== browser_group
)
200 groups_pair
.second
->AppendSortedTaskIds(&sorted_task_ids_
);
204 return sorted_task_ids_
;
207 size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id
) const {
208 return GetTaskGroupByTaskId(task_id
)->num_tasks();
211 void TaskManagerImpl::TaskAdded(Task
* task
) {
214 TaskGroup
* task_group
= nullptr;
215 const base::ProcessId proc_id
= task
->process_id();
216 const TaskId task_id
= task
->task_id();
218 auto itr
= task_groups_by_proc_id_
.find(proc_id
);
219 if (itr
== task_groups_by_proc_id_
.end()) {
220 task_group
= new TaskGroup(task
->process_handle(),
222 blocking_pool_runner_
);
223 task_groups_by_proc_id_
[proc_id
] = task_group
;
225 task_group
= itr
->second
;
228 task_group
->AddTask(task
);
230 task_groups_by_task_id_
[task_id
] = task_group
;
232 // Invalidate the cached sorted IDs by clearing the list.
233 sorted_task_ids_
.clear();
235 NotifyObserversOnTaskAdded(task_id
);
238 void TaskManagerImpl::TaskRemoved(Task
* task
) {
241 const base::ProcessId proc_id
= task
->process_id();
242 const TaskId task_id
= task
->task_id();
244 DCHECK(ContainsKey(task_groups_by_proc_id_
, proc_id
));
245 DCHECK(ContainsKey(task_groups_by_task_id_
, task_id
));
247 NotifyObserversOnTaskToBeRemoved(task_id
);
249 TaskGroup
* task_group
= task_groups_by_proc_id_
.at(proc_id
);
250 task_group
->RemoveTask(task
);
252 task_groups_by_task_id_
.erase(task_id
);
254 // Invalidate the cached sorted IDs by clearing the list.
255 sorted_task_ids_
.clear();
257 if (task_group
->empty()) {
258 task_groups_by_proc_id_
.erase(proc_id
);
263 void TaskManagerImpl::OnVideoMemoryUsageStatsUpdate(
264 const content::GPUVideoMemoryUsageStats
& gpu_memory_stats
) {
265 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
267 gpu_memory_stats_
= gpu_memory_stats
;
271 void TaskManagerImpl::OnMultipleBytesReadUI(
272 std::vector
<BytesReadParam
>* params
) {
273 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
276 for (BytesReadParam
& param
: *params
) {
277 if (!GetInstance()->UpdateTasksWithBytesRead(param
)) {
278 // We can't match a task to the notification. That might mean the
279 // tab that started a download was closed, or the request may have had
280 // no originating task associated with it in the first place.
281 // We attribute orphaned/unaccounted activity to the Browser process.
282 DCHECK(param
.origin_pid
|| (param
.child_id
!= -1));
284 param
.origin_pid
= 0;
285 param
.child_id
= param
.route_id
= -1;
287 GetInstance()->UpdateTasksWithBytesRead(param
);
292 void TaskManagerImpl::Refresh() {
293 if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY
)) {
294 content::GpuDataManager::GetInstance()->
295 RequestVideoMemoryUsageStatsUpdate();
298 for (auto& groups_itr
: task_groups_by_proc_id_
) {
299 groups_itr
.second
->Refresh(gpu_memory_stats_
,
300 GetCurrentRefreshTime(),
301 enabled_resources_flags());
304 NotifyObserversOnRefresh(GetTaskIdsList());
307 void TaskManagerImpl::StartUpdating() {
310 for (auto& provider
: task_providers_
)
311 provider
->SetObserver(this);
313 io_thread_helper_manager_
.reset(new IoThreadHelperManager
);
316 void TaskManagerImpl::StopUpdating() {
319 io_thread_helper_manager_
.reset();
321 for (auto& provider
: task_providers_
)
322 provider
->ClearObserver();
324 STLDeleteValues(&task_groups_by_proc_id_
);
325 task_groups_by_task_id_
.clear();
326 sorted_task_ids_
.clear();
329 bool TaskManagerImpl::UpdateTasksWithBytesRead(const BytesReadParam
& param
) {
330 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
332 for (auto& task_provider
: task_providers_
) {
333 Task
* task
= task_provider
->GetTaskOfUrlRequest(param
.origin_pid
,
337 task
->OnNetworkBytesRead(param
.byte_count
);
342 // Couldn't match the bytes to any existing task.
346 TaskGroup
* TaskManagerImpl::GetTaskGroupByTaskId(TaskId task_id
) const {
347 DCHECK(ContainsKey(task_groups_by_task_id_
, task_id
));
349 return task_groups_by_task_id_
.at(task_id
);
352 Task
* TaskManagerImpl::GetTaskByTaskId(TaskId task_id
) const {
353 return GetTaskGroupByTaskId(task_id
)->GetTaskById(task_id
);
356 } // namespace task_management