Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / platform / win_platform_backend.py
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
5 import collections
6 import contextlib
7 import ctypes
8 import platform
9 import re
10 import subprocess
11 import time
12
13 from telemetry import decorators
14 from telemetry.core import exceptions
15 from telemetry.core.platform import desktop_platform_backend
16 from telemetry.core.platform import platform_backend
17 from telemetry.core.platform.power_monitor import ippet_power_monitor
18
19 try:
20   import pywintypes  # pylint: disable=F0401
21   import win32api  # pylint: disable=F0401
22   from win32com.shell import shell  # pylint: disable=F0401
23   from win32com.shell import shellcon  # pylint: disable=F0401
24   import win32con  # pylint: disable=F0401
25   import win32process  # pylint: disable=F0401
26   import win32security  # pylint: disable=F0401
27 except ImportError:
28   pywintypes = None
29   shell = None
30   shellcon = None
31   win32api = None
32   win32con = None
33   win32process = None
34   win32security = None
35
36
37
38 def IsCurrentProcessElevated():
39   handle = win32process.GetCurrentProcess()
40   with contextlib.closing(
41       win32security.OpenProcessToken(handle, win32con.TOKEN_QUERY)) as token:
42     return bool(
43         win32security.GetTokenInformation(token, win32security.TokenElevation))
44
45
46 class WinPlatformBackend(desktop_platform_backend.DesktopPlatformBackend):
47   def __init__(self):
48     super(WinPlatformBackend, self).__init__()
49     self._power_monitor = ippet_power_monitor.IppetPowerMonitor(self)
50
51   # pylint: disable=W0613
52   def StartRawDisplayFrameRateMeasurement(self):
53     raise NotImplementedError()
54
55   def StopRawDisplayFrameRateMeasurement(self):
56     raise NotImplementedError()
57
58   def GetRawDisplayFrameRateMeasurements(self):
59     raise NotImplementedError()
60
61   def IsThermallyThrottled(self):
62     raise NotImplementedError()
63
64   def HasBeenThermallyThrottled(self):
65     raise NotImplementedError()
66
67   def GetSystemCommitCharge(self):
68     performance_info = self._GetPerformanceInfo()
69     return performance_info.CommitTotal * performance_info.PageSize / 1024
70
71   @decorators.Cache
72   def GetSystemTotalPhysicalMemory(self):
73     performance_info = self._GetPerformanceInfo()
74     return performance_info.PhysicalTotal * performance_info.PageSize / 1024
75
76   def GetCpuStats(self, pid):
77     cpu_info = self._GetWin32ProcessInfo(win32process.GetProcessTimes, pid)
78     # Convert 100 nanosecond units to seconds
79     cpu_time = (cpu_info['UserTime'] / 1e7 +
80                 cpu_info['KernelTime'] / 1e7)
81     return {'CpuProcessTime': cpu_time}
82
83   def GetCpuTimestamp(self):
84     """Return current timestamp in seconds."""
85     return {'TotalTime': time.time()}
86
87   def GetMemoryStats(self, pid):
88     memory_info = self._GetWin32ProcessInfo(
89         win32process.GetProcessMemoryInfo, pid)
90     return {'VM': memory_info['PagefileUsage'],
91             'VMPeak': memory_info['PeakPagefileUsage'],
92             'WorkingSetSize': memory_info['WorkingSetSize'],
93             'WorkingSetSizePeak': memory_info['PeakWorkingSetSize']}
94
95   def GetIOStats(self, pid):
96     io_stats = self._GetWin32ProcessInfo(win32process.GetProcessIoCounters, pid)
97     return {'ReadOperationCount': io_stats['ReadOperationCount'],
98             'WriteOperationCount': io_stats['WriteOperationCount'],
99             'ReadTransferCount': io_stats['ReadTransferCount'],
100             'WriteTransferCount': io_stats['WriteTransferCount']}
101
102   def KillProcess(self, pid, kill_process_tree=False):
103     # os.kill for Windows is Python 2.7.
104     cmd = ['taskkill', '/F', '/PID', str(pid)]
105     if kill_process_tree:
106       cmd.append('/T')
107     subprocess.Popen(cmd, stdout=subprocess.PIPE,
108                      stderr=subprocess.STDOUT).communicate()
109
110   def GetSystemProcessInfo(self):
111     # [3:] To skip 2 blank lines and header.
112     lines = subprocess.Popen(
113         ['wmic', 'process', 'get',
114          'CommandLine,CreationDate,Name,ParentProcessId,ProcessId',
115          '/format:csv'],
116         stdout=subprocess.PIPE).communicate()[0].splitlines()[3:]
117     process_info = []
118     for line in lines:
119       if not line:
120         continue
121       parts = line.split(',')
122       pi = {}
123       pi['ProcessId'] = int(parts[-1])
124       pi['ParentProcessId'] = int(parts[-2])
125       pi['Name'] = parts[-3]
126       creation_date = None
127       if parts[-4]:
128         creation_date = float(re.split('[+-]', parts[-4])[0])
129       pi['CreationDate'] = creation_date
130       pi['CommandLine'] = ','.join(parts[1:-4])
131       process_info.append(pi)
132     return process_info
133
134   def GetChildPids(self, pid):
135     """Retunds a list of child pids of |pid|."""
136     ppid_map = collections.defaultdict(list)
137     creation_map = {}
138     for pi in self.GetSystemProcessInfo():
139       ppid_map[pi['ParentProcessId']].append(pi['ProcessId'])
140       if pi['CreationDate']:
141         creation_map[pi['ProcessId']] = pi['CreationDate']
142
143     def _InnerGetChildPids(pid):
144       if not pid or pid not in ppid_map:
145         return []
146       ret = [p for p in ppid_map[pid] if creation_map[p] >= creation_map[pid]]
147       for child in ret:
148         if child == pid:
149           continue
150         ret.extend(_InnerGetChildPids(child))
151       return ret
152
153     return _InnerGetChildPids(pid)
154
155   def GetCommandLine(self, pid):
156     for pi in self.GetSystemProcessInfo():
157       if pid == pi['ProcessId']:
158         return pi['CommandLine']
159     raise exceptions.ProcessGoneException()
160
161   def GetOSName(self):
162     return 'win'
163
164   @decorators.Cache
165   def GetOSVersionName(self):
166     os_version = platform.uname()[3]
167
168     if os_version.startswith('5.1.'):
169       return platform_backend.XP
170     if os_version.startswith('6.0.'):
171       return platform_backend.VISTA
172     if os_version.startswith('6.1.'):
173       return platform_backend.WIN7
174     if os_version.startswith('6.2.'):
175       return platform_backend.WIN8
176
177     raise NotImplementedError('Unknown win version %s.' % os_version)
178
179   def CanFlushIndividualFilesFromSystemCache(self):
180     return True
181
182   def _GetWin32ProcessInfo(self, func, pid):
183     mask = (win32con.PROCESS_QUERY_INFORMATION |
184             win32con.PROCESS_VM_READ)
185     handle = None
186     try:
187       handle = win32api.OpenProcess(mask, False, pid)
188       return func(handle)
189     except pywintypes.error, e:
190       errcode = e[0]
191       if errcode == 87:
192         raise exceptions.ProcessGoneException()
193       raise
194     finally:
195       if handle:
196         win32api.CloseHandle(handle)
197
198   def _GetPerformanceInfo(self):
199     class PerformanceInfo(ctypes.Structure):
200       """Struct for GetPerformanceInfo() call
201       http://msdn.microsoft.com/en-us/library/ms683210
202       """
203       _fields_ = [('size', ctypes.c_ulong),
204                   ('CommitTotal', ctypes.c_size_t),
205                   ('CommitLimit', ctypes.c_size_t),
206                   ('CommitPeak', ctypes.c_size_t),
207                   ('PhysicalTotal', ctypes.c_size_t),
208                   ('PhysicalAvailable', ctypes.c_size_t),
209                   ('SystemCache', ctypes.c_size_t),
210                   ('KernelTotal', ctypes.c_size_t),
211                   ('KernelPaged', ctypes.c_size_t),
212                   ('KernelNonpaged', ctypes.c_size_t),
213                   ('PageSize', ctypes.c_size_t),
214                   ('HandleCount', ctypes.c_ulong),
215                   ('ProcessCount', ctypes.c_ulong),
216                   ('ThreadCount', ctypes.c_ulong)]
217
218       def __init__(self):
219         self.size = ctypes.sizeof(self)
220         super(PerformanceInfo, self).__init__()
221
222     performance_info = PerformanceInfo()
223     ctypes.windll.psapi.GetPerformanceInfo(
224         ctypes.byref(performance_info), performance_info.size)
225     return performance_info
226
227   def LaunchApplication(
228       self, application, parameters=None, elevate_privilege=False):
229     """Launch an application. Returns a PyHANDLE object."""
230
231     parameters = ' '.join(parameters) if parameters else ''
232     if elevate_privilege and not IsCurrentProcessElevated():
233       # Use ShellExecuteEx() instead of subprocess.Popen()/CreateProcess() to
234       # elevate privileges. A new console will be created if the new process has
235       # different permissions than this process.
236       proc_info = shell.ShellExecuteEx(
237           fMask=shellcon.SEE_MASK_NOCLOSEPROCESS | shellcon.SEE_MASK_NO_CONSOLE,
238           lpVerb='runas' if elevate_privilege else '',
239           lpFile=application,
240           lpParameters=parameters,
241           nShow=win32con.SW_HIDE)
242       if proc_info['hInstApp'] <= 32:
243         raise Exception('Unable to launch %s' % application)
244       return proc_info['hProcess']
245     else:
246       handle, _, _, _ = win32process.CreateProcess(
247           None, application + ' ' + parameters, None, None, False,
248           win32process.CREATE_NO_WINDOW, None, None, win32process.STARTUPINFO())
249       return handle
250
251   def CanMonitorPower(self):
252     return self._power_monitor.CanMonitorPower()
253
254   def CanMeasurePerApplicationPower(self):
255     return self._power_monitor.CanMeasurePerApplicationPower()
256
257   def StartMonitoringPower(self, browser):
258     self._power_monitor.StartMonitoringPower(browser)
259
260   def StopMonitoringPower(self):
261     return self._power_monitor.StopMonitoringPower()