blob: 9a514e74b7c31424aea14445f65a93b697195e0f [file] [log] [blame]
Greg Clayton52e63782013-03-23 01:44:48 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
4# Be sure to add the python path that points to the LLDB shared library.
5# On MacOSX csh, tcsh:
6# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
7# On MacOSX sh, bash:
8# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
9#----------------------------------------------------------------------
10
Serge Guelton525cd592019-03-21 18:27:40 +000011from __future__ import print_function
12
Greg Clayton52e63782013-03-23 01:44:48 +000013import optparse
14import os
15import platform
Greg Clayton2d95f352013-03-26 21:00:29 +000016import re
Greg Clayton52e63782013-03-23 01:44:48 +000017import resource
18import sys
19import time
Greg Clayton7b619fc2013-04-03 22:59:27 +000020import types
Greg Clayton52e63782013-03-23 01:44:48 +000021
Serge Guelton1a12dd72019-03-26 14:46:15 +000022if sys.version_info.major == 2:
23 import commands as subprocess
24else:
25 import subprocess
26
Greg Clayton52e63782013-03-23 01:44:48 +000027#----------------------------------------------------------------------
28# Code that auto imports LLDB
29#----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000030try:
Greg Clayton52e63782013-03-23 01:44:48 +000031 # Just try for LLDB in case PYTHONPATH is already correctly setup
32 import lldb
33except ImportError:
34 lldb_python_dirs = list()
35 # lldb is not in the PYTHONPATH, try some defaults for the current platform
36 platform_system = platform.system()
37 if platform_system == 'Darwin':
38 # On Darwin, try the currently selected Xcode directory
Serge Guelton1a12dd72019-03-26 14:46:15 +000039 xcode_dir = subprocess.getoutput("xcode-select --print-path")
Greg Clayton52e63782013-03-23 01:44:48 +000040 if xcode_dir:
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 lldb_python_dirs.append(
42 os.path.realpath(
43 xcode_dir +
44 '/../SharedFrameworks/LLDB.framework/Resources/Python'))
45 lldb_python_dirs.append(
46 xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
47 lldb_python_dirs.append(
48 '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
Greg Clayton52e63782013-03-23 01:44:48 +000049 success = False
50 for lldb_python_dir in lldb_python_dirs:
51 if os.path.exists(lldb_python_dir):
52 if not (sys.path.__contains__(lldb_python_dir)):
53 sys.path.append(lldb_python_dir)
Kate Stoneb9c1b512016-09-06 20:57:50 +000054 try:
Greg Clayton52e63782013-03-23 01:44:48 +000055 import lldb
56 except ImportError:
57 pass
58 else:
Serge Guelton525cd592019-03-21 18:27:40 +000059 print('imported lldb from: "%s"' % (lldb_python_dir))
Greg Clayton52e63782013-03-23 01:44:48 +000060 success = True
61 break
62 if not success:
Serge Guelton525cd592019-03-21 18:27:40 +000063 print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly")
Greg Clayton52e63782013-03-23 01:44:48 +000064 sys.exit(1)
65
66
Kate Stoneb9c1b512016-09-06 20:57:50 +000067class Timer:
68
Greg Clayton52e63782013-03-23 01:44:48 +000069 def __enter__(self):
70 self.start = time.clock()
71 return self
72
73 def __exit__(self, *args):
74 self.end = time.clock()
75 self.interval = self.end - self.start
76
Kate Stoneb9c1b512016-09-06 20:57:50 +000077
Greg Clayton7b619fc2013-04-03 22:59:27 +000078class Action(object):
79 """Class that encapsulates actions to take when a thread stops for a reason."""
Kate Stoneb9c1b512016-09-06 20:57:50 +000080
81 def __init__(self, callback=None, callback_owner=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +000082 self.callback = callback
83 self.callback_owner = callback_owner
Kate Stoneb9c1b512016-09-06 20:57:50 +000084
85 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +000086 assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
87
Kate Stoneb9c1b512016-09-06 20:57:50 +000088
Greg Clayton7b619fc2013-04-03 22:59:27 +000089class PlanCompleteAction (Action):
Kate Stoneb9c1b512016-09-06 20:57:50 +000090
91 def __init__(self, callback=None, callback_owner=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +000092 Action.__init__(self, callback, callback_owner)
Kate Stoneb9c1b512016-09-06 20:57:50 +000093
94 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +000095 if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
96 if self.callback:
97 if self.callback_owner:
Kate Stoneb9c1b512016-09-06 20:57:50 +000098 self.callback(self.callback_owner, thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +000099 else:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100 self.callback(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000101 return True
102 return False
103
104
105class BreakpointAction (Action):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106
107 def __init__(
108 self,
109 callback=None,
110 callback_owner=None,
111 name=None,
112 module=None,
113 file=None,
114 line=None,
115 breakpoint=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000116 Action.__init__(self, callback, callback_owner)
117 self.modules = lldb.SBFileSpecList()
118 self.files = lldb.SBFileSpecList()
119 self.breakpoints = list()
120 # "module" can be a list or a string
121 if breakpoint:
122 self.breakpoints.append(breakpoint)
123 else:
124 if module:
125 if isinstance(module, types.ListType):
126 for module_path in module:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127 self.modules.Append(
128 lldb.SBFileSpec(module_path, False))
Greg Clayton7b619fc2013-04-03 22:59:27 +0000129 elif isinstance(module, types.StringTypes):
130 self.modules.Append(lldb.SBFileSpec(module, False))
131 if name:
132 # "file" can be a list or a string
133 if file:
134 if isinstance(file, types.ListType):
135 self.files = lldb.SBFileSpecList()
136 for f in file:
137 self.files.Append(lldb.SBFileSpec(f, False))
138 elif isinstance(file, types.StringTypes):
139 self.files.Append(lldb.SBFileSpec(file, False))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140 self.breakpoints.append(
141 self.target.BreakpointCreateByName(
142 name, self.modules, self.files))
Greg Clayton7b619fc2013-04-03 22:59:27 +0000143 elif file and line:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144 self.breakpoints.append(
145 self.target.BreakpointCreateByLocation(
146 file, line))
147
148 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000149 if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
150 for bp in self.breakpoints:
151 if bp.GetID() == thread.GetStopReasonDataAtIndex(0):
152 if self.callback:
153 if self.callback_owner:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 self.callback(self.callback_owner, thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000155 else:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 self.callback(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000157 return True
158 return False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000159
160
Greg Clayton52e63782013-03-23 01:44:48 +0000161class TestCase:
162 """Class that aids in running performance tests."""
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163
Greg Clayton52e63782013-03-23 01:44:48 +0000164 def __init__(self):
165 self.verbose = False
166 self.debugger = lldb.SBDebugger.Create()
167 self.target = None
168 self.process = None
169 self.thread = None
170 self.launch_info = None
Greg Clayton7b619fc2013-04-03 22:59:27 +0000171 self.done = False
Greg Clayton52e63782013-03-23 01:44:48 +0000172 self.listener = self.debugger.GetListener()
Greg Clayton7b619fc2013-04-03 22:59:27 +0000173 self.user_actions = list()
174 self.builtin_actions = list()
175 self.bp_id_to_dict = dict()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176
Greg Clayton52e63782013-03-23 01:44:48 +0000177 def Setup(self, args):
178 self.launch_info = lldb.SBLaunchInfo(args)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179
180 def Run(self, args):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000181 assert False, "performance.TestCase.Run(self, args) must be subclassed"
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182
Greg Clayton52e63782013-03-23 01:44:48 +0000183 def Launch(self):
184 if self.target:
185 error = lldb.SBError()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 self.process = self.target.Launch(self.launch_info, error)
Greg Clayton52e63782013-03-23 01:44:48 +0000187 if not error.Success():
Serge Guelton525cd592019-03-21 18:27:40 +0000188 print("error: %s" % error.GetCString())
Greg Clayton52e63782013-03-23 01:44:48 +0000189 if self.process:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 self.process.GetBroadcaster().AddListener(self.listener,
191 lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
Greg Clayton52e63782013-03-23 01:44:48 +0000192 return True
193 return False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194
195 def WaitForNextProcessEvent(self):
Greg Clayton52e63782013-03-23 01:44:48 +0000196 event = None
197 if self.process:
198 while event is None:
199 process_event = lldb.SBEvent()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 if self.listener.WaitForEvent(lldb.UINT32_MAX, process_event):
201 state = lldb.SBProcess.GetStateFromEvent(process_event)
Greg Clayton52e63782013-03-23 01:44:48 +0000202 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000203 print("event = %s" % (lldb.SBDebugger.StateAsCString(state)))
Greg Clayton52e63782013-03-23 01:44:48 +0000204 if lldb.SBProcess.GetRestartedFromEvent(process_event):
205 continue
Kate Stoneb9c1b512016-09-06 20:57:50 +0000206 if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000207 event = process_event
208 self.done = True
Greg Clayton52e63782013-03-23 01:44:48 +0000209 elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000210 continue
Greg Clayton52e63782013-03-23 01:44:48 +0000211 elif state == lldb.eStateStopped:
212 event = process_event
213 call_test_step = True
214 fatal = False
215 selected_thread = False
216 for thread in self.process:
217 frame = thread.GetFrameAtIndex(0)
218 select_thread = False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000219
Greg Clayton7b619fc2013-04-03 22:59:27 +0000220 stop_reason = thread.GetStopReason()
Greg Clayton52e63782013-03-23 01:44:48 +0000221 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000222 print("tid = %#x pc = %#x " % (thread.GetThreadID(), frame.GetPC()), end=' ')
Greg Clayton52e63782013-03-23 01:44:48 +0000223 if stop_reason == lldb.eStopReasonNone:
224 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000225 print("none")
Greg Clayton52e63782013-03-23 01:44:48 +0000226 elif stop_reason == lldb.eStopReasonTrace:
227 select_thread = True
228 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000229 print("trace")
Greg Clayton52e63782013-03-23 01:44:48 +0000230 elif stop_reason == lldb.eStopReasonPlanComplete:
231 select_thread = True
232 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000233 print("plan complete")
Greg Clayton52e63782013-03-23 01:44:48 +0000234 elif stop_reason == lldb.eStopReasonThreadExiting:
235 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000236 print("thread exiting")
Greg Clayton52e63782013-03-23 01:44:48 +0000237 elif stop_reason == lldb.eStopReasonExec:
238 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000239 print("exec")
Greg Clayton52e63782013-03-23 01:44:48 +0000240 elif stop_reason == lldb.eStopReasonInvalid:
241 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000242 print("invalid")
Greg Clayton52e63782013-03-23 01:44:48 +0000243 elif stop_reason == lldb.eStopReasonException:
244 select_thread = True
245 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000246 print("exception")
Greg Clayton52e63782013-03-23 01:44:48 +0000247 fatal = True
248 elif stop_reason == lldb.eStopReasonBreakpoint:
249 select_thread = True
Greg Clayton7b619fc2013-04-03 22:59:27 +0000250 bp_id = thread.GetStopReasonDataAtIndex(0)
251 bp_loc_id = thread.GetStopReasonDataAtIndex(1)
Greg Clayton52e63782013-03-23 01:44:48 +0000252 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000253 print("breakpoint id = %d.%d" % (bp_id, bp_loc_id))
Greg Clayton52e63782013-03-23 01:44:48 +0000254 elif stop_reason == lldb.eStopReasonWatchpoint:
255 select_thread = True
256 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000257 print("watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0)))
Greg Clayton52e63782013-03-23 01:44:48 +0000258 elif stop_reason == lldb.eStopReasonSignal:
259 select_thread = True
260 if self.verbose:
Serge Guelton525cd592019-03-21 18:27:40 +0000261 print("signal %d" % (thread.GetStopReasonDataAtIndex(0)))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262
Greg Clayton52e63782013-03-23 01:44:48 +0000263 if select_thread and not selected_thread:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000264 self.thread = thread
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 selected_thread = self.process.SetSelectedThread(
266 thread)
267
Greg Clayton7b619fc2013-04-03 22:59:27 +0000268 for action in self.user_actions:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269 action.ThreadStopped(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000270
Greg Clayton52e63782013-03-23 01:44:48 +0000271 if fatal:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272 # if self.verbose:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000273 # Xcode.RunCommand(self.debugger,"bt all",true)
274 sys.exit(1)
Greg Clayton52e63782013-03-23 01:44:48 +0000275 return event
Kate Stoneb9c1b512016-09-06 20:57:50 +0000276
277
Greg Clayton2d95f352013-03-26 21:00:29 +0000278class Measurement:
279 '''A class that encapsulates a measurement'''
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280
Greg Clayton7b619fc2013-04-03 22:59:27 +0000281 def __init__(self):
282 object.__init__(self)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283
Greg Clayton2d95f352013-03-26 21:00:29 +0000284 def Measure(self):
285 assert False, "performance.Measurement.Measure() must be subclassed"
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286
287
Greg Clayton2d95f352013-03-26 21:00:29 +0000288class MemoryMeasurement(Measurement):
289 '''A class that can measure memory statistics for a process.'''
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290
Greg Clayton2d95f352013-03-26 21:00:29 +0000291 def __init__(self, pid):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000292 Measurement.__init__(self)
Greg Clayton2d95f352013-03-26 21:00:29 +0000293 self.pid = pid
Kate Stoneb9c1b512016-09-06 20:57:50 +0000294 self.stats = [
295 "rprvt",
296 "rshrd",
297 "rsize",
298 "vsize",
299 "vprvt",
300 "kprvt",
301 "kshrd",
302 "faults",
303 "cow",
304 "pageins"]
305 self.command = "top -l 1 -pid %u -stats %s" % (
306 self.pid, ",".join(self.stats))
Greg Clayton2d95f352013-03-26 21:00:29 +0000307 self.value = dict()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308
Greg Clayton2d95f352013-03-26 21:00:29 +0000309 def Measure(self):
Serge Guelton1a12dd72019-03-26 14:46:15 +0000310 output = subprocess.getoutput(self.command).split("\n")[-1]
Greg Clayton2d95f352013-03-26 21:00:29 +0000311 values = re.split('[-+\s]+', output)
312 for (idx, stat) in enumerate(values):
313 multiplier = 1
314 if stat:
315 if stat[-1] == 'K':
Greg Clayton7b619fc2013-04-03 22:59:27 +0000316 multiplier = 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000317 stat = stat[:-1]
318 elif stat[-1] == 'M':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000319 multiplier = 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000320 stat = stat[:-1]
321 elif stat[-1] == 'G':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000322 multiplier = 1024 * 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000323 elif stat[-1] == 'T':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000324 multiplier = 1024 * 1024 * 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000325 stat = stat[:-1]
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326 self.value[self.stats[idx]] = int(stat) * multiplier
Greg Clayton2d95f352013-03-26 21:00:29 +0000327
328 def __str__(self):
329 '''Dump the MemoryMeasurement current value'''
330 s = ''
331 for key in self.value.keys():
332 if s:
333 s += "\n"
334 s += "%8s = %s" % (key, self.value[key])
335 return s
336
Greg Clayton52e63782013-03-23 01:44:48 +0000337
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338class TesterTestCase(TestCase):
339
Greg Clayton7b619fc2013-04-03 22:59:27 +0000340 def __init__(self):
341 TestCase.__init__(self)
342 self.verbose = True
343 self.num_steps = 5
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344
345 def BreakpointHit(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000346 bp_id = thread.GetStopReasonDataAtIndex(0)
347 loc_id = thread.GetStopReasonDataAtIndex(1)
Serge Guelton525cd592019-03-21 18:27:40 +0000348 print("Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id)))
Greg Clayton7b619fc2013-04-03 22:59:27 +0000349 thread.StepOver()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000350
351 def PlanComplete(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000352 if self.num_steps > 0:
353 thread.StepOver()
354 self.num_steps = self.num_steps - 1
355 else:
356 thread.process.Kill()
357
Kate Stoneb9c1b512016-09-06 20:57:50 +0000358 def Run(self, args):
Greg Clayton52e63782013-03-23 01:44:48 +0000359 self.Setup(args)
Greg Clayton2d95f352013-03-26 21:00:29 +0000360 with Timer() as total_time:
361 self.target = self.debugger.CreateTarget(args[0])
362 if self.target:
Greg Clayton52e63782013-03-23 01:44:48 +0000363 with Timer() as breakpoint_timer:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000364 bp = self.target.BreakpointCreateByName("main")
Kate Stoneb9c1b512016-09-06 20:57:50 +0000365 print(
366 'Breakpoint time = %.03f sec.' %
367 breakpoint_timer.interval)
368
369 self.user_actions.append(
370 BreakpointAction(
371 breakpoint=bp,
372 callback=TesterTestCase.BreakpointHit,
373 callback_owner=self))
374 self.user_actions.append(
375 PlanCompleteAction(
376 callback=TesterTestCase.PlanComplete,
377 callback_owner=self))
378
Greg Clayton2d95f352013-03-26 21:00:29 +0000379 if self.Launch():
Greg Clayton7b619fc2013-04-03 22:59:27 +0000380 while not self.done:
381 self.WaitForNextProcessEvent()
Greg Clayton2d95f352013-03-26 21:00:29 +0000382 else:
Serge Guelton525cd592019-03-21 18:27:40 +0000383 print("error: failed to launch process")
Greg Clayton52e63782013-03-23 01:44:48 +0000384 else:
Serge Guelton525cd592019-03-21 18:27:40 +0000385 print("error: failed to create target with '%s'" % (args[0]))
Greg Clayton2d95f352013-03-26 21:00:29 +0000386 print('Total time = %.03f sec.' % total_time.interval)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000387
Greg Clayton52e63782013-03-23 01:44:48 +0000388
389if __name__ == '__main__':
390 lldb.SBDebugger.Initialize()
391 test = TesterTestCase()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000392 test.Run(sys.argv[1:])
Greg Clayton2d95f352013-03-26 21:00:29 +0000393 mem = MemoryMeasurement(os.getpid())
394 mem.Measure()
Serge Guelton525cd592019-03-21 18:27:40 +0000395 print(str(mem))
Greg Clayton52e63782013-03-23 01:44:48 +0000396 lldb.SBDebugger.Terminate()
Greg Clayton2d95f352013-03-26 21:00:29 +0000397 # print "sleeeping for 100 seconds"
398 # time.sleep(100)