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 ProcSupportingPlatformBackend(platform_backend.PlatformBackend): 16 17 """Represents a platform that supports /proc. 18 19 Subclasses must implement _GetFileContents and _GetPsOutput.""" 20 21 def GetSystemCommitCharge(self): 22 meminfo_contents = self._GetFileContents('/proc/meminfo') 23 meminfo = self._GetProcFileDict(meminfo_contents) 24 return (self._ConvertKbToByte(meminfo['MemTotal']) 25 - self._ConvertKbToByte(meminfo['MemFree']) 26 - self._ConvertKbToByte(meminfo['Buffers']) 27 - self._ConvertKbToByte(meminfo['Cached'])) 28 29 @decorators.Cache 30 def GetSystemTotalPhysicalMemory(self): 31 meminfo_contents = self._GetFileContents('/proc/meminfo') 32 meminfo = self._GetProcFileDict(meminfo_contents) 33 return self._ConvertKbToByte(meminfo['MemTotal']) 34 35 def GetCpuStats(self, pid): 36 stats = self._GetProcFileForPid(pid, 'stat') 37 if not stats: 38 return {} 39 stats = stats.split() 40 utime = float(stats[13]) 41 stime = float(stats[14]) 42 cpu_process_jiffies = utime + stime 43 return {'CpuProcessTime': cpu_process_jiffies} 44 45 def GetCpuTimestamp(self): 46 timer_list = self._GetFileContents('/proc/timer_list') 47 total_jiffies = float(self._GetProcJiffies(timer_list)) 48 return {'TotalTime': total_jiffies} 49 50 def GetMemoryStats(self, pid): 51 status_contents = self._GetProcFileForPid(pid, 'status') 52 stats = self._GetProcFileForPid(pid, 'stat').split() 53 status = self._GetProcFileDict(status_contents) 54 if not status or not stats or 'Z' in status['State']: 55 return {} 56 vm = int(stats[22]) 57 vm_peak = (self._ConvertKbToByte(status['VmPeak']) 58 if 'VmPeak' in status else vm) 59 wss = int(stats[23]) * resource.getpagesize() 60 wss_peak = (self._ConvertKbToByte(status['VmHWM']) 61 if 'VmHWM' in status else wss) 62 63 private_dirty_bytes = 0 64 for line in self._GetProcFileForPid(pid, 'smaps').splitlines(): 65 if line.startswith('Private_Dirty:'): 66 private_dirty_bytes += self._ConvertKbToByte(line.split(':')[1].strip()) 67 68 return {'VM': vm, 69 'VMPeak': vm_peak, 70 'PrivateDirty': private_dirty_bytes, 71 'WorkingSetSize': wss, 72 'WorkingSetSizePeak': wss_peak} 73 74 def GetIOStats(self, pid): 75 io_contents = self._GetProcFileForPid(pid, 'io') 76 io = self._GetProcFileDict(io_contents) 77 return {'ReadOperationCount': int(io['syscr']), 78 'WriteOperationCount': int(io['syscw']), 79 'ReadTransferCount': int(io['rchar']), 80 'WriteTransferCount': int(io['wchar'])} 81 82 def _GetFileContents(self, filename): 83 raise NotImplementedError() 84 85 def _GetPsOutput(self, columns, pid=None): 86 raise NotImplementedError() 87 88 def _IsPidAlive(self, pid): 89 assert pid, 'pid is required' 90 return bool(self._GetPsOutput(['pid'], pid) == str(pid)) 91 92 def _GetProcFileForPid(self, pid, filename): 93 try: 94 return self._GetFileContents('/proc/%s/%s' % (pid, filename)) 95 except IOError: 96 if not self._IsPidAlive(pid): 97 raise exceptions.ProcessGoneException() 98 raise 99 100 def _ConvertKbToByte(self, value): 101 return int(value.replace('kB','')) * 1024 102 103 def _GetProcFileDict(self, contents): 104 retval = {} 105 for line in contents.splitlines(): 106 key, value = line.split(':') 107 retval[key.strip()] = value.strip() 108 return retval 109 110 def _GetProcJiffies(self, timer_list): 111 """Parse '/proc/timer_list' output and returns the first jiffies attribute. 112 113 Multi-CPU machines will have multiple 'jiffies:' lines, all of which will be 114 essentially the same. Return the first one.""" 115 if isinstance(timer_list, str): 116 timer_list = timer_list.splitlines() 117 for line in timer_list: 118 if line.startswith('jiffies:'): 119 _, value = line.split(':') 120 return value 121 raise Exception('Unable to find jiffies from /proc/timer_list') 122