1 # Copyright (c) 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.
12 import pywintypes # pylint: disable=F0401
13 import win32api # pylint: disable=F0401
14 import win32con # pylint: disable=F0401
15 import win32process # pylint: disable=F0401
22 from telemetry import decorators
23 from telemetry.core import exceptions
24 from telemetry.core.platform import desktop_platform_backend
25 from telemetry.core.platform import platform_backend
28 class WinPlatformBackend(desktop_platform_backend.DesktopPlatformBackend):
29 # pylint: disable=W0613
30 def StartRawDisplayFrameRateMeasurement(self):
31 raise NotImplementedError()
33 def StopRawDisplayFrameRateMeasurement(self):
34 raise NotImplementedError()
36 def GetRawDisplayFrameRateMeasurements(self):
37 raise NotImplementedError()
39 def IsThermallyThrottled(self):
40 raise NotImplementedError()
42 def HasBeenThermallyThrottled(self):
43 raise NotImplementedError()
45 def GetSystemCommitCharge(self):
46 performance_info = self._GetPerformanceInfo()
47 return performance_info.CommitTotal * performance_info.PageSize / 1024
50 def GetSystemTotalPhysicalMemory(self):
51 performance_info = self._GetPerformanceInfo()
52 return performance_info.PhysicalTotal * performance_info.PageSize / 1024
54 def GetCpuStats(self, pid):
55 cpu_info = self._GetWin32ProcessInfo(win32process.GetProcessTimes, pid)
56 # Convert 100 nanosecond units to seconds
57 cpu_time = (cpu_info['UserTime'] / 1e7 +
58 cpu_info['KernelTime'] / 1e7)
59 return {'CpuProcessTime': cpu_time}
61 def GetCpuTimestamp(self):
62 """Return current timestamp in seconds."""
63 return {'TotalTime': time.time()}
65 def GetMemoryStats(self, pid):
66 memory_info = self._GetWin32ProcessInfo(
67 win32process.GetProcessMemoryInfo, pid)
68 return {'VM': memory_info['PagefileUsage'],
69 'VMPeak': memory_info['PeakPagefileUsage'],
70 'WorkingSetSize': memory_info['WorkingSetSize'],
71 'WorkingSetSizePeak': memory_info['PeakWorkingSetSize']}
73 def GetIOStats(self, pid):
74 io_stats = self._GetWin32ProcessInfo(win32process.GetProcessIoCounters, pid)
75 return {'ReadOperationCount': io_stats['ReadOperationCount'],
76 'WriteOperationCount': io_stats['WriteOperationCount'],
77 'ReadTransferCount': io_stats['ReadTransferCount'],
78 'WriteTransferCount': io_stats['WriteTransferCount']}
80 def KillProcess(self, pid, kill_process_tree=False):
81 # os.kill for Windows is Python 2.7.
82 cmd = ['taskkill', '/F', '/PID', str(pid)]
85 subprocess.Popen(cmd, stdout=subprocess.PIPE,
86 stderr=subprocess.STDOUT).wait()
88 def GetSystemProcessInfo(self):
89 # [3:] To skip 2 blank lines and header.
90 lines = subprocess.Popen(
91 ['wmic', 'process', 'get',
92 'CommandLine,CreationDate,Name,ParentProcessId,ProcessId',
94 stdout=subprocess.PIPE).communicate()[0].splitlines()[3:]
99 parts = line.split(',')
101 pi['ProcessId'] = int(parts[-1])
102 pi['ParentProcessId'] = int(parts[-2])
103 pi['Name'] = parts[-3]
106 creation_date = float(re.split('[+-]', parts[-4])[0])
107 pi['CreationDate'] = creation_date
108 pi['CommandLine'] = ','.join(parts[1:-4])
109 process_info.append(pi)
112 def GetChildPids(self, pid):
113 """Retunds a list of child pids of |pid|."""
114 ppid_map = collections.defaultdict(list)
116 for pi in self.GetSystemProcessInfo():
117 ppid_map[pi['ParentProcessId']].append(pi['ProcessId'])
118 if pi['CreationDate']:
119 creation_map[pi['ProcessId']] = pi['CreationDate']
121 def _InnerGetChildPids(pid):
122 if not pid or pid not in ppid_map:
124 ret = [p for p in ppid_map[pid] if creation_map[p] >= creation_map[pid]]
128 ret.extend(_InnerGetChildPids(child))
131 return _InnerGetChildPids(pid)
133 def GetCommandLine(self, pid):
134 for pi in self.GetSystemProcessInfo():
135 if pid == pi['ProcessId']:
136 return pi['CommandLine']
137 raise exceptions.ProcessGoneException()
143 def GetOSVersionName(self):
144 os_version = platform.uname()[3]
146 if os_version.startswith('5.1.'):
147 return platform_backend.OSVersion('xp', 5.1)
148 if os_version.startswith('6.0.'):
149 return platform_backend.OSVersion('vista', 6.0)
150 if os_version.startswith('6.1.'):
151 return platform_backend.OSVersion('win7', 6.1)
152 if os_version.startswith('6.2.'):
153 return platform_backend.OSVersion('win8', 6.2)
155 raise NotImplementedError('Unknown win version %s.' % os_version)
157 def CanFlushIndividualFilesFromSystemCache(self):
160 def GetFlushUtilityName(self):
161 return 'clear_system_cache.exe'
163 def _GetWin32ProcessInfo(self, func, pid):
164 mask = (win32con.PROCESS_QUERY_INFORMATION |
165 win32con.PROCESS_VM_READ)
168 handle = win32api.OpenProcess(mask, False, pid)
170 except pywintypes.error, e:
173 raise exceptions.ProcessGoneException()
177 win32api.CloseHandle(handle)
179 def _GetPerformanceInfo(self):
180 class PerformanceInfo(ctypes.Structure):
181 """Struct for GetPerformanceInfo() call
182 http://msdn.microsoft.com/en-us/library/ms683210
184 _fields_ = [('size', ctypes.c_ulong),
185 ('CommitTotal', ctypes.c_size_t),
186 ('CommitLimit', ctypes.c_size_t),
187 ('CommitPeak', ctypes.c_size_t),
188 ('PhysicalTotal', ctypes.c_size_t),
189 ('PhysicalAvailable', ctypes.c_size_t),
190 ('SystemCache', ctypes.c_size_t),
191 ('KernelTotal', ctypes.c_size_t),
192 ('KernelPaged', ctypes.c_size_t),
193 ('KernelNonpaged', ctypes.c_size_t),
194 ('PageSize', ctypes.c_size_t),
195 ('HandleCount', ctypes.c_ulong),
196 ('ProcessCount', ctypes.c_ulong),
197 ('ThreadCount', ctypes.c_ulong)]
200 self.size = ctypes.sizeof(self)
201 super(PerformanceInfo, self).__init__()
203 performance_info = PerformanceInfo()
204 ctypes.windll.psapi.GetPerformanceInfo(
205 ctypes.byref(performance_info), performance_info.size)
206 return performance_info