1 # Copyright 2013 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.
6 import resource # pylint: disable=F0401
8 resource = None # Not available on all platforms
10 from telemetry import decorators
11 from telemetry.core import exceptions
12 from telemetry.core.platform import platform_backend
15 class LinuxBasedPlatformBackend(platform_backend.PlatformBackend):
17 """Abstract platform containing functionality shared by all linux based OSes.
19 Subclasses must implement RunCommand, GetFileContents, GetPsOutput, and
22 def GetSystemCommitCharge(self):
23 meminfo_contents = self.GetFileContents('/proc/meminfo')
24 meminfo = self._GetProcFileDict(meminfo_contents)
27 return (self._ConvertKbToByte(meminfo['MemTotal'])
28 - self._ConvertKbToByte(meminfo['MemFree'])
29 - self._ConvertKbToByte(meminfo['Buffers'])
30 - self._ConvertKbToByte(meminfo['Cached']))
33 def GetSystemTotalPhysicalMemory(self):
34 meminfo_contents = self.GetFileContents('/proc/meminfo')
35 meminfo = self._GetProcFileDict(meminfo_contents)
38 return self._ConvertKbToByte(meminfo['MemTotal'])
40 def GetCpuStats(self, pid):
41 stats = self._GetProcFileForPid(pid, 'stat')
45 utime = float(stats[13])
46 stime = float(stats[14])
47 cpu_process_jiffies = utime + stime
48 return {'CpuProcessTime': cpu_process_jiffies}
50 def GetCpuTimestamp(self):
51 timer_list = self.GetFileContents('/proc/timer_list')
52 total_jiffies = float(self._GetProcJiffies(timer_list))
53 return {'TotalTime': total_jiffies}
55 def GetMemoryStats(self, pid):
56 status_contents = self._GetProcFileForPid(pid, 'status')
57 stats = self._GetProcFileForPid(pid, 'stat').split()
58 status = self._GetProcFileDict(status_contents)
59 if not status or not stats or 'Z' in status['State']:
62 vm_peak = (self._ConvertKbToByte(status['VmPeak'])
63 if 'VmPeak' in status else vm)
64 wss = int(stats[23]) * resource.getpagesize()
65 wss_peak = (self._ConvertKbToByte(status['VmHWM'])
66 if 'VmHWM' in status else wss)
68 private_dirty_bytes = 0
69 for line in self._GetProcFileForPid(pid, 'smaps').splitlines():
70 if line.startswith('Private_Dirty:'):
71 private_dirty_bytes += self._ConvertKbToByte(line.split(':')[1].strip())
75 'PrivateDirty': private_dirty_bytes,
76 'WorkingSetSize': wss,
77 'WorkingSetSizePeak': wss_peak}
79 def GetIOStats(self, pid):
80 io_contents = self._GetProcFileForPid(pid, 'io')
81 io = self._GetProcFileDict(io_contents)
82 return {'ReadOperationCount': int(io['syscr']),
83 'WriteOperationCount': int(io['syscw']),
84 'ReadTransferCount': int(io['rchar']),
85 'WriteTransferCount': int(io['wchar'])}
87 def GetFileContents(self, filename):
88 raise NotImplementedError()
90 def GetPsOutput(self, columns, pid=None):
91 raise NotImplementedError()
93 def RunCommand(self, cmd):
94 raise NotImplementedError()
97 def ParseCStateSample(sample):
98 """Parse a single c-state residency sample.
101 sample: A sample of c-state residency times to be parsed. Organized as
102 a dictionary mapping CPU name to a string containing all c-state
103 names, the times in each state, the latency of each state, and the
104 time at which the sample was taken all separated by newlines.
105 Ex: {'cpu0': 'C0\nC1\n5000\n2000\n20\n30\n1406673171'}
108 Dictionary associating a c-state with a time.
110 raise NotImplementedError()
112 def _IsPidAlive(self, pid):
113 assert pid, 'pid is required'
114 return bool(self.GetPsOutput(['pid'], pid) == str(pid))
116 def _GetProcFileForPid(self, pid, filename):
118 return self.GetFileContents('/proc/%s/%s' % (pid, filename))
120 if not self._IsPidAlive(pid):
121 raise exceptions.ProcessGoneException()
124 def _ConvertKbToByte(self, value):
125 return int(value.replace('kB','')) * 1024
127 def _GetProcFileDict(self, contents):
129 for line in contents.splitlines():
130 key, value = line.split(':')
131 retval[key.strip()] = value.strip()
134 def _GetProcJiffies(self, timer_list):
135 """Parse '/proc/timer_list' output and returns the first jiffies attribute.
137 Multi-CPU machines will have multiple 'jiffies:' lines, all of which will be
138 essentially the same. Return the first one."""
139 if isinstance(timer_list, str):
140 timer_list = timer_list.splitlines()
141 for line in timer_list:
142 if line.startswith('jiffies:'):
143 _, value = line.split(':')
145 raise Exception('Unable to find jiffies from /proc/timer_list')