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.
4
5 #include "chrome/browser/task_manager/sampling/task_group_sampler.h"
6
7 #include <limits>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/process/process_metrics.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/task_manager/task_manager_observer.h"
15 #include "content/public/browser/browser_child_process_host.h"
16 #include "content/public/browser/browser_thread.h"
17
18 #if defined(OS_WIN)
19 #include <windows.h>
20
21 #include <psapi.h>
22 #endif
23
24 namespace task_manager {
25
26 namespace {
27
CreateProcessMetrics(base::ProcessHandle handle)28 std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
29 base::ProcessHandle handle) {
30 #if !defined(OS_MAC)
31 return base::ProcessMetrics::CreateProcessMetrics(handle);
32 #else
33 return base::ProcessMetrics::CreateProcessMetrics(
34 handle, content::BrowserChildProcessHost::GetPortProvider());
35 #endif
36 }
37
38 } // namespace
39
TaskGroupSampler(base::Process process,const scoped_refptr<base::SequencedTaskRunner> & blocking_pool_runner,const OnCpuRefreshCallback & on_cpu_refresh,const OnSwappedMemRefreshCallback & on_swapped_mem_refresh,const OnIdleWakeupsCallback & on_idle_wakeups,const OnOpenFdCountCallback & on_open_fd_count,const OnProcessPriorityCallback & on_process_priority)40 TaskGroupSampler::TaskGroupSampler(
41 base::Process process,
42 const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner,
43 const OnCpuRefreshCallback& on_cpu_refresh,
44 const OnSwappedMemRefreshCallback& on_swapped_mem_refresh,
45 const OnIdleWakeupsCallback& on_idle_wakeups,
46 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
47 const OnOpenFdCountCallback& on_open_fd_count,
48 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
49 const OnProcessPriorityCallback& on_process_priority)
50 : process_(std::move(process)),
51 process_metrics_(CreateProcessMetrics(process_.Handle())),
52 blocking_pool_runner_(blocking_pool_runner),
53 on_cpu_refresh_callback_(on_cpu_refresh),
54 on_swapped_mem_refresh_callback_(on_swapped_mem_refresh),
55 on_idle_wakeups_callback_(on_idle_wakeups),
56 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
57 on_open_fd_count_callback_(on_open_fd_count),
58 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
59 on_process_priority_callback_(on_process_priority) {
60 DCHECK(blocking_pool_runner.get());
61
62 // This object will be created on the UI thread, however the sequenced checker
63 // will be used to assert we're running the expensive operations on one of the
64 // blocking pool threads.
65 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
66 worker_pool_sequenced_checker_.DetachFromSequence();
67 }
68
Refresh(int64_t refresh_flags)69 void TaskGroupSampler::Refresh(int64_t refresh_flags) {
70 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
71
72 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_CPU,
73 refresh_flags)) {
74 base::PostTaskAndReplyWithResult(
75 blocking_pool_runner_.get(), FROM_HERE,
76 base::BindOnce(&TaskGroupSampler::RefreshCpuUsage, this),
77 base::BindOnce(on_cpu_refresh_callback_));
78 }
79
80 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_SWAPPED_MEM,
81 refresh_flags)) {
82 base::PostTaskAndReplyWithResult(
83 blocking_pool_runner_.get(), FROM_HERE,
84 base::BindOnce(&TaskGroupSampler::RefreshSwappedMem, this),
85 base::BindOnce(on_swapped_mem_refresh_callback_));
86 }
87
88 #if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
89 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS,
90 refresh_flags)) {
91 base::PostTaskAndReplyWithResult(
92 blocking_pool_runner_.get(), FROM_HERE,
93 base::BindOnce(&TaskGroupSampler::RefreshIdleWakeupsPerSecond, this),
94 base::BindOnce(on_idle_wakeups_callback_));
95 }
96 #endif // defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
97
98 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
99 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_FD_COUNT,
100 refresh_flags)) {
101 base::PostTaskAndReplyWithResult(
102 blocking_pool_runner_.get(), FROM_HERE,
103 base::BindOnce(&TaskGroupSampler::RefreshOpenFdCount, this),
104 base::BindOnce(on_open_fd_count_callback_));
105 }
106 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
107
108 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_PRIORITY,
109 refresh_flags)) {
110 base::PostTaskAndReplyWithResult(
111 blocking_pool_runner_.get(), FROM_HERE,
112 base::BindOnce(&TaskGroupSampler::RefreshProcessPriority, this),
113 base::BindOnce(on_process_priority_callback_));
114 }
115 }
116
~TaskGroupSampler()117 TaskGroupSampler::~TaskGroupSampler() {
118 }
119
RefreshCpuUsage()120 double TaskGroupSampler::RefreshCpuUsage() {
121 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
122 double cpu_usage = process_metrics_->GetPlatformIndependentCPUUsage();
123 if (!cpu_usage_calculated_) {
124 // First call to GetPlatformIndependentCPUUsage returns 0. Ignore it,
125 // and return NaN.
126 cpu_usage_calculated_ = true;
127 return std::numeric_limits<double>::quiet_NaN();
128 }
129 return cpu_usage;
130 }
131
RefreshSwappedMem()132 int64_t TaskGroupSampler::RefreshSwappedMem() {
133 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
134
135 #if defined(OS_CHROMEOS)
136 return process_metrics_->GetVmSwapBytes();
137 #endif // defined(OS_CHROMEOS)
138
139 return 0;
140 }
141
RefreshIdleWakeupsPerSecond()142 int TaskGroupSampler::RefreshIdleWakeupsPerSecond() {
143 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
144
145 return process_metrics_->GetIdleWakeupsPerSecond();
146 }
147
148 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
RefreshOpenFdCount()149 int TaskGroupSampler::RefreshOpenFdCount() {
150 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
151
152 return process_metrics_->GetOpenFdCount();
153 }
154 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
155
RefreshProcessPriority()156 bool TaskGroupSampler::RefreshProcessPriority() {
157 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
158 #if defined(OS_MAC)
159 return process_.IsProcessBackgrounded(
160 content::BrowserChildProcessHost::GetPortProvider());
161 #else
162 return process_.IsProcessBackgrounded();
163 #endif // defined(OS_MAC)
164 }
165
166 } // namespace task_manager
167