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
);
113 // First refresh the enabled non-expensive resources usages on the UI thread.
114 // 1- Refresh all the tasks.
115 for (auto& task_pair
: tasks_
)
116 task_pair
.second
->Refresh(update_interval
, refresh_flags
);
118 // 2- Refresh GPU memory (if enabled).
119 if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY
, refresh_flags
))
120 RefreshGpuMemory(gpu_memory_stats
);
122 // 3- Refresh Windows handles (if enabled).
124 if (IsResourceRefreshEnabled(REFRESH_TYPE_HANDLES
, refresh_flags
))
125 RefreshWindowsHandles();
126 #endif // defined(OS_WIN)
128 // 4- Refresh the NACL debug stub port (if enabled).
129 #if !defined(DISABLE_NACL)
130 if (IsResourceRefreshEnabled(REFRESH_TYPE_NACL
, refresh_flags
) &&
132 RefreshNaClDebugStubPort(tasks_
.begin()->second
->GetChildProcessUniqueID());
134 #endif // !defined(DISABLE_NACL)
136 // The remaining resource refreshes are time consuming and cannot be done on
137 // the UI thread. Do them all on the worker thread using the TaskGroupSampler.
140 // 7- Idle Wakeups per second.
141 worker_thread_sampler_
->Refresh(refresh_flags
);
144 Task
* TaskGroup::GetTaskById(TaskId task_id
) const {
145 DCHECK(ContainsKey(tasks_
, task_id
));
147 return tasks_
.at(task_id
);
150 void TaskGroup::RefreshGpuMemory(
151 const content::GPUVideoMemoryUsageStats
& gpu_memory_stats
) {
152 auto itr
= gpu_memory_stats
.process_map
.find(process_id_
);
153 if (itr
== gpu_memory_stats
.process_map
.end()) {
155 gpu_memory_has_duplicates_
= false;
159 gpu_memory_
= static_cast<int64
>(itr
->second
.video_memory
);
160 gpu_memory_has_duplicates_
= itr
->second
.has_duplicates
;
163 void TaskGroup::RefreshWindowsHandles() {
165 GetWindowsHandles(process_handle_
,
166 &gdi_current_handles_
,
168 &user_current_handles_
,
169 &user_peak_handles_
);
170 #endif // defined(OS_WIN)
173 void TaskGroup::RefreshNaClDebugStubPort(int child_process_unique_id
) {
174 #if !defined(DISABLE_NACL)
175 nacl::NaClBrowser
* nacl_browser
= nacl::NaClBrowser::GetInstance();
176 nacl_debug_stub_port_
=
177 nacl_browser
->GetProcessGdbDebugStubPort(child_process_unique_id
);
178 #endif // !defined(DISABLE_NACL)
181 void TaskGroup::OnCpuRefreshDone(double cpu_usage
) {
182 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
184 cpu_usage_
= cpu_usage
;
187 void TaskGroup::OnMemoryUsageRefreshDone(MemoryUsageStats memory_usage
) {
188 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
190 memory_usage_
= memory_usage
;
193 void TaskGroup::OnIdleWakeupsRefreshDone(int idle_wakeups_per_second
) {
194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
196 idle_wakeups_per_second_
= idle_wakeups_per_second
;
199 } // namespace task_management