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_group.h"
8 #include "base/callback.h"
9 #include "base/stl_util.h"
10 #include "chrome/browser/task_management/task_manager_observer.h"
11 #include "components/nacl/browser/nacl_browser.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace task_management
{
18 inline bool IsResourceRefreshEnabled(RefreshType refresh_type
,
20 return (refresh_flags
& refresh_type
) != 0;
24 // Gets the GDI and USER Handles on Windows at one shot.
25 void GetWindowsHandles(base::ProcessHandle handle
,
26 int64
* out_gdi_current
,
28 int64
* out_user_current
,
29 int64
* out_user_peak
) {
32 *out_user_current
= 0;
34 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
35 HANDLE current_process
= GetCurrentProcess();
36 HANDLE process_with_query_rights
;
37 if (DuplicateHandle(current_process
, handle
, current_process
,
38 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
40 *out_gdi_current
= static_cast<int64
>(
41 GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS
));
42 *out_gdi_peak
= static_cast<int64
>(
43 GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS_PEAK
));
44 *out_user_current
= static_cast<int64
>(
45 GetGuiResources(process_with_query_rights
, GR_USEROBJECTS
));
46 *out_user_peak
= static_cast<int64
>(
47 GetGuiResources(process_with_query_rights
, GR_USEROBJECTS_PEAK
));
48 CloseHandle(process_with_query_rights
);
51 #endif // defined(OS_WIN)
56 base::ProcessHandle proc_handle
,
57 base::ProcessId proc_id
,
58 const scoped_refptr
<base::SequencedTaskRunner
>& blocking_pool_runner
)
59 : process_handle_(proc_handle
),
61 worker_thread_sampler_(nullptr),
67 gdi_current_handles_(-1),
68 gdi_peak_handles_(-1),
69 user_current_handles_(-1),
70 user_peak_handles_(-1),
71 #endif // defined(OS_WIN)
72 #if !defined(DISABLE_NACL)
73 nacl_debug_stub_port_(-1),
74 #endif // !defined(DISABLE_NACL)
75 idle_wakeups_per_second_(-1),
76 gpu_memory_has_duplicates_(false),
77 weak_ptr_factory_(this) {
78 scoped_refptr
<TaskGroupSampler
> sampler(
79 new TaskGroupSampler(proc_handle
,
81 base::Bind(&TaskGroup::OnCpuRefreshDone
,
82 weak_ptr_factory_
.GetWeakPtr()),
83 base::Bind(&TaskGroup::OnMemoryUsageRefreshDone
,
84 weak_ptr_factory_
.GetWeakPtr()),
85 base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone
,
86 weak_ptr_factory_
.GetWeakPtr())));
87 worker_thread_sampler_
.swap(sampler
);
90 TaskGroup::~TaskGroup() {
93 void TaskGroup::AddTask(Task
* task
) {
95 DCHECK(task
->process_id() == process_id_
);
96 DCHECK(!ContainsKey(tasks_
, task
->task_id()));
98 tasks_
[task
->task_id()] = task
;
101 void TaskGroup::RemoveTask(Task
* task
) {
103 DCHECK(ContainsKey(tasks_
, task
->task_id()));
105 tasks_
.erase(task
->task_id());
108 void TaskGroup::Refresh(
109 const content::GPUVideoMemoryUsageStats
& gpu_memory_stats
,
110 base::TimeDelta update_interval
,
111 int64 refresh_flags
) {
112 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
114 // First refresh the enabled non-expensive resources usages on the UI thread.
115 // 1- Refresh all the tasks.
116 for (auto& task_pair
: tasks_
)
117 task_pair
.second
->Refresh(update_interval
, refresh_flags
);
119 // 2- Refresh GPU memory (if enabled).
120 if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY
, refresh_flags
))
121 RefreshGpuMemory(gpu_memory_stats
);
123 // 3- Refresh Windows handles (if enabled).
125 if (IsResourceRefreshEnabled(REFRESH_TYPE_HANDLES
, refresh_flags
))
126 RefreshWindowsHandles();
127 #endif // defined(OS_WIN)
129 // 4- Refresh the NACL debug stub port (if enabled).
130 #if !defined(DISABLE_NACL)
131 if (IsResourceRefreshEnabled(REFRESH_TYPE_NACL
, refresh_flags
) &&
133 RefreshNaClDebugStubPort(tasks_
.begin()->second
->GetChildProcessUniqueID());
135 #endif // !defined(DISABLE_NACL)
137 // The remaining resource refreshes are time consuming and cannot be done on
138 // the UI thread. Do them all on the worker thread using the TaskGroupSampler.
141 // 7- Idle Wakeups per second.
142 worker_thread_sampler_
->Refresh(refresh_flags
);
145 void TaskGroup::AppendSortedTaskIds(TaskIdList
* out_list
) const {
146 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
149 for (const auto& task_pair
: tasks_
)
150 out_list
->push_back(task_pair
.first
);
153 Task
* TaskGroup::GetTaskById(TaskId task_id
) const {
154 DCHECK(ContainsKey(tasks_
, task_id
));
156 return tasks_
.at(task_id
);
159 void TaskGroup::RefreshGpuMemory(
160 const content::GPUVideoMemoryUsageStats
& gpu_memory_stats
) {
161 auto itr
= gpu_memory_stats
.process_map
.find(process_id_
);
162 if (itr
== gpu_memory_stats
.process_map
.end()) {
164 gpu_memory_has_duplicates_
= false;
168 gpu_memory_
= static_cast<int64
>(itr
->second
.video_memory
);
169 gpu_memory_has_duplicates_
= itr
->second
.has_duplicates
;
172 void TaskGroup::RefreshWindowsHandles() {
174 GetWindowsHandles(process_handle_
,
175 &gdi_current_handles_
,
177 &user_current_handles_
,
178 &user_peak_handles_
);
179 #endif // defined(OS_WIN)
182 void TaskGroup::RefreshNaClDebugStubPort(int child_process_unique_id
) {
183 #if !defined(DISABLE_NACL)
184 nacl::NaClBrowser
* nacl_browser
= nacl::NaClBrowser::GetInstance();
185 nacl_debug_stub_port_
=
186 nacl_browser
->GetProcessGdbDebugStubPort(child_process_unique_id
);
187 #endif // !defined(DISABLE_NACL)
190 void TaskGroup::OnCpuRefreshDone(double cpu_usage
) {
191 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
193 cpu_usage_
= cpu_usage
;
196 void TaskGroup::OnMemoryUsageRefreshDone(MemoryUsageStats memory_usage
) {
197 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
199 memory_usage_
= memory_usage
;
202 void TaskGroup::OnIdleWakeupsRefreshDone(int idle_wakeups_per_second
) {
203 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
205 idle_wakeups_per_second_
= idle_wakeups_per_second
;
208 } // namespace task_management