xref: /aosp_15_r20/external/libchrome/base/process/process_metrics_linux.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/process/process_metrics.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <dirent.h>
8*635a8641SAndroid Build Coastguard Worker #include <fcntl.h>
9*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
10*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
11*635a8641SAndroid Build Coastguard Worker #include <sys/stat.h>
12*635a8641SAndroid Build Coastguard Worker #include <sys/time.h>
13*635a8641SAndroid Build Coastguard Worker #include <sys/types.h>
14*635a8641SAndroid Build Coastguard Worker #include <unistd.h>
15*635a8641SAndroid Build Coastguard Worker #include <utility>
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker #include "base/files/dir_reader_posix.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/optional.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/process/internal_linux.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/process/process_metrics_iocounters.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
25*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
26*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_tokenizer.h"
27*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
28*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
29*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
30*635a8641SAndroid Build Coastguard Worker 
31*635a8641SAndroid Build Coastguard Worker namespace base {
32*635a8641SAndroid Build Coastguard Worker 
33*635a8641SAndroid Build Coastguard Worker namespace {
34*635a8641SAndroid Build Coastguard Worker 
TrimKeyValuePairs(StringPairs * pairs)35*635a8641SAndroid Build Coastguard Worker void TrimKeyValuePairs(StringPairs* pairs) {
36*635a8641SAndroid Build Coastguard Worker   for (auto& pair : *pairs) {
37*635a8641SAndroid Build Coastguard Worker     TrimWhitespaceASCII(pair.first, TRIM_ALL, &pair.first);
38*635a8641SAndroid Build Coastguard Worker     TrimWhitespaceASCII(pair.second, TRIM_ALL, &pair.second);
39*635a8641SAndroid Build Coastguard Worker   }
40*635a8641SAndroid Build Coastguard Worker }
41*635a8641SAndroid Build Coastguard Worker 
42*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
43*635a8641SAndroid Build Coastguard Worker // Read a file with a single number string and return the number as a uint64_t.
ReadFileToUint64(const FilePath & file)44*635a8641SAndroid Build Coastguard Worker uint64_t ReadFileToUint64(const FilePath& file) {
45*635a8641SAndroid Build Coastguard Worker   std::string file_contents;
46*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(file, &file_contents))
47*635a8641SAndroid Build Coastguard Worker     return 0;
48*635a8641SAndroid Build Coastguard Worker   TrimWhitespaceASCII(file_contents, TRIM_ALL, &file_contents);
49*635a8641SAndroid Build Coastguard Worker   uint64_t file_contents_uint64 = 0;
50*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(file_contents, &file_contents_uint64))
51*635a8641SAndroid Build Coastguard Worker     return 0;
52*635a8641SAndroid Build Coastguard Worker   return file_contents_uint64;
53*635a8641SAndroid Build Coastguard Worker }
54*635a8641SAndroid Build Coastguard Worker #endif
55*635a8641SAndroid Build Coastguard Worker 
56*635a8641SAndroid Build Coastguard Worker // Read |filename| in /proc/<pid>/, split the entries into key/value pairs, and
57*635a8641SAndroid Build Coastguard Worker // trim the key and value. On success, return true and write the trimmed
58*635a8641SAndroid Build Coastguard Worker // key/value pairs into |key_value_pairs|.
ReadProcFileToTrimmedStringPairs(pid_t pid,StringPiece filename,StringPairs * key_value_pairs)59*635a8641SAndroid Build Coastguard Worker bool ReadProcFileToTrimmedStringPairs(pid_t pid,
60*635a8641SAndroid Build Coastguard Worker                                       StringPiece filename,
61*635a8641SAndroid Build Coastguard Worker                                       StringPairs* key_value_pairs) {
62*635a8641SAndroid Build Coastguard Worker   std::string status_data;
63*635a8641SAndroid Build Coastguard Worker   {
64*635a8641SAndroid Build Coastguard Worker     // Synchronously reading files in /proc does not hit the disk.
65*635a8641SAndroid Build Coastguard Worker     ThreadRestrictions::ScopedAllowIO allow_io;
66*635a8641SAndroid Build Coastguard Worker     FilePath status_file = internal::GetProcPidDir(pid).Append(filename);
67*635a8641SAndroid Build Coastguard Worker     if (!ReadFileToString(status_file, &status_data))
68*635a8641SAndroid Build Coastguard Worker       return false;
69*635a8641SAndroid Build Coastguard Worker   }
70*635a8641SAndroid Build Coastguard Worker   SplitStringIntoKeyValuePairs(status_data, ':', '\n', key_value_pairs);
71*635a8641SAndroid Build Coastguard Worker   TrimKeyValuePairs(key_value_pairs);
72*635a8641SAndroid Build Coastguard Worker   return true;
73*635a8641SAndroid Build Coastguard Worker }
74*635a8641SAndroid Build Coastguard Worker 
75*635a8641SAndroid Build Coastguard Worker // Read /proc/<pid>/status and return the value for |field|, or 0 on failure.
76*635a8641SAndroid Build Coastguard Worker // Only works for fields in the form of "Field: value kB".
ReadProcStatusAndGetFieldAsSizeT(pid_t pid,StringPiece field)77*635a8641SAndroid Build Coastguard Worker size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, StringPiece field) {
78*635a8641SAndroid Build Coastguard Worker   StringPairs pairs;
79*635a8641SAndroid Build Coastguard Worker   if (!ReadProcFileToTrimmedStringPairs(pid, "status", &pairs))
80*635a8641SAndroid Build Coastguard Worker     return 0;
81*635a8641SAndroid Build Coastguard Worker 
82*635a8641SAndroid Build Coastguard Worker   for (const auto& pair : pairs) {
83*635a8641SAndroid Build Coastguard Worker     const std::string& key = pair.first;
84*635a8641SAndroid Build Coastguard Worker     const std::string& value_str = pair.second;
85*635a8641SAndroid Build Coastguard Worker     if (key != field)
86*635a8641SAndroid Build Coastguard Worker       continue;
87*635a8641SAndroid Build Coastguard Worker 
88*635a8641SAndroid Build Coastguard Worker     std::vector<StringPiece> split_value_str =
89*635a8641SAndroid Build Coastguard Worker         SplitStringPiece(value_str, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
90*635a8641SAndroid Build Coastguard Worker     if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
91*635a8641SAndroid Build Coastguard Worker       NOTREACHED();
92*635a8641SAndroid Build Coastguard Worker       return 0;
93*635a8641SAndroid Build Coastguard Worker     }
94*635a8641SAndroid Build Coastguard Worker     size_t value;
95*635a8641SAndroid Build Coastguard Worker     if (!StringToSizeT(split_value_str[0], &value)) {
96*635a8641SAndroid Build Coastguard Worker       NOTREACHED();
97*635a8641SAndroid Build Coastguard Worker       return 0;
98*635a8641SAndroid Build Coastguard Worker     }
99*635a8641SAndroid Build Coastguard Worker     return value;
100*635a8641SAndroid Build Coastguard Worker   }
101*635a8641SAndroid Build Coastguard Worker   // This can be reached if the process dies when proc is read -- in that case,
102*635a8641SAndroid Build Coastguard Worker   // the kernel can return missing fields.
103*635a8641SAndroid Build Coastguard Worker   return 0;
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker 
106*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX) || defined(OS_AIX)
107*635a8641SAndroid Build Coastguard Worker // Read /proc/<pid>/status and look for |field|. On success, return true and
108*635a8641SAndroid Build Coastguard Worker // write the value for |field| into |result|.
109*635a8641SAndroid Build Coastguard Worker // Only works for fields in the form of "field    :     uint_value"
ReadProcStatusAndGetFieldAsUint64(pid_t pid,StringPiece field,uint64_t * result)110*635a8641SAndroid Build Coastguard Worker bool ReadProcStatusAndGetFieldAsUint64(pid_t pid,
111*635a8641SAndroid Build Coastguard Worker                                        StringPiece field,
112*635a8641SAndroid Build Coastguard Worker                                        uint64_t* result) {
113*635a8641SAndroid Build Coastguard Worker   StringPairs pairs;
114*635a8641SAndroid Build Coastguard Worker   if (!ReadProcFileToTrimmedStringPairs(pid, "status", &pairs))
115*635a8641SAndroid Build Coastguard Worker     return false;
116*635a8641SAndroid Build Coastguard Worker 
117*635a8641SAndroid Build Coastguard Worker   for (const auto& pair : pairs) {
118*635a8641SAndroid Build Coastguard Worker     const std::string& key = pair.first;
119*635a8641SAndroid Build Coastguard Worker     const std::string& value_str = pair.second;
120*635a8641SAndroid Build Coastguard Worker     if (key != field)
121*635a8641SAndroid Build Coastguard Worker       continue;
122*635a8641SAndroid Build Coastguard Worker 
123*635a8641SAndroid Build Coastguard Worker     uint64_t value;
124*635a8641SAndroid Build Coastguard Worker     if (!StringToUint64(value_str, &value))
125*635a8641SAndroid Build Coastguard Worker       return false;
126*635a8641SAndroid Build Coastguard Worker     *result = value;
127*635a8641SAndroid Build Coastguard Worker     return true;
128*635a8641SAndroid Build Coastguard Worker   }
129*635a8641SAndroid Build Coastguard Worker   return false;
130*635a8641SAndroid Build Coastguard Worker }
131*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_LINUX) || defined(OS_AIX)
132*635a8641SAndroid Build Coastguard Worker 
133*635a8641SAndroid Build Coastguard Worker // Get the total CPU of a single process.  Return value is number of jiffies
134*635a8641SAndroid Build Coastguard Worker // on success or -1 on error.
GetProcessCPU(pid_t pid)135*635a8641SAndroid Build Coastguard Worker int64_t GetProcessCPU(pid_t pid) {
136*635a8641SAndroid Build Coastguard Worker   std::string buffer;
137*635a8641SAndroid Build Coastguard Worker   std::vector<std::string> proc_stats;
138*635a8641SAndroid Build Coastguard Worker   if (!internal::ReadProcStats(pid, &buffer) ||
139*635a8641SAndroid Build Coastguard Worker       !internal::ParseProcStats(buffer, &proc_stats)) {
140*635a8641SAndroid Build Coastguard Worker     return -1;
141*635a8641SAndroid Build Coastguard Worker   }
142*635a8641SAndroid Build Coastguard Worker 
143*635a8641SAndroid Build Coastguard Worker   int64_t total_cpu =
144*635a8641SAndroid Build Coastguard Worker       internal::GetProcStatsFieldAsInt64(proc_stats, internal::VM_UTIME) +
145*635a8641SAndroid Build Coastguard Worker       internal::GetProcStatsFieldAsInt64(proc_stats, internal::VM_STIME);
146*635a8641SAndroid Build Coastguard Worker 
147*635a8641SAndroid Build Coastguard Worker   return total_cpu;
148*635a8641SAndroid Build Coastguard Worker }
149*635a8641SAndroid Build Coastguard Worker 
150*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
151*635a8641SAndroid Build Coastguard Worker // Report on Chrome OS GEM object graphics memory. /run/debugfs_gpu is a
152*635a8641SAndroid Build Coastguard Worker // bind mount into /sys/kernel/debug and synchronously reading the in-memory
153*635a8641SAndroid Build Coastguard Worker // files in /sys is fast.
ReadChromeOSGraphicsMemory(SystemMemoryInfoKB * meminfo)154*635a8641SAndroid Build Coastguard Worker void ReadChromeOSGraphicsMemory(SystemMemoryInfoKB* meminfo) {
155*635a8641SAndroid Build Coastguard Worker #if defined(ARCH_CPU_ARM_FAMILY)
156*635a8641SAndroid Build Coastguard Worker   FilePath geminfo_file("/run/debugfs_gpu/exynos_gem_objects");
157*635a8641SAndroid Build Coastguard Worker #else
158*635a8641SAndroid Build Coastguard Worker   FilePath geminfo_file("/run/debugfs_gpu/i915_gem_objects");
159*635a8641SAndroid Build Coastguard Worker #endif
160*635a8641SAndroid Build Coastguard Worker   std::string geminfo_data;
161*635a8641SAndroid Build Coastguard Worker   meminfo->gem_objects = -1;
162*635a8641SAndroid Build Coastguard Worker   meminfo->gem_size = -1;
163*635a8641SAndroid Build Coastguard Worker   if (ReadFileToString(geminfo_file, &geminfo_data)) {
164*635a8641SAndroid Build Coastguard Worker     int gem_objects = -1;
165*635a8641SAndroid Build Coastguard Worker     long long gem_size = -1;
166*635a8641SAndroid Build Coastguard Worker     int num_res = sscanf(geminfo_data.c_str(), "%d objects, %lld bytes",
167*635a8641SAndroid Build Coastguard Worker                          &gem_objects, &gem_size);
168*635a8641SAndroid Build Coastguard Worker     if (num_res == 2) {
169*635a8641SAndroid Build Coastguard Worker       meminfo->gem_objects = gem_objects;
170*635a8641SAndroid Build Coastguard Worker       meminfo->gem_size = gem_size;
171*635a8641SAndroid Build Coastguard Worker     }
172*635a8641SAndroid Build Coastguard Worker   }
173*635a8641SAndroid Build Coastguard Worker 
174*635a8641SAndroid Build Coastguard Worker #if defined(ARCH_CPU_ARM_FAMILY)
175*635a8641SAndroid Build Coastguard Worker   // Incorporate Mali graphics memory if present.
176*635a8641SAndroid Build Coastguard Worker   FilePath mali_memory_file("/sys/class/misc/mali0/device/memory");
177*635a8641SAndroid Build Coastguard Worker   std::string mali_memory_data;
178*635a8641SAndroid Build Coastguard Worker   if (ReadFileToString(mali_memory_file, &mali_memory_data)) {
179*635a8641SAndroid Build Coastguard Worker     long long mali_size = -1;
180*635a8641SAndroid Build Coastguard Worker     int num_res = sscanf(mali_memory_data.c_str(), "%lld bytes", &mali_size);
181*635a8641SAndroid Build Coastguard Worker     if (num_res == 1)
182*635a8641SAndroid Build Coastguard Worker       meminfo->gem_size += mali_size;
183*635a8641SAndroid Build Coastguard Worker   }
184*635a8641SAndroid Build Coastguard Worker #endif  // defined(ARCH_CPU_ARM_FAMILY)
185*635a8641SAndroid Build Coastguard Worker }
186*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
187*635a8641SAndroid Build Coastguard Worker 
188*635a8641SAndroid Build Coastguard Worker }  // namespace
189*635a8641SAndroid Build Coastguard Worker 
190*635a8641SAndroid Build Coastguard Worker // static
CreateProcessMetrics(ProcessHandle process)191*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
192*635a8641SAndroid Build Coastguard Worker     ProcessHandle process) {
193*635a8641SAndroid Build Coastguard Worker   return WrapUnique(new ProcessMetrics(process));
194*635a8641SAndroid Build Coastguard Worker }
195*635a8641SAndroid Build Coastguard Worker 
GetResidentSetSize() const196*635a8641SAndroid Build Coastguard Worker size_t ProcessMetrics::GetResidentSetSize() const {
197*635a8641SAndroid Build Coastguard Worker   return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) *
198*635a8641SAndroid Build Coastguard Worker       getpagesize();
199*635a8641SAndroid Build Coastguard Worker }
200*635a8641SAndroid Build Coastguard Worker 
GetCumulativeCPUUsage()201*635a8641SAndroid Build Coastguard Worker TimeDelta ProcessMetrics::GetCumulativeCPUUsage() {
202*635a8641SAndroid Build Coastguard Worker   return internal::ClockTicksToTimeDelta(GetProcessCPU(process_));
203*635a8641SAndroid Build Coastguard Worker }
204*635a8641SAndroid Build Coastguard Worker 
205*635a8641SAndroid Build Coastguard Worker // For the /proc/self/io file to exist, the Linux kernel must have
206*635a8641SAndroid Build Coastguard Worker // CONFIG_TASK_IO_ACCOUNTING enabled.
GetIOCounters(IoCounters * io_counters) const207*635a8641SAndroid Build Coastguard Worker bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
208*635a8641SAndroid Build Coastguard Worker   StringPairs pairs;
209*635a8641SAndroid Build Coastguard Worker   if (!ReadProcFileToTrimmedStringPairs(process_, "io", &pairs))
210*635a8641SAndroid Build Coastguard Worker     return false;
211*635a8641SAndroid Build Coastguard Worker 
212*635a8641SAndroid Build Coastguard Worker   io_counters->OtherOperationCount = 0;
213*635a8641SAndroid Build Coastguard Worker   io_counters->OtherTransferCount = 0;
214*635a8641SAndroid Build Coastguard Worker 
215*635a8641SAndroid Build Coastguard Worker   for (const auto& pair : pairs) {
216*635a8641SAndroid Build Coastguard Worker     const std::string& key = pair.first;
217*635a8641SAndroid Build Coastguard Worker     const std::string& value_str = pair.second;
218*635a8641SAndroid Build Coastguard Worker     uint64_t* target_counter = nullptr;
219*635a8641SAndroid Build Coastguard Worker     if (key == "syscr")
220*635a8641SAndroid Build Coastguard Worker       target_counter = &io_counters->ReadOperationCount;
221*635a8641SAndroid Build Coastguard Worker     else if (key == "syscw")
222*635a8641SAndroid Build Coastguard Worker       target_counter = &io_counters->WriteOperationCount;
223*635a8641SAndroid Build Coastguard Worker     else if (key == "rchar")
224*635a8641SAndroid Build Coastguard Worker       target_counter = &io_counters->ReadTransferCount;
225*635a8641SAndroid Build Coastguard Worker     else if (key == "wchar")
226*635a8641SAndroid Build Coastguard Worker       target_counter = &io_counters->WriteTransferCount;
227*635a8641SAndroid Build Coastguard Worker     if (!target_counter)
228*635a8641SAndroid Build Coastguard Worker       continue;
229*635a8641SAndroid Build Coastguard Worker     bool converted = StringToUint64(value_str, target_counter);
230*635a8641SAndroid Build Coastguard Worker     DCHECK(converted);
231*635a8641SAndroid Build Coastguard Worker   }
232*635a8641SAndroid Build Coastguard Worker   return true;
233*635a8641SAndroid Build Coastguard Worker }
234*635a8641SAndroid Build Coastguard Worker 
235*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX) || defined(OS_ANDROID)
GetVmSwapBytes() const236*635a8641SAndroid Build Coastguard Worker uint64_t ProcessMetrics::GetVmSwapBytes() const {
237*635a8641SAndroid Build Coastguard Worker   return ReadProcStatusAndGetFieldAsSizeT(process_, "VmSwap") * 1024;
238*635a8641SAndroid Build Coastguard Worker }
239*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
240*635a8641SAndroid Build Coastguard Worker 
241*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX) || defined(OS_ANDROID)
GetPageFaultCounts(PageFaultCounts * counts) const242*635a8641SAndroid Build Coastguard Worker bool ProcessMetrics::GetPageFaultCounts(PageFaultCounts* counts) const {
243*635a8641SAndroid Build Coastguard Worker   // We are not using internal::ReadStatsFileAndGetFieldAsInt64(), since it
244*635a8641SAndroid Build Coastguard Worker   // would read the file twice, and return inconsistent numbers.
245*635a8641SAndroid Build Coastguard Worker   std::string stats_data;
246*635a8641SAndroid Build Coastguard Worker   if (!internal::ReadProcStats(process_, &stats_data))
247*635a8641SAndroid Build Coastguard Worker     return false;
248*635a8641SAndroid Build Coastguard Worker   std::vector<std::string> proc_stats;
249*635a8641SAndroid Build Coastguard Worker   if (!internal::ParseProcStats(stats_data, &proc_stats))
250*635a8641SAndroid Build Coastguard Worker     return false;
251*635a8641SAndroid Build Coastguard Worker 
252*635a8641SAndroid Build Coastguard Worker   counts->minor =
253*635a8641SAndroid Build Coastguard Worker       internal::GetProcStatsFieldAsInt64(proc_stats, internal::VM_MINFLT);
254*635a8641SAndroid Build Coastguard Worker   counts->major =
255*635a8641SAndroid Build Coastguard Worker       internal::GetProcStatsFieldAsInt64(proc_stats, internal::VM_MAJFLT);
256*635a8641SAndroid Build Coastguard Worker   return true;
257*635a8641SAndroid Build Coastguard Worker }
258*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
259*635a8641SAndroid Build Coastguard Worker 
GetOpenFdCount() const260*635a8641SAndroid Build Coastguard Worker int ProcessMetrics::GetOpenFdCount() const {
261*635a8641SAndroid Build Coastguard Worker   // Use /proc/<pid>/fd to count the number of entries there.
262*635a8641SAndroid Build Coastguard Worker   FilePath fd_path = internal::GetProcPidDir(process_).Append("fd");
263*635a8641SAndroid Build Coastguard Worker 
264*635a8641SAndroid Build Coastguard Worker   DirReaderPosix dir_reader(fd_path.value().c_str());
265*635a8641SAndroid Build Coastguard Worker   if (!dir_reader.IsValid())
266*635a8641SAndroid Build Coastguard Worker     return -1;
267*635a8641SAndroid Build Coastguard Worker 
268*635a8641SAndroid Build Coastguard Worker   int total_count = 0;
269*635a8641SAndroid Build Coastguard Worker   for (; dir_reader.Next(); ) {
270*635a8641SAndroid Build Coastguard Worker     const char* name = dir_reader.name();
271*635a8641SAndroid Build Coastguard Worker     if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
272*635a8641SAndroid Build Coastguard Worker       ++total_count;
273*635a8641SAndroid Build Coastguard Worker   }
274*635a8641SAndroid Build Coastguard Worker 
275*635a8641SAndroid Build Coastguard Worker   return total_count;
276*635a8641SAndroid Build Coastguard Worker }
277*635a8641SAndroid Build Coastguard Worker 
GetOpenFdSoftLimit() const278*635a8641SAndroid Build Coastguard Worker int ProcessMetrics::GetOpenFdSoftLimit() const {
279*635a8641SAndroid Build Coastguard Worker   // Use /proc/<pid>/limits to read the open fd limit.
280*635a8641SAndroid Build Coastguard Worker   FilePath fd_path = internal::GetProcPidDir(process_).Append("limits");
281*635a8641SAndroid Build Coastguard Worker 
282*635a8641SAndroid Build Coastguard Worker   std::string limits_contents;
283*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(fd_path, &limits_contents))
284*635a8641SAndroid Build Coastguard Worker     return -1;
285*635a8641SAndroid Build Coastguard Worker 
286*635a8641SAndroid Build Coastguard Worker   for (const auto& line : SplitStringPiece(
287*635a8641SAndroid Build Coastguard Worker            limits_contents, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
288*635a8641SAndroid Build Coastguard Worker     if (!line.starts_with("Max open files"))
289*635a8641SAndroid Build Coastguard Worker       continue;
290*635a8641SAndroid Build Coastguard Worker 
291*635a8641SAndroid Build Coastguard Worker     auto tokens =
292*635a8641SAndroid Build Coastguard Worker         SplitStringPiece(line, " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
293*635a8641SAndroid Build Coastguard Worker     if (tokens.size() > 3) {
294*635a8641SAndroid Build Coastguard Worker       int limit = -1;
295*635a8641SAndroid Build Coastguard Worker       if (!StringToInt(tokens[3], &limit))
296*635a8641SAndroid Build Coastguard Worker         return -1;
297*635a8641SAndroid Build Coastguard Worker       return limit;
298*635a8641SAndroid Build Coastguard Worker     }
299*635a8641SAndroid Build Coastguard Worker   }
300*635a8641SAndroid Build Coastguard Worker   return -1;
301*635a8641SAndroid Build Coastguard Worker }
302*635a8641SAndroid Build Coastguard Worker 
303*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX) || defined(OS_AIX)
ProcessMetrics(ProcessHandle process)304*635a8641SAndroid Build Coastguard Worker ProcessMetrics::ProcessMetrics(ProcessHandle process)
305*635a8641SAndroid Build Coastguard Worker     : process_(process), last_absolute_idle_wakeups_(0) {}
306*635a8641SAndroid Build Coastguard Worker #else
ProcessMetrics(ProcessHandle process)307*635a8641SAndroid Build Coastguard Worker ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process) {}
308*635a8641SAndroid Build Coastguard Worker #endif
309*635a8641SAndroid Build Coastguard Worker 
310*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
311*635a8641SAndroid Build Coastguard Worker // Private, Shared and Proportional working set sizes are obtained from
312*635a8641SAndroid Build Coastguard Worker // /proc/<pid>/totmaps
GetTotalsSummary() const313*635a8641SAndroid Build Coastguard Worker ProcessMetrics::TotalsSummary ProcessMetrics::GetTotalsSummary() const {
314*635a8641SAndroid Build Coastguard Worker   // The format of /proc/<pid>/totmaps is:
315*635a8641SAndroid Build Coastguard Worker   //
316*635a8641SAndroid Build Coastguard Worker   // Rss:                6120 kB
317*635a8641SAndroid Build Coastguard Worker   // Pss:                3335 kB
318*635a8641SAndroid Build Coastguard Worker   // Shared_Clean:       1008 kB
319*635a8641SAndroid Build Coastguard Worker   // Shared_Dirty:       4012 kB
320*635a8641SAndroid Build Coastguard Worker   // Private_Clean:         4 kB
321*635a8641SAndroid Build Coastguard Worker   // Private_Dirty:      1096 kB
322*635a8641SAndroid Build Coastguard Worker   // Referenced:          XXX kB
323*635a8641SAndroid Build Coastguard Worker   // Anonymous:           XXX kB
324*635a8641SAndroid Build Coastguard Worker   // AnonHugePages:       XXX kB
325*635a8641SAndroid Build Coastguard Worker   // Swap:                XXX kB
326*635a8641SAndroid Build Coastguard Worker   // Locked:              XXX kB
327*635a8641SAndroid Build Coastguard Worker   ProcessMetrics::TotalsSummary summary = {};
328*635a8641SAndroid Build Coastguard Worker 
329*635a8641SAndroid Build Coastguard Worker   const size_t kPrivate_CleanIndex = (4 * 3) + 1;
330*635a8641SAndroid Build Coastguard Worker   const size_t kPrivate_DirtyIndex = (5 * 3) + 1;
331*635a8641SAndroid Build Coastguard Worker   const size_t kSwapIndex = (9 * 3) + 1;
332*635a8641SAndroid Build Coastguard Worker 
333*635a8641SAndroid Build Coastguard Worker   std::string totmaps_data;
334*635a8641SAndroid Build Coastguard Worker   {
335*635a8641SAndroid Build Coastguard Worker     FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps");
336*635a8641SAndroid Build Coastguard Worker     ThreadRestrictions::ScopedAllowIO allow_io;
337*635a8641SAndroid Build Coastguard Worker     bool ret = ReadFileToString(totmaps_file, &totmaps_data);
338*635a8641SAndroid Build Coastguard Worker     if (!ret || totmaps_data.length() == 0)
339*635a8641SAndroid Build Coastguard Worker       return summary;
340*635a8641SAndroid Build Coastguard Worker   }
341*635a8641SAndroid Build Coastguard Worker 
342*635a8641SAndroid Build Coastguard Worker   std::vector<std::string> totmaps_fields = SplitString(
343*635a8641SAndroid Build Coastguard Worker       totmaps_data, kWhitespaceASCII, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
344*635a8641SAndroid Build Coastguard Worker 
345*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
346*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex - 1]);
347*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ("Swap:", totmaps_fields[kSwapIndex-1]);
348*635a8641SAndroid Build Coastguard Worker 
349*635a8641SAndroid Build Coastguard Worker   int private_clean_kb = 0;
350*635a8641SAndroid Build Coastguard Worker   int private_dirty_kb = 0;
351*635a8641SAndroid Build Coastguard Worker   int swap_kb = 0;
352*635a8641SAndroid Build Coastguard Worker   bool success = true;
353*635a8641SAndroid Build Coastguard Worker   success &=
354*635a8641SAndroid Build Coastguard Worker       StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean_kb);
355*635a8641SAndroid Build Coastguard Worker   success &=
356*635a8641SAndroid Build Coastguard Worker       StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty_kb);
357*635a8641SAndroid Build Coastguard Worker   success &= StringToInt(totmaps_fields[kSwapIndex], &swap_kb);
358*635a8641SAndroid Build Coastguard Worker 
359*635a8641SAndroid Build Coastguard Worker   if (!success)
360*635a8641SAndroid Build Coastguard Worker     return summary;
361*635a8641SAndroid Build Coastguard Worker 
362*635a8641SAndroid Build Coastguard Worker   summary.private_clean_kb = private_clean_kb;
363*635a8641SAndroid Build Coastguard Worker   summary.private_dirty_kb = private_dirty_kb;
364*635a8641SAndroid Build Coastguard Worker   summary.swap_kb = swap_kb;
365*635a8641SAndroid Build Coastguard Worker 
366*635a8641SAndroid Build Coastguard Worker   return summary;
367*635a8641SAndroid Build Coastguard Worker }
368*635a8641SAndroid Build Coastguard Worker #endif
369*635a8641SAndroid Build Coastguard Worker 
GetSystemCommitCharge()370*635a8641SAndroid Build Coastguard Worker size_t GetSystemCommitCharge() {
371*635a8641SAndroid Build Coastguard Worker   SystemMemoryInfoKB meminfo;
372*635a8641SAndroid Build Coastguard Worker   if (!GetSystemMemoryInfo(&meminfo))
373*635a8641SAndroid Build Coastguard Worker     return 0;
374*635a8641SAndroid Build Coastguard Worker   return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
375*635a8641SAndroid Build Coastguard Worker }
376*635a8641SAndroid Build Coastguard Worker 
ParseProcStatCPU(StringPiece input)377*635a8641SAndroid Build Coastguard Worker int ParseProcStatCPU(StringPiece input) {
378*635a8641SAndroid Build Coastguard Worker   // |input| may be empty if the process disappeared somehow.
379*635a8641SAndroid Build Coastguard Worker   // e.g. http://crbug.com/145811.
380*635a8641SAndroid Build Coastguard Worker   if (input.empty())
381*635a8641SAndroid Build Coastguard Worker     return -1;
382*635a8641SAndroid Build Coastguard Worker 
383*635a8641SAndroid Build Coastguard Worker   size_t start = input.find_last_of(')');
384*635a8641SAndroid Build Coastguard Worker   if (start == input.npos)
385*635a8641SAndroid Build Coastguard Worker     return -1;
386*635a8641SAndroid Build Coastguard Worker 
387*635a8641SAndroid Build Coastguard Worker   // Number of spaces remaining until reaching utime's index starting after the
388*635a8641SAndroid Build Coastguard Worker   // last ')'.
389*635a8641SAndroid Build Coastguard Worker   int num_spaces_remaining = internal::VM_UTIME - 1;
390*635a8641SAndroid Build Coastguard Worker 
391*635a8641SAndroid Build Coastguard Worker   size_t i = start;
392*635a8641SAndroid Build Coastguard Worker   while ((i = input.find(' ', i + 1)) != input.npos) {
393*635a8641SAndroid Build Coastguard Worker     // Validate the assumption that there aren't any contiguous spaces
394*635a8641SAndroid Build Coastguard Worker     // in |input| before utime.
395*635a8641SAndroid Build Coastguard Worker     DCHECK_NE(input[i - 1], ' ');
396*635a8641SAndroid Build Coastguard Worker     if (--num_spaces_remaining == 0) {
397*635a8641SAndroid Build Coastguard Worker       int utime = 0;
398*635a8641SAndroid Build Coastguard Worker       int stime = 0;
399*635a8641SAndroid Build Coastguard Worker       if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2)
400*635a8641SAndroid Build Coastguard Worker         return -1;
401*635a8641SAndroid Build Coastguard Worker 
402*635a8641SAndroid Build Coastguard Worker       return utime + stime;
403*635a8641SAndroid Build Coastguard Worker     }
404*635a8641SAndroid Build Coastguard Worker   }
405*635a8641SAndroid Build Coastguard Worker 
406*635a8641SAndroid Build Coastguard Worker   return -1;
407*635a8641SAndroid Build Coastguard Worker }
408*635a8641SAndroid Build Coastguard Worker 
GetNumberOfThreads(ProcessHandle process)409*635a8641SAndroid Build Coastguard Worker int GetNumberOfThreads(ProcessHandle process) {
410*635a8641SAndroid Build Coastguard Worker   return internal::ReadProcStatsAndGetFieldAsInt64(process,
411*635a8641SAndroid Build Coastguard Worker                                                    internal::VM_NUMTHREADS);
412*635a8641SAndroid Build Coastguard Worker }
413*635a8641SAndroid Build Coastguard Worker 
414*635a8641SAndroid Build Coastguard Worker const char kProcSelfExe[] = "/proc/self/exe";
415*635a8641SAndroid Build Coastguard Worker 
416*635a8641SAndroid Build Coastguard Worker namespace {
417*635a8641SAndroid Build Coastguard Worker 
418*635a8641SAndroid Build Coastguard Worker // The format of /proc/diskstats is:
419*635a8641SAndroid Build Coastguard Worker //  Device major number
420*635a8641SAndroid Build Coastguard Worker //  Device minor number
421*635a8641SAndroid Build Coastguard Worker //  Device name
422*635a8641SAndroid Build Coastguard Worker //  Field  1 -- # of reads completed
423*635a8641SAndroid Build Coastguard Worker //      This is the total number of reads completed successfully.
424*635a8641SAndroid Build Coastguard Worker //  Field  2 -- # of reads merged, field 6 -- # of writes merged
425*635a8641SAndroid Build Coastguard Worker //      Reads and writes which are adjacent to each other may be merged for
426*635a8641SAndroid Build Coastguard Worker //      efficiency.  Thus two 4K reads may become one 8K read before it is
427*635a8641SAndroid Build Coastguard Worker //      ultimately handed to the disk, and so it will be counted (and queued)
428*635a8641SAndroid Build Coastguard Worker //      as only one I/O.  This field lets you know how often this was done.
429*635a8641SAndroid Build Coastguard Worker //  Field  3 -- # of sectors read
430*635a8641SAndroid Build Coastguard Worker //      This is the total number of sectors read successfully.
431*635a8641SAndroid Build Coastguard Worker //  Field  4 -- # of milliseconds spent reading
432*635a8641SAndroid Build Coastguard Worker //      This is the total number of milliseconds spent by all reads (as
433*635a8641SAndroid Build Coastguard Worker //      measured from __make_request() to end_that_request_last()).
434*635a8641SAndroid Build Coastguard Worker //  Field  5 -- # of writes completed
435*635a8641SAndroid Build Coastguard Worker //      This is the total number of writes completed successfully.
436*635a8641SAndroid Build Coastguard Worker //  Field  6 -- # of writes merged
437*635a8641SAndroid Build Coastguard Worker //      See the description of field 2.
438*635a8641SAndroid Build Coastguard Worker //  Field  7 -- # of sectors written
439*635a8641SAndroid Build Coastguard Worker //      This is the total number of sectors written successfully.
440*635a8641SAndroid Build Coastguard Worker //  Field  8 -- # of milliseconds spent writing
441*635a8641SAndroid Build Coastguard Worker //      This is the total number of milliseconds spent by all writes (as
442*635a8641SAndroid Build Coastguard Worker //      measured from __make_request() to end_that_request_last()).
443*635a8641SAndroid Build Coastguard Worker //  Field  9 -- # of I/Os currently in progress
444*635a8641SAndroid Build Coastguard Worker //      The only field that should go to zero. Incremented as requests are
445*635a8641SAndroid Build Coastguard Worker //      given to appropriate struct request_queue and decremented as they
446*635a8641SAndroid Build Coastguard Worker //      finish.
447*635a8641SAndroid Build Coastguard Worker //  Field 10 -- # of milliseconds spent doing I/Os
448*635a8641SAndroid Build Coastguard Worker //      This field increases so long as field 9 is nonzero.
449*635a8641SAndroid Build Coastguard Worker //  Field 11 -- weighted # of milliseconds spent doing I/Os
450*635a8641SAndroid Build Coastguard Worker //      This field is incremented at each I/O start, I/O completion, I/O
451*635a8641SAndroid Build Coastguard Worker //      merge, or read of these stats by the number of I/Os in progress
452*635a8641SAndroid Build Coastguard Worker //      (field 9) times the number of milliseconds spent doing I/O since the
453*635a8641SAndroid Build Coastguard Worker //      last update of this field.  This can provide an easy measure of both
454*635a8641SAndroid Build Coastguard Worker //      I/O completion time and the backlog that may be accumulating.
455*635a8641SAndroid Build Coastguard Worker 
456*635a8641SAndroid Build Coastguard Worker const size_t kDiskDriveName = 2;
457*635a8641SAndroid Build Coastguard Worker const size_t kDiskReads = 3;
458*635a8641SAndroid Build Coastguard Worker const size_t kDiskReadsMerged = 4;
459*635a8641SAndroid Build Coastguard Worker const size_t kDiskSectorsRead = 5;
460*635a8641SAndroid Build Coastguard Worker const size_t kDiskReadTime = 6;
461*635a8641SAndroid Build Coastguard Worker const size_t kDiskWrites = 7;
462*635a8641SAndroid Build Coastguard Worker const size_t kDiskWritesMerged = 8;
463*635a8641SAndroid Build Coastguard Worker const size_t kDiskSectorsWritten = 9;
464*635a8641SAndroid Build Coastguard Worker const size_t kDiskWriteTime = 10;
465*635a8641SAndroid Build Coastguard Worker const size_t kDiskIO = 11;
466*635a8641SAndroid Build Coastguard Worker const size_t kDiskIOTime = 12;
467*635a8641SAndroid Build Coastguard Worker const size_t kDiskWeightedIOTime = 13;
468*635a8641SAndroid Build Coastguard Worker 
469*635a8641SAndroid Build Coastguard Worker }  // namespace
470*635a8641SAndroid Build Coastguard Worker 
ToValue() const471*635a8641SAndroid Build Coastguard Worker std::unique_ptr<DictionaryValue> SystemMemoryInfoKB::ToValue() const {
472*635a8641SAndroid Build Coastguard Worker   auto res = std::make_unique<DictionaryValue>();
473*635a8641SAndroid Build Coastguard Worker   res->SetInteger("total", total);
474*635a8641SAndroid Build Coastguard Worker   res->SetInteger("free", free);
475*635a8641SAndroid Build Coastguard Worker   res->SetInteger("available", available);
476*635a8641SAndroid Build Coastguard Worker   res->SetInteger("buffers", buffers);
477*635a8641SAndroid Build Coastguard Worker   res->SetInteger("cached", cached);
478*635a8641SAndroid Build Coastguard Worker   res->SetInteger("active_anon", active_anon);
479*635a8641SAndroid Build Coastguard Worker   res->SetInteger("inactive_anon", inactive_anon);
480*635a8641SAndroid Build Coastguard Worker   res->SetInteger("active_file", active_file);
481*635a8641SAndroid Build Coastguard Worker   res->SetInteger("inactive_file", inactive_file);
482*635a8641SAndroid Build Coastguard Worker   res->SetInteger("swap_total", swap_total);
483*635a8641SAndroid Build Coastguard Worker   res->SetInteger("swap_free", swap_free);
484*635a8641SAndroid Build Coastguard Worker   res->SetInteger("swap_used", swap_total - swap_free);
485*635a8641SAndroid Build Coastguard Worker   res->SetInteger("dirty", dirty);
486*635a8641SAndroid Build Coastguard Worker   res->SetInteger("reclaimable", reclaimable);
487*635a8641SAndroid Build Coastguard Worker #ifdef OS_CHROMEOS
488*635a8641SAndroid Build Coastguard Worker   res->SetInteger("shmem", shmem);
489*635a8641SAndroid Build Coastguard Worker   res->SetInteger("slab", slab);
490*635a8641SAndroid Build Coastguard Worker   res->SetInteger("gem_objects", gem_objects);
491*635a8641SAndroid Build Coastguard Worker   res->SetInteger("gem_size", gem_size);
492*635a8641SAndroid Build Coastguard Worker #endif
493*635a8641SAndroid Build Coastguard Worker 
494*635a8641SAndroid Build Coastguard Worker   return res;
495*635a8641SAndroid Build Coastguard Worker }
496*635a8641SAndroid Build Coastguard Worker 
ParseProcMeminfo(StringPiece meminfo_data,SystemMemoryInfoKB * meminfo)497*635a8641SAndroid Build Coastguard Worker bool ParseProcMeminfo(StringPiece meminfo_data, SystemMemoryInfoKB* meminfo) {
498*635a8641SAndroid Build Coastguard Worker   // The format of /proc/meminfo is:
499*635a8641SAndroid Build Coastguard Worker   //
500*635a8641SAndroid Build Coastguard Worker   // MemTotal:      8235324 kB
501*635a8641SAndroid Build Coastguard Worker   // MemFree:       1628304 kB
502*635a8641SAndroid Build Coastguard Worker   // Buffers:        429596 kB
503*635a8641SAndroid Build Coastguard Worker   // Cached:        4728232 kB
504*635a8641SAndroid Build Coastguard Worker   // ...
505*635a8641SAndroid Build Coastguard Worker   // There is no guarantee on the ordering or position
506*635a8641SAndroid Build Coastguard Worker   // though it doesn't appear to change very often
507*635a8641SAndroid Build Coastguard Worker 
508*635a8641SAndroid Build Coastguard Worker   // As a basic sanity check at the end, make sure the MemTotal value will be at
509*635a8641SAndroid Build Coastguard Worker   // least non-zero. So start off with a zero total.
510*635a8641SAndroid Build Coastguard Worker   meminfo->total = 0;
511*635a8641SAndroid Build Coastguard Worker 
512*635a8641SAndroid Build Coastguard Worker   for (const StringPiece& line : SplitStringPiece(
513*635a8641SAndroid Build Coastguard Worker            meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
514*635a8641SAndroid Build Coastguard Worker     std::vector<StringPiece> tokens = SplitStringPiece(
515*635a8641SAndroid Build Coastguard Worker         line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
516*635a8641SAndroid Build Coastguard Worker     // HugePages_* only has a number and no suffix so there may not be exactly 3
517*635a8641SAndroid Build Coastguard Worker     // tokens.
518*635a8641SAndroid Build Coastguard Worker     if (tokens.size() <= 1) {
519*635a8641SAndroid Build Coastguard Worker       DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
520*635a8641SAndroid Build Coastguard Worker                     << " malformed line: " << line.as_string();
521*635a8641SAndroid Build Coastguard Worker       continue;
522*635a8641SAndroid Build Coastguard Worker     }
523*635a8641SAndroid Build Coastguard Worker 
524*635a8641SAndroid Build Coastguard Worker     int* target = nullptr;
525*635a8641SAndroid Build Coastguard Worker     if (tokens[0] == "MemTotal:")
526*635a8641SAndroid Build Coastguard Worker       target = &meminfo->total;
527*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "MemFree:")
528*635a8641SAndroid Build Coastguard Worker       target = &meminfo->free;
529*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "MemAvailable:")
530*635a8641SAndroid Build Coastguard Worker       target = &meminfo->available;
531*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Buffers:")
532*635a8641SAndroid Build Coastguard Worker       target = &meminfo->buffers;
533*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Cached:")
534*635a8641SAndroid Build Coastguard Worker       target = &meminfo->cached;
535*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Active(anon):")
536*635a8641SAndroid Build Coastguard Worker       target = &meminfo->active_anon;
537*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Inactive(anon):")
538*635a8641SAndroid Build Coastguard Worker       target = &meminfo->inactive_anon;
539*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Active(file):")
540*635a8641SAndroid Build Coastguard Worker       target = &meminfo->active_file;
541*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Inactive(file):")
542*635a8641SAndroid Build Coastguard Worker       target = &meminfo->inactive_file;
543*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "SwapTotal:")
544*635a8641SAndroid Build Coastguard Worker       target = &meminfo->swap_total;
545*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "SwapFree:")
546*635a8641SAndroid Build Coastguard Worker       target = &meminfo->swap_free;
547*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Dirty:")
548*635a8641SAndroid Build Coastguard Worker       target = &meminfo->dirty;
549*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "SReclaimable:")
550*635a8641SAndroid Build Coastguard Worker       target = &meminfo->reclaimable;
551*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
552*635a8641SAndroid Build Coastguard Worker     // Chrome OS has a tweaked kernel that allows querying Shmem, which is
553*635a8641SAndroid Build Coastguard Worker     // usually video memory otherwise invisible to the OS.
554*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Shmem:")
555*635a8641SAndroid Build Coastguard Worker       target = &meminfo->shmem;
556*635a8641SAndroid Build Coastguard Worker     else if (tokens[0] == "Slab:")
557*635a8641SAndroid Build Coastguard Worker       target = &meminfo->slab;
558*635a8641SAndroid Build Coastguard Worker #endif
559*635a8641SAndroid Build Coastguard Worker     if (target)
560*635a8641SAndroid Build Coastguard Worker       StringToInt(tokens[1], target);
561*635a8641SAndroid Build Coastguard Worker   }
562*635a8641SAndroid Build Coastguard Worker 
563*635a8641SAndroid Build Coastguard Worker   // Make sure the MemTotal is valid.
564*635a8641SAndroid Build Coastguard Worker   return meminfo->total > 0;
565*635a8641SAndroid Build Coastguard Worker }
566*635a8641SAndroid Build Coastguard Worker 
ParseProcVmstat(StringPiece vmstat_data,VmStatInfo * vmstat)567*635a8641SAndroid Build Coastguard Worker bool ParseProcVmstat(StringPiece vmstat_data, VmStatInfo* vmstat) {
568*635a8641SAndroid Build Coastguard Worker   // The format of /proc/vmstat is:
569*635a8641SAndroid Build Coastguard Worker   //
570*635a8641SAndroid Build Coastguard Worker   // nr_free_pages 299878
571*635a8641SAndroid Build Coastguard Worker   // nr_inactive_anon 239863
572*635a8641SAndroid Build Coastguard Worker   // nr_active_anon 1318966
573*635a8641SAndroid Build Coastguard Worker   // nr_inactive_file 2015629
574*635a8641SAndroid Build Coastguard Worker   // ...
575*635a8641SAndroid Build Coastguard Worker   //
576*635a8641SAndroid Build Coastguard Worker   // Iterate through the whole file because the position of the
577*635a8641SAndroid Build Coastguard Worker   // fields are dependent on the kernel version and configuration.
578*635a8641SAndroid Build Coastguard Worker   bool has_pswpin = false;
579*635a8641SAndroid Build Coastguard Worker   bool has_pswpout = false;
580*635a8641SAndroid Build Coastguard Worker   bool has_pgmajfault = false;
581*635a8641SAndroid Build Coastguard Worker   for (const StringPiece& line : SplitStringPiece(
582*635a8641SAndroid Build Coastguard Worker            vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
583*635a8641SAndroid Build Coastguard Worker     std::vector<StringPiece> tokens = SplitStringPiece(
584*635a8641SAndroid Build Coastguard Worker         line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
585*635a8641SAndroid Build Coastguard Worker     if (tokens.size() != 2)
586*635a8641SAndroid Build Coastguard Worker       continue;
587*635a8641SAndroid Build Coastguard Worker 
588*635a8641SAndroid Build Coastguard Worker     uint64_t val;
589*635a8641SAndroid Build Coastguard Worker     if (!StringToUint64(tokens[1], &val))
590*635a8641SAndroid Build Coastguard Worker       continue;
591*635a8641SAndroid Build Coastguard Worker 
592*635a8641SAndroid Build Coastguard Worker     if (tokens[0] == "pswpin") {
593*635a8641SAndroid Build Coastguard Worker       vmstat->pswpin = val;
594*635a8641SAndroid Build Coastguard Worker       DCHECK(!has_pswpin);
595*635a8641SAndroid Build Coastguard Worker       has_pswpin = true;
596*635a8641SAndroid Build Coastguard Worker     } else if (tokens[0] == "pswpout") {
597*635a8641SAndroid Build Coastguard Worker       vmstat->pswpout = val;
598*635a8641SAndroid Build Coastguard Worker       DCHECK(!has_pswpout);
599*635a8641SAndroid Build Coastguard Worker       has_pswpout = true;
600*635a8641SAndroid Build Coastguard Worker     } else if (tokens[0] == "pgmajfault") {
601*635a8641SAndroid Build Coastguard Worker       vmstat->pgmajfault = val;
602*635a8641SAndroid Build Coastguard Worker       DCHECK(!has_pgmajfault);
603*635a8641SAndroid Build Coastguard Worker       has_pgmajfault = true;
604*635a8641SAndroid Build Coastguard Worker     }
605*635a8641SAndroid Build Coastguard Worker     if (has_pswpin && has_pswpout && has_pgmajfault)
606*635a8641SAndroid Build Coastguard Worker       return true;
607*635a8641SAndroid Build Coastguard Worker   }
608*635a8641SAndroid Build Coastguard Worker 
609*635a8641SAndroid Build Coastguard Worker   return false;
610*635a8641SAndroid Build Coastguard Worker }
611*635a8641SAndroid Build Coastguard Worker 
GetSystemMemoryInfo(SystemMemoryInfoKB * meminfo)612*635a8641SAndroid Build Coastguard Worker bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
613*635a8641SAndroid Build Coastguard Worker   // Synchronously reading files in /proc and /sys are safe.
614*635a8641SAndroid Build Coastguard Worker   ThreadRestrictions::ScopedAllowIO allow_io;
615*635a8641SAndroid Build Coastguard Worker 
616*635a8641SAndroid Build Coastguard Worker   // Used memory is: total - free - buffers - caches
617*635a8641SAndroid Build Coastguard Worker   FilePath meminfo_file("/proc/meminfo");
618*635a8641SAndroid Build Coastguard Worker   std::string meminfo_data;
619*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(meminfo_file, &meminfo_data)) {
620*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to open " << meminfo_file.value();
621*635a8641SAndroid Build Coastguard Worker     return false;
622*635a8641SAndroid Build Coastguard Worker   }
623*635a8641SAndroid Build Coastguard Worker 
624*635a8641SAndroid Build Coastguard Worker   if (!ParseProcMeminfo(meminfo_data, meminfo)) {
625*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to parse " << meminfo_file.value();
626*635a8641SAndroid Build Coastguard Worker     return false;
627*635a8641SAndroid Build Coastguard Worker   }
628*635a8641SAndroid Build Coastguard Worker 
629*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
630*635a8641SAndroid Build Coastguard Worker   ReadChromeOSGraphicsMemory(meminfo);
631*635a8641SAndroid Build Coastguard Worker #endif
632*635a8641SAndroid Build Coastguard Worker 
633*635a8641SAndroid Build Coastguard Worker   return true;
634*635a8641SAndroid Build Coastguard Worker }
635*635a8641SAndroid Build Coastguard Worker 
ToValue() const636*635a8641SAndroid Build Coastguard Worker std::unique_ptr<DictionaryValue> VmStatInfo::ToValue() const {
637*635a8641SAndroid Build Coastguard Worker   auto res = std::make_unique<DictionaryValue>();
638*635a8641SAndroid Build Coastguard Worker   res->SetInteger("pswpin", pswpin);
639*635a8641SAndroid Build Coastguard Worker   res->SetInteger("pswpout", pswpout);
640*635a8641SAndroid Build Coastguard Worker   res->SetInteger("pgmajfault", pgmajfault);
641*635a8641SAndroid Build Coastguard Worker   return res;
642*635a8641SAndroid Build Coastguard Worker }
643*635a8641SAndroid Build Coastguard Worker 
GetVmStatInfo(VmStatInfo * vmstat)644*635a8641SAndroid Build Coastguard Worker bool GetVmStatInfo(VmStatInfo* vmstat) {
645*635a8641SAndroid Build Coastguard Worker   // Synchronously reading files in /proc and /sys are safe.
646*635a8641SAndroid Build Coastguard Worker   ThreadRestrictions::ScopedAllowIO allow_io;
647*635a8641SAndroid Build Coastguard Worker 
648*635a8641SAndroid Build Coastguard Worker   FilePath vmstat_file("/proc/vmstat");
649*635a8641SAndroid Build Coastguard Worker   std::string vmstat_data;
650*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(vmstat_file, &vmstat_data)) {
651*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to open " << vmstat_file.value();
652*635a8641SAndroid Build Coastguard Worker     return false;
653*635a8641SAndroid Build Coastguard Worker   }
654*635a8641SAndroid Build Coastguard Worker   if (!ParseProcVmstat(vmstat_data, vmstat)) {
655*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to parse " << vmstat_file.value();
656*635a8641SAndroid Build Coastguard Worker     return false;
657*635a8641SAndroid Build Coastguard Worker   }
658*635a8641SAndroid Build Coastguard Worker   return true;
659*635a8641SAndroid Build Coastguard Worker }
660*635a8641SAndroid Build Coastguard Worker 
SystemDiskInfo()661*635a8641SAndroid Build Coastguard Worker SystemDiskInfo::SystemDiskInfo() {
662*635a8641SAndroid Build Coastguard Worker   reads = 0;
663*635a8641SAndroid Build Coastguard Worker   reads_merged = 0;
664*635a8641SAndroid Build Coastguard Worker   sectors_read = 0;
665*635a8641SAndroid Build Coastguard Worker   read_time = 0;
666*635a8641SAndroid Build Coastguard Worker   writes = 0;
667*635a8641SAndroid Build Coastguard Worker   writes_merged = 0;
668*635a8641SAndroid Build Coastguard Worker   sectors_written = 0;
669*635a8641SAndroid Build Coastguard Worker   write_time = 0;
670*635a8641SAndroid Build Coastguard Worker   io = 0;
671*635a8641SAndroid Build Coastguard Worker   io_time = 0;
672*635a8641SAndroid Build Coastguard Worker   weighted_io_time = 0;
673*635a8641SAndroid Build Coastguard Worker }
674*635a8641SAndroid Build Coastguard Worker 
675*635a8641SAndroid Build Coastguard Worker SystemDiskInfo::SystemDiskInfo(const SystemDiskInfo& other) = default;
676*635a8641SAndroid Build Coastguard Worker 
ToValue() const677*635a8641SAndroid Build Coastguard Worker std::unique_ptr<Value> SystemDiskInfo::ToValue() const {
678*635a8641SAndroid Build Coastguard Worker   auto res = std::make_unique<DictionaryValue>();
679*635a8641SAndroid Build Coastguard Worker 
680*635a8641SAndroid Build Coastguard Worker   // Write out uint64_t variables as doubles.
681*635a8641SAndroid Build Coastguard Worker   // Note: this may discard some precision, but for JS there's no other option.
682*635a8641SAndroid Build Coastguard Worker   res->SetDouble("reads", static_cast<double>(reads));
683*635a8641SAndroid Build Coastguard Worker   res->SetDouble("reads_merged", static_cast<double>(reads_merged));
684*635a8641SAndroid Build Coastguard Worker   res->SetDouble("sectors_read", static_cast<double>(sectors_read));
685*635a8641SAndroid Build Coastguard Worker   res->SetDouble("read_time", static_cast<double>(read_time));
686*635a8641SAndroid Build Coastguard Worker   res->SetDouble("writes", static_cast<double>(writes));
687*635a8641SAndroid Build Coastguard Worker   res->SetDouble("writes_merged", static_cast<double>(writes_merged));
688*635a8641SAndroid Build Coastguard Worker   res->SetDouble("sectors_written", static_cast<double>(sectors_written));
689*635a8641SAndroid Build Coastguard Worker   res->SetDouble("write_time", static_cast<double>(write_time));
690*635a8641SAndroid Build Coastguard Worker   res->SetDouble("io", static_cast<double>(io));
691*635a8641SAndroid Build Coastguard Worker   res->SetDouble("io_time", static_cast<double>(io_time));
692*635a8641SAndroid Build Coastguard Worker   res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
693*635a8641SAndroid Build Coastguard Worker 
694*635a8641SAndroid Build Coastguard Worker   return std::move(res);
695*635a8641SAndroid Build Coastguard Worker }
696*635a8641SAndroid Build Coastguard Worker 
IsValidDiskName(StringPiece candidate)697*635a8641SAndroid Build Coastguard Worker bool IsValidDiskName(StringPiece candidate) {
698*635a8641SAndroid Build Coastguard Worker   if (candidate.length() < 3)
699*635a8641SAndroid Build Coastguard Worker     return false;
700*635a8641SAndroid Build Coastguard Worker 
701*635a8641SAndroid Build Coastguard Worker   if (candidate[1] == 'd' &&
702*635a8641SAndroid Build Coastguard Worker       (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) {
703*635a8641SAndroid Build Coastguard Worker     // [hsv]d[a-z]+ case
704*635a8641SAndroid Build Coastguard Worker     for (size_t i = 2; i < candidate.length(); ++i) {
705*635a8641SAndroid Build Coastguard Worker       if (!islower(candidate[i]))
706*635a8641SAndroid Build Coastguard Worker         return false;
707*635a8641SAndroid Build Coastguard Worker     }
708*635a8641SAndroid Build Coastguard Worker     return true;
709*635a8641SAndroid Build Coastguard Worker   }
710*635a8641SAndroid Build Coastguard Worker 
711*635a8641SAndroid Build Coastguard Worker   const char kMMCName[] = "mmcblk";
712*635a8641SAndroid Build Coastguard Worker   if (!candidate.starts_with(kMMCName))
713*635a8641SAndroid Build Coastguard Worker     return false;
714*635a8641SAndroid Build Coastguard Worker 
715*635a8641SAndroid Build Coastguard Worker   // mmcblk[0-9]+ case
716*635a8641SAndroid Build Coastguard Worker   for (size_t i = strlen(kMMCName); i < candidate.length(); ++i) {
717*635a8641SAndroid Build Coastguard Worker     if (!isdigit(candidate[i]))
718*635a8641SAndroid Build Coastguard Worker       return false;
719*635a8641SAndroid Build Coastguard Worker   }
720*635a8641SAndroid Build Coastguard Worker   return true;
721*635a8641SAndroid Build Coastguard Worker }
722*635a8641SAndroid Build Coastguard Worker 
GetSystemDiskInfo(SystemDiskInfo * diskinfo)723*635a8641SAndroid Build Coastguard Worker bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
724*635a8641SAndroid Build Coastguard Worker   // Synchronously reading files in /proc does not hit the disk.
725*635a8641SAndroid Build Coastguard Worker   ThreadRestrictions::ScopedAllowIO allow_io;
726*635a8641SAndroid Build Coastguard Worker 
727*635a8641SAndroid Build Coastguard Worker   FilePath diskinfo_file("/proc/diskstats");
728*635a8641SAndroid Build Coastguard Worker   std::string diskinfo_data;
729*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(diskinfo_file, &diskinfo_data)) {
730*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to open " << diskinfo_file.value();
731*635a8641SAndroid Build Coastguard Worker     return false;
732*635a8641SAndroid Build Coastguard Worker   }
733*635a8641SAndroid Build Coastguard Worker 
734*635a8641SAndroid Build Coastguard Worker   std::vector<StringPiece> diskinfo_lines = SplitStringPiece(
735*635a8641SAndroid Build Coastguard Worker       diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
736*635a8641SAndroid Build Coastguard Worker   if (diskinfo_lines.empty()) {
737*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "No lines found";
738*635a8641SAndroid Build Coastguard Worker     return false;
739*635a8641SAndroid Build Coastguard Worker   }
740*635a8641SAndroid Build Coastguard Worker 
741*635a8641SAndroid Build Coastguard Worker   diskinfo->reads = 0;
742*635a8641SAndroid Build Coastguard Worker   diskinfo->reads_merged = 0;
743*635a8641SAndroid Build Coastguard Worker   diskinfo->sectors_read = 0;
744*635a8641SAndroid Build Coastguard Worker   diskinfo->read_time = 0;
745*635a8641SAndroid Build Coastguard Worker   diskinfo->writes = 0;
746*635a8641SAndroid Build Coastguard Worker   diskinfo->writes_merged = 0;
747*635a8641SAndroid Build Coastguard Worker   diskinfo->sectors_written = 0;
748*635a8641SAndroid Build Coastguard Worker   diskinfo->write_time = 0;
749*635a8641SAndroid Build Coastguard Worker   diskinfo->io = 0;
750*635a8641SAndroid Build Coastguard Worker   diskinfo->io_time = 0;
751*635a8641SAndroid Build Coastguard Worker   diskinfo->weighted_io_time = 0;
752*635a8641SAndroid Build Coastguard Worker 
753*635a8641SAndroid Build Coastguard Worker   uint64_t reads = 0;
754*635a8641SAndroid Build Coastguard Worker   uint64_t reads_merged = 0;
755*635a8641SAndroid Build Coastguard Worker   uint64_t sectors_read = 0;
756*635a8641SAndroid Build Coastguard Worker   uint64_t read_time = 0;
757*635a8641SAndroid Build Coastguard Worker   uint64_t writes = 0;
758*635a8641SAndroid Build Coastguard Worker   uint64_t writes_merged = 0;
759*635a8641SAndroid Build Coastguard Worker   uint64_t sectors_written = 0;
760*635a8641SAndroid Build Coastguard Worker   uint64_t write_time = 0;
761*635a8641SAndroid Build Coastguard Worker   uint64_t io = 0;
762*635a8641SAndroid Build Coastguard Worker   uint64_t io_time = 0;
763*635a8641SAndroid Build Coastguard Worker   uint64_t weighted_io_time = 0;
764*635a8641SAndroid Build Coastguard Worker 
765*635a8641SAndroid Build Coastguard Worker   for (const StringPiece& line : diskinfo_lines) {
766*635a8641SAndroid Build Coastguard Worker     std::vector<StringPiece> disk_fields = SplitStringPiece(
767*635a8641SAndroid Build Coastguard Worker         line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
768*635a8641SAndroid Build Coastguard Worker 
769*635a8641SAndroid Build Coastguard Worker     // Fields may have overflowed and reset to zero.
770*635a8641SAndroid Build Coastguard Worker     if (!IsValidDiskName(disk_fields[kDiskDriveName].as_string()))
771*635a8641SAndroid Build Coastguard Worker       continue;
772*635a8641SAndroid Build Coastguard Worker 
773*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskReads], &reads);
774*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
775*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
776*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskReadTime], &read_time);
777*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskWrites], &writes);
778*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
779*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
780*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskWriteTime], &write_time);
781*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskIO], &io);
782*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskIOTime], &io_time);
783*635a8641SAndroid Build Coastguard Worker     StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
784*635a8641SAndroid Build Coastguard Worker 
785*635a8641SAndroid Build Coastguard Worker     diskinfo->reads += reads;
786*635a8641SAndroid Build Coastguard Worker     diskinfo->reads_merged += reads_merged;
787*635a8641SAndroid Build Coastguard Worker     diskinfo->sectors_read += sectors_read;
788*635a8641SAndroid Build Coastguard Worker     diskinfo->read_time += read_time;
789*635a8641SAndroid Build Coastguard Worker     diskinfo->writes += writes;
790*635a8641SAndroid Build Coastguard Worker     diskinfo->writes_merged += writes_merged;
791*635a8641SAndroid Build Coastguard Worker     diskinfo->sectors_written += sectors_written;
792*635a8641SAndroid Build Coastguard Worker     diskinfo->write_time += write_time;
793*635a8641SAndroid Build Coastguard Worker     diskinfo->io += io;
794*635a8641SAndroid Build Coastguard Worker     diskinfo->io_time += io_time;
795*635a8641SAndroid Build Coastguard Worker     diskinfo->weighted_io_time += weighted_io_time;
796*635a8641SAndroid Build Coastguard Worker   }
797*635a8641SAndroid Build Coastguard Worker 
798*635a8641SAndroid Build Coastguard Worker   return true;
799*635a8641SAndroid Build Coastguard Worker }
800*635a8641SAndroid Build Coastguard Worker 
GetUserCpuTimeSinceBoot()801*635a8641SAndroid Build Coastguard Worker TimeDelta GetUserCpuTimeSinceBoot() {
802*635a8641SAndroid Build Coastguard Worker   return internal::GetUserCpuTimeSinceBoot();
803*635a8641SAndroid Build Coastguard Worker }
804*635a8641SAndroid Build Coastguard Worker 
805*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
ToValue() const806*635a8641SAndroid Build Coastguard Worker std::unique_ptr<Value> SwapInfo::ToValue() const {
807*635a8641SAndroid Build Coastguard Worker   auto res = std::make_unique<DictionaryValue>();
808*635a8641SAndroid Build Coastguard Worker 
809*635a8641SAndroid Build Coastguard Worker   // Write out uint64_t variables as doubles.
810*635a8641SAndroid Build Coastguard Worker   // Note: this may discard some precision, but for JS there's no other option.
811*635a8641SAndroid Build Coastguard Worker   res->SetDouble("num_reads", static_cast<double>(num_reads));
812*635a8641SAndroid Build Coastguard Worker   res->SetDouble("num_writes", static_cast<double>(num_writes));
813*635a8641SAndroid Build Coastguard Worker   res->SetDouble("orig_data_size", static_cast<double>(orig_data_size));
814*635a8641SAndroid Build Coastguard Worker   res->SetDouble("compr_data_size", static_cast<double>(compr_data_size));
815*635a8641SAndroid Build Coastguard Worker   res->SetDouble("mem_used_total", static_cast<double>(mem_used_total));
816*635a8641SAndroid Build Coastguard Worker   double ratio = compr_data_size ? static_cast<double>(orig_data_size) /
817*635a8641SAndroid Build Coastguard Worker                                        static_cast<double>(compr_data_size)
818*635a8641SAndroid Build Coastguard Worker                                  : 0;
819*635a8641SAndroid Build Coastguard Worker   res->SetDouble("compression_ratio", ratio);
820*635a8641SAndroid Build Coastguard Worker 
821*635a8641SAndroid Build Coastguard Worker   return std::move(res);
822*635a8641SAndroid Build Coastguard Worker }
823*635a8641SAndroid Build Coastguard Worker 
ParseZramMmStat(StringPiece mm_stat_data,SwapInfo * swap_info)824*635a8641SAndroid Build Coastguard Worker bool ParseZramMmStat(StringPiece mm_stat_data, SwapInfo* swap_info) {
825*635a8641SAndroid Build Coastguard Worker   // There are 7 columns in /sys/block/zram0/mm_stat,
826*635a8641SAndroid Build Coastguard Worker   // split by several spaces. The first three columns
827*635a8641SAndroid Build Coastguard Worker   // are orig_data_size, compr_data_size and mem_used_total.
828*635a8641SAndroid Build Coastguard Worker   // Example:
829*635a8641SAndroid Build Coastguard Worker   // 17715200 5008166 566062  0 1225715712  127 183842
830*635a8641SAndroid Build Coastguard Worker   //
831*635a8641SAndroid Build Coastguard Worker   // For more details:
832*635a8641SAndroid Build Coastguard Worker   // https://www.kernel.org/doc/Documentation/blockdev/zram.txt
833*635a8641SAndroid Build Coastguard Worker 
834*635a8641SAndroid Build Coastguard Worker   std::vector<StringPiece> tokens = SplitStringPiece(
835*635a8641SAndroid Build Coastguard Worker       mm_stat_data, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
836*635a8641SAndroid Build Coastguard Worker   if (tokens.size() < 7) {
837*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "zram mm_stat: tokens: " << tokens.size()
838*635a8641SAndroid Build Coastguard Worker                   << " malformed line: " << mm_stat_data.as_string();
839*635a8641SAndroid Build Coastguard Worker     return false;
840*635a8641SAndroid Build Coastguard Worker   }
841*635a8641SAndroid Build Coastguard Worker 
842*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(tokens[0], &swap_info->orig_data_size))
843*635a8641SAndroid Build Coastguard Worker     return false;
844*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(tokens[1], &swap_info->compr_data_size))
845*635a8641SAndroid Build Coastguard Worker     return false;
846*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(tokens[2], &swap_info->mem_used_total))
847*635a8641SAndroid Build Coastguard Worker     return false;
848*635a8641SAndroid Build Coastguard Worker 
849*635a8641SAndroid Build Coastguard Worker   return true;
850*635a8641SAndroid Build Coastguard Worker }
851*635a8641SAndroid Build Coastguard Worker 
ParseZramStat(StringPiece stat_data,SwapInfo * swap_info)852*635a8641SAndroid Build Coastguard Worker bool ParseZramStat(StringPiece stat_data, SwapInfo* swap_info) {
853*635a8641SAndroid Build Coastguard Worker   // There are 11 columns in /sys/block/zram0/stat,
854*635a8641SAndroid Build Coastguard Worker   // split by several spaces. The first column is read I/Os
855*635a8641SAndroid Build Coastguard Worker   // and fifth column is write I/Os.
856*635a8641SAndroid Build Coastguard Worker   // Example:
857*635a8641SAndroid Build Coastguard Worker   // 299    0    2392    0    1    0    8    0    0    0    0
858*635a8641SAndroid Build Coastguard Worker   //
859*635a8641SAndroid Build Coastguard Worker   // For more details:
860*635a8641SAndroid Build Coastguard Worker   // https://www.kernel.org/doc/Documentation/blockdev/zram.txt
861*635a8641SAndroid Build Coastguard Worker 
862*635a8641SAndroid Build Coastguard Worker   std::vector<StringPiece> tokens = SplitStringPiece(
863*635a8641SAndroid Build Coastguard Worker       stat_data, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
864*635a8641SAndroid Build Coastguard Worker   if (tokens.size() < 11) {
865*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "zram stat: tokens: " << tokens.size()
866*635a8641SAndroid Build Coastguard Worker                   << " malformed line: " << stat_data.as_string();
867*635a8641SAndroid Build Coastguard Worker     return false;
868*635a8641SAndroid Build Coastguard Worker   }
869*635a8641SAndroid Build Coastguard Worker 
870*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(tokens[0], &swap_info->num_reads))
871*635a8641SAndroid Build Coastguard Worker     return false;
872*635a8641SAndroid Build Coastguard Worker   if (!StringToUint64(tokens[4], &swap_info->num_writes))
873*635a8641SAndroid Build Coastguard Worker     return false;
874*635a8641SAndroid Build Coastguard Worker 
875*635a8641SAndroid Build Coastguard Worker   return true;
876*635a8641SAndroid Build Coastguard Worker }
877*635a8641SAndroid Build Coastguard Worker 
878*635a8641SAndroid Build Coastguard Worker namespace {
879*635a8641SAndroid Build Coastguard Worker 
IgnoreZramFirstPage(uint64_t orig_data_size,SwapInfo * swap_info)880*635a8641SAndroid Build Coastguard Worker bool IgnoreZramFirstPage(uint64_t orig_data_size, SwapInfo* swap_info) {
881*635a8641SAndroid Build Coastguard Worker   if (orig_data_size <= 4096) {
882*635a8641SAndroid Build Coastguard Worker     // A single page is compressed at startup, and has a high compression
883*635a8641SAndroid Build Coastguard Worker     // ratio. Ignore this as it doesn't indicate any real swapping.
884*635a8641SAndroid Build Coastguard Worker     swap_info->orig_data_size = 0;
885*635a8641SAndroid Build Coastguard Worker     swap_info->num_reads = 0;
886*635a8641SAndroid Build Coastguard Worker     swap_info->num_writes = 0;
887*635a8641SAndroid Build Coastguard Worker     swap_info->compr_data_size = 0;
888*635a8641SAndroid Build Coastguard Worker     swap_info->mem_used_total = 0;
889*635a8641SAndroid Build Coastguard Worker     return true;
890*635a8641SAndroid Build Coastguard Worker   }
891*635a8641SAndroid Build Coastguard Worker   return false;
892*635a8641SAndroid Build Coastguard Worker }
893*635a8641SAndroid Build Coastguard Worker 
ParseZramPath(SwapInfo * swap_info)894*635a8641SAndroid Build Coastguard Worker void ParseZramPath(SwapInfo* swap_info) {
895*635a8641SAndroid Build Coastguard Worker   FilePath zram_path("/sys/block/zram0");
896*635a8641SAndroid Build Coastguard Worker   uint64_t orig_data_size =
897*635a8641SAndroid Build Coastguard Worker       ReadFileToUint64(zram_path.Append("orig_data_size"));
898*635a8641SAndroid Build Coastguard Worker   if (IgnoreZramFirstPage(orig_data_size, swap_info))
899*635a8641SAndroid Build Coastguard Worker     return;
900*635a8641SAndroid Build Coastguard Worker 
901*635a8641SAndroid Build Coastguard Worker   swap_info->orig_data_size = orig_data_size;
902*635a8641SAndroid Build Coastguard Worker   swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
903*635a8641SAndroid Build Coastguard Worker   swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
904*635a8641SAndroid Build Coastguard Worker   swap_info->compr_data_size =
905*635a8641SAndroid Build Coastguard Worker       ReadFileToUint64(zram_path.Append("compr_data_size"));
906*635a8641SAndroid Build Coastguard Worker   swap_info->mem_used_total =
907*635a8641SAndroid Build Coastguard Worker       ReadFileToUint64(zram_path.Append("mem_used_total"));
908*635a8641SAndroid Build Coastguard Worker }
909*635a8641SAndroid Build Coastguard Worker 
GetSwapInfoImpl(SwapInfo * swap_info)910*635a8641SAndroid Build Coastguard Worker bool GetSwapInfoImpl(SwapInfo* swap_info) {
911*635a8641SAndroid Build Coastguard Worker   // Synchronously reading files in /sys/block/zram0 does not hit the disk.
912*635a8641SAndroid Build Coastguard Worker   ThreadRestrictions::ScopedAllowIO allow_io;
913*635a8641SAndroid Build Coastguard Worker 
914*635a8641SAndroid Build Coastguard Worker   // Since ZRAM update, it shows the usage data in different places.
915*635a8641SAndroid Build Coastguard Worker   // If file "/sys/block/zram0/mm_stat" exists, use the new way, otherwise,
916*635a8641SAndroid Build Coastguard Worker   // use the old way.
917*635a8641SAndroid Build Coastguard Worker   static Optional<bool> use_new_zram_interface;
918*635a8641SAndroid Build Coastguard Worker   FilePath zram_mm_stat_file("/sys/block/zram0/mm_stat");
919*635a8641SAndroid Build Coastguard Worker   if (!use_new_zram_interface.has_value()) {
920*635a8641SAndroid Build Coastguard Worker     use_new_zram_interface = PathExists(zram_mm_stat_file);
921*635a8641SAndroid Build Coastguard Worker   }
922*635a8641SAndroid Build Coastguard Worker 
923*635a8641SAndroid Build Coastguard Worker   if (!use_new_zram_interface.value()) {
924*635a8641SAndroid Build Coastguard Worker     ParseZramPath(swap_info);
925*635a8641SAndroid Build Coastguard Worker     return true;
926*635a8641SAndroid Build Coastguard Worker   }
927*635a8641SAndroid Build Coastguard Worker 
928*635a8641SAndroid Build Coastguard Worker   std::string mm_stat_data;
929*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(zram_mm_stat_file, &mm_stat_data)) {
930*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to open " << zram_mm_stat_file.value();
931*635a8641SAndroid Build Coastguard Worker     return false;
932*635a8641SAndroid Build Coastguard Worker   }
933*635a8641SAndroid Build Coastguard Worker   if (!ParseZramMmStat(mm_stat_data, swap_info)) {
934*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to parse " << zram_mm_stat_file.value();
935*635a8641SAndroid Build Coastguard Worker     return false;
936*635a8641SAndroid Build Coastguard Worker   }
937*635a8641SAndroid Build Coastguard Worker   if (IgnoreZramFirstPage(swap_info->orig_data_size, swap_info))
938*635a8641SAndroid Build Coastguard Worker     return true;
939*635a8641SAndroid Build Coastguard Worker 
940*635a8641SAndroid Build Coastguard Worker   FilePath zram_stat_file("/sys/block/zram0/stat");
941*635a8641SAndroid Build Coastguard Worker   std::string stat_data;
942*635a8641SAndroid Build Coastguard Worker   if (!ReadFileToString(zram_stat_file, &stat_data)) {
943*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to open " << zram_stat_file.value();
944*635a8641SAndroid Build Coastguard Worker     return false;
945*635a8641SAndroid Build Coastguard Worker   }
946*635a8641SAndroid Build Coastguard Worker   if (!ParseZramStat(stat_data, swap_info)) {
947*635a8641SAndroid Build Coastguard Worker     DLOG(WARNING) << "Failed to parse " << zram_stat_file.value();
948*635a8641SAndroid Build Coastguard Worker     return false;
949*635a8641SAndroid Build Coastguard Worker   }
950*635a8641SAndroid Build Coastguard Worker 
951*635a8641SAndroid Build Coastguard Worker   return true;
952*635a8641SAndroid Build Coastguard Worker }
953*635a8641SAndroid Build Coastguard Worker 
954*635a8641SAndroid Build Coastguard Worker }  // namespace
955*635a8641SAndroid Build Coastguard Worker 
GetSwapInfo(SwapInfo * swap_info)956*635a8641SAndroid Build Coastguard Worker bool GetSwapInfo(SwapInfo* swap_info) {
957*635a8641SAndroid Build Coastguard Worker   if (!GetSwapInfoImpl(swap_info)) {
958*635a8641SAndroid Build Coastguard Worker     *swap_info = SwapInfo();
959*635a8641SAndroid Build Coastguard Worker     return false;
960*635a8641SAndroid Build Coastguard Worker   }
961*635a8641SAndroid Build Coastguard Worker   return true;
962*635a8641SAndroid Build Coastguard Worker }
963*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
964*635a8641SAndroid Build Coastguard Worker 
965*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX) || defined(OS_AIX)
GetIdleWakeupsPerSecond()966*635a8641SAndroid Build Coastguard Worker int ProcessMetrics::GetIdleWakeupsPerSecond() {
967*635a8641SAndroid Build Coastguard Worker   uint64_t num_switches;
968*635a8641SAndroid Build Coastguard Worker   static const char kSwitchStat[] = "voluntary_ctxt_switches";
969*635a8641SAndroid Build Coastguard Worker   return ReadProcStatusAndGetFieldAsUint64(process_, kSwitchStat, &num_switches)
970*635a8641SAndroid Build Coastguard Worker              ? CalculateIdleWakeupsPerSecond(num_switches)
971*635a8641SAndroid Build Coastguard Worker              : 0;
972*635a8641SAndroid Build Coastguard Worker }
973*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_LINUX) || defined(OS_AIX)
974*635a8641SAndroid Build Coastguard Worker 
975*635a8641SAndroid Build Coastguard Worker }  // namespace base
976