• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5try:
6  import resource  # pylint: disable=F0401
7except ImportError:
8  resource = None  # Not available on all platforms
9
10from telemetry import decorators
11from telemetry.core import exceptions
12from telemetry.core.platform import platform_backend
13
14
15class LinuxBasedPlatformBackend(platform_backend.PlatformBackend):
16
17  """Abstract platform containing functionality shared by all linux based OSes.
18
19  Subclasses must implement RunCommand, GetFileContents, GetPsOutput, and
20  ParseCStateSample."""
21
22  def GetSystemCommitCharge(self):
23    meminfo_contents = self.GetFileContents('/proc/meminfo')
24    meminfo = self._GetProcFileDict(meminfo_contents)
25    if not meminfo:
26      return None
27    return (self._ConvertKbToByte(meminfo['MemTotal'])
28            - self._ConvertKbToByte(meminfo['MemFree'])
29            - self._ConvertKbToByte(meminfo['Buffers'])
30            - self._ConvertKbToByte(meminfo['Cached']))
31
32  @decorators.Cache
33  def GetSystemTotalPhysicalMemory(self):
34    meminfo_contents = self.GetFileContents('/proc/meminfo')
35    meminfo = self._GetProcFileDict(meminfo_contents)
36    if not meminfo:
37      return None
38    return self._ConvertKbToByte(meminfo['MemTotal'])
39
40  def GetCpuStats(self, pid):
41    stats = self._GetProcFileForPid(pid, 'stat')
42    if not stats:
43      return {}
44    stats = stats.split()
45    utime = float(stats[13])
46    stime = float(stats[14])
47    cpu_process_jiffies = utime + stime
48    return {'CpuProcessTime': cpu_process_jiffies}
49
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}
54
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']:
60      return {}
61    vm = int(stats[22])
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)
67
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())
72
73    return {'VM': vm,
74            'VMPeak': vm_peak,
75            'PrivateDirty': private_dirty_bytes,
76            'WorkingSetSize': wss,
77            'WorkingSetSizePeak': wss_peak}
78
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'])}
86
87  def GetFileContents(self, filename):
88    raise NotImplementedError()
89
90  def GetPsOutput(self, columns, pid=None):
91    raise NotImplementedError()
92
93  def RunCommand(self, cmd):
94    raise NotImplementedError()
95
96  @staticmethod
97  def ParseCStateSample(sample):
98    """Parse a single c-state residency sample.
99
100    Args:
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'}
106
107    Returns:
108        Dictionary associating a c-state with a time.
109    """
110    raise NotImplementedError()
111
112  def _IsPidAlive(self, pid):
113    assert pid, 'pid is required'
114    return bool(self.GetPsOutput(['pid'], pid) == str(pid))
115
116  def _GetProcFileForPid(self, pid, filename):
117    try:
118      return self.GetFileContents('/proc/%s/%s' % (pid, filename))
119    except IOError:
120      if not self._IsPidAlive(pid):
121        raise exceptions.ProcessGoneException()
122      raise
123
124  def _ConvertKbToByte(self, value):
125    return int(value.replace('kB','')) * 1024
126
127  def _GetProcFileDict(self, contents):
128    retval = {}
129    for line in contents.splitlines():
130      key, value = line.split(':')
131      retval[key.strip()] = value.strip()
132    return retval
133
134  def _GetProcJiffies(self, timer_list):
135    """Parse '/proc/timer_list' output and returns the first jiffies attribute.
136
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(':')
144        return value
145    raise Exception('Unable to find jiffies from /proc/timer_list')
146