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