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());
189 for (const auto& groups_pair
: task_groups_by_proc_id_
)
190 groups_pair
.second
->AppendSortedTaskIds(&sorted_task_ids_
);
193 return sorted_task_ids_
;
196 size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id
) const {
197 return GetTaskGroupByTaskId(task_id
)->num_tasks();
200 void TaskManagerImpl::TaskAdded(Task
* task
) {
203 TaskGroup
* task_group
= nullptr;
204 const base::ProcessId proc_id
= task
->process_id();
205 const TaskId task_id
= task
->task_id();
207 auto itr
= task_groups_by_proc_id_
.find(proc_id
);
208 if (itr
== task_groups_by_proc_id_
.end()) {
209 task_group
= new TaskGroup(task
->process_handle(),
211 blocking_pool_runner_
);
212 task_groups_by_proc_id_
[proc_id
] = task_group
;
214 task_group
= itr
->second
;
217 task_group
->AddTask(task
);
219 task_groups_by_task_id_
[task_id
] = task_group
;
221 // Invalidate the cached sorted IDs by clearing the list.
222 sorted_task_ids_
.clear();
224 NotifyObserversOnTaskAdded(task_id
);
227 void TaskManagerImpl::TaskRemoved(Task
* task
) {
230 const base::ProcessId proc_id
= task
->process_id();
231 const TaskId task_id
= task
->task_id();
233 DCHECK(ContainsKey(task_groups_by_proc_id_
, proc_id
));
234 DCHECK(ContainsKey(task_groups_by_task_id_
, task_id
));
236 NotifyObserversOnTaskToBeRemoved(task_id
);
238 TaskGroup
* task_group
= task_groups_by_proc_id_
.at(proc_id
);
239 task_group
->RemoveTask(task
);
241 task_groups_by_task_id_
.erase(task_id
);
243 // Invalidate the cached sorted IDs by clearing the list.
244 sorted_task_ids_
.clear();
246 if (task_group
->empty()) {
247 task_groups_by_proc_id_
.erase(proc_id
);
252 void TaskManagerImpl::OnVideoMemoryUsageStatsUpdate(
253 const content::GPUVideoMemoryUsageStats
& gpu_memory_stats
) {
254 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
256 gpu_memory_stats_
= gpu_memory_stats
;
260 void TaskManagerImpl::OnMultipleBytesReadUI(
261 std::vector
<BytesReadParam
>* params
) {
262 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
265 for (BytesReadParam
& param
: *params
) {
266 if (!GetInstance()->UpdateTasksWithBytesRead(param
)) {
267 // We can't match a task to the notification. That might mean the
268 // tab that started a download was closed, or the request may have had
269 // no originating task associated with it in the first place.
270 // We attribute orphaned/unaccounted activity to the Browser process.
271 DCHECK(param
.origin_pid
|| (param
.child_id
!= -1));
273 param
.origin_pid
= 0;
274 param
.child_id
= param
.route_id
= -1;
276 GetInstance()->UpdateTasksWithBytesRead(param
);
281 void TaskManagerImpl::Refresh() {
282 if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY
)) {
283 content::GpuDataManager::GetInstance()->
284 RequestVideoMemoryUsageStatsUpdate();
287 for (auto& groups_itr
: task_groups_by_proc_id_
) {
288 groups_itr
.second
->Refresh(gpu_memory_stats_
,
289 GetCurrentRefreshTime(),
290 enabled_resources_flags());
293 TaskIdList
task_ids(GetTaskIdsList());
294 NotifyObserversOnRefresh(task_ids
);
297 void TaskManagerImpl::StartUpdating() {
300 for (auto& provider
: task_providers_
)
301 provider
->SetObserver(this);
303 io_thread_helper_manager_
.reset(new IoThreadHelperManager
);
306 void TaskManagerImpl::StopUpdating() {
309 io_thread_helper_manager_
.reset();
311 for (auto& provider
: task_providers_
)
312 provider
->ClearObserver();
314 STLDeleteValues(&task_groups_by_proc_id_
);
315 task_groups_by_task_id_
.clear();
316 sorted_task_ids_
.clear();
319 bool TaskManagerImpl::UpdateTasksWithBytesRead(const BytesReadParam
& param
) {
320 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
322 for (auto& task_provider
: task_providers_
) {
323 Task
* task
= task_provider
->GetTaskOfUrlRequest(param
.origin_pid
,
327 task
->OnNetworkBytesRead(param
.byte_count
);
332 // Couldn't match the bytes to any existing task.
336 TaskGroup
* TaskManagerImpl::GetTaskGroupByTaskId(TaskId task_id
) const {
337 DCHECK(ContainsKey(task_groups_by_task_id_
, task_id
));
339 return task_groups_by_task_id_
.at(task_id
);
342 Task
* TaskManagerImpl::GetTaskByTaskId(TaskId task_id
) const {
343 return GetTaskGroupByTaskId(task_id
)->GetTaskById(task_id
);
346 } // namespace task_management