blob: f1bc94f4b43ab843a24e643d55f9b6339067e6a1 [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
11import commands
12import optparse
13import os
14import platform
Greg Clayton2d95f352013-03-26 21:00:29 +000015import re
Greg Clayton52e63782013-03-23 01:44:48 +000016import resource
17import sys
18import time
Greg Clayton7b619fc2013-04-03 22:59:27 +000019import types
Greg Clayton52e63782013-03-23 01:44:48 +000020
21#----------------------------------------------------------------------
22# Code that auto imports LLDB
23#----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000024try:
Greg Clayton52e63782013-03-23 01:44:48 +000025 # Just try for LLDB in case PYTHONPATH is already correctly setup
26 import lldb
27except ImportError:
28 lldb_python_dirs = list()
29 # lldb is not in the PYTHONPATH, try some defaults for the current platform
30 platform_system = platform.system()
31 if platform_system == 'Darwin':
32 # On Darwin, try the currently selected Xcode directory
33 xcode_dir = commands.getoutput("xcode-select --print-path")
34 if xcode_dir:
Kate Stoneb9c1b512016-09-06 20:57:50 +000035 lldb_python_dirs.append(
36 os.path.realpath(
37 xcode_dir +
38 '/../SharedFrameworks/LLDB.framework/Resources/Python'))
39 lldb_python_dirs.append(
40 xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
41 lldb_python_dirs.append(
42 '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
Greg Clayton52e63782013-03-23 01:44:48 +000043 success = False
44 for lldb_python_dir in lldb_python_dirs:
45 if os.path.exists(lldb_python_dir):
46 if not (sys.path.__contains__(lldb_python_dir)):
47 sys.path.append(lldb_python_dir)
Kate Stoneb9c1b512016-09-06 20:57:50 +000048 try:
Greg Clayton52e63782013-03-23 01:44:48 +000049 import lldb
50 except ImportError:
51 pass
52 else:
53 print 'imported lldb from: "%s"' % (lldb_python_dir)
54 success = True
55 break
56 if not success:
57 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
58 sys.exit(1)
59
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061class Timer:
62
Greg Clayton52e63782013-03-23 01:44:48 +000063 def __enter__(self):
64 self.start = time.clock()
65 return self
66
67 def __exit__(self, *args):
68 self.end = time.clock()
69 self.interval = self.end - self.start
70
Kate Stoneb9c1b512016-09-06 20:57:50 +000071
Greg Clayton7b619fc2013-04-03 22:59:27 +000072class Action(object):
73 """Class that encapsulates actions to take when a thread stops for a reason."""
Kate Stoneb9c1b512016-09-06 20:57:50 +000074
75 def __init__(self, callback=None, callback_owner=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +000076 self.callback = callback
77 self.callback_owner = callback_owner
Kate Stoneb9c1b512016-09-06 20:57:50 +000078
79 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +000080 assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
81
Kate Stoneb9c1b512016-09-06 20:57:50 +000082
Greg Clayton7b619fc2013-04-03 22:59:27 +000083class PlanCompleteAction (Action):
Kate Stoneb9c1b512016-09-06 20:57:50 +000084
85 def __init__(self, callback=None, callback_owner=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +000086 Action.__init__(self, callback, callback_owner)
Kate Stoneb9c1b512016-09-06 20:57:50 +000087
88 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +000089 if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
90 if self.callback:
91 if self.callback_owner:
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 self.callback(self.callback_owner, thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +000093 else:
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 self.callback(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +000095 return True
96 return False
97
98
99class BreakpointAction (Action):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100
101 def __init__(
102 self,
103 callback=None,
104 callback_owner=None,
105 name=None,
106 module=None,
107 file=None,
108 line=None,
109 breakpoint=None):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000110 Action.__init__(self, callback, callback_owner)
111 self.modules = lldb.SBFileSpecList()
112 self.files = lldb.SBFileSpecList()
113 self.breakpoints = list()
114 # "module" can be a list or a string
115 if breakpoint:
116 self.breakpoints.append(breakpoint)
117 else:
118 if module:
119 if isinstance(module, types.ListType):
120 for module_path in module:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 self.modules.Append(
122 lldb.SBFileSpec(module_path, False))
Greg Clayton7b619fc2013-04-03 22:59:27 +0000123 elif isinstance(module, types.StringTypes):
124 self.modules.Append(lldb.SBFileSpec(module, False))
125 if name:
126 # "file" can be a list or a string
127 if file:
128 if isinstance(file, types.ListType):
129 self.files = lldb.SBFileSpecList()
130 for f in file:
131 self.files.Append(lldb.SBFileSpec(f, False))
132 elif isinstance(file, types.StringTypes):
133 self.files.Append(lldb.SBFileSpec(file, False))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 self.breakpoints.append(
135 self.target.BreakpointCreateByName(
136 name, self.modules, self.files))
Greg Clayton7b619fc2013-04-03 22:59:27 +0000137 elif file and line:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 self.breakpoints.append(
139 self.target.BreakpointCreateByLocation(
140 file, line))
141
142 def ThreadStopped(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000143 if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
144 for bp in self.breakpoints:
145 if bp.GetID() == thread.GetStopReasonDataAtIndex(0):
146 if self.callback:
147 if self.callback_owner:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 self.callback(self.callback_owner, thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000149 else:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 self.callback(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000151 return True
152 return False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153
154
Greg Clayton52e63782013-03-23 01:44:48 +0000155class TestCase:
156 """Class that aids in running performance tests."""
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157
Greg Clayton52e63782013-03-23 01:44:48 +0000158 def __init__(self):
159 self.verbose = False
160 self.debugger = lldb.SBDebugger.Create()
161 self.target = None
162 self.process = None
163 self.thread = None
164 self.launch_info = None
Greg Clayton7b619fc2013-04-03 22:59:27 +0000165 self.done = False
Greg Clayton52e63782013-03-23 01:44:48 +0000166 self.listener = self.debugger.GetListener()
Greg Clayton7b619fc2013-04-03 22:59:27 +0000167 self.user_actions = list()
168 self.builtin_actions = list()
169 self.bp_id_to_dict = dict()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170
Greg Clayton52e63782013-03-23 01:44:48 +0000171 def Setup(self, args):
172 self.launch_info = lldb.SBLaunchInfo(args)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173
174 def Run(self, args):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000175 assert False, "performance.TestCase.Run(self, args) must be subclassed"
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176
Greg Clayton52e63782013-03-23 01:44:48 +0000177 def Launch(self):
178 if self.target:
179 error = lldb.SBError()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 self.process = self.target.Launch(self.launch_info, error)
Greg Clayton52e63782013-03-23 01:44:48 +0000181 if not error.Success():
182 print "error: %s" % error.GetCString()
183 if self.process:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 self.process.GetBroadcaster().AddListener(self.listener,
185 lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
Greg Clayton52e63782013-03-23 01:44:48 +0000186 return True
187 return False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188
189 def WaitForNextProcessEvent(self):
Greg Clayton52e63782013-03-23 01:44:48 +0000190 event = None
191 if self.process:
192 while event is None:
193 process_event = lldb.SBEvent()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 if self.listener.WaitForEvent(lldb.UINT32_MAX, process_event):
195 state = lldb.SBProcess.GetStateFromEvent(process_event)
Greg Clayton52e63782013-03-23 01:44:48 +0000196 if self.verbose:
197 print "event = %s" % (lldb.SBDebugger.StateAsCString(state))
198 if lldb.SBProcess.GetRestartedFromEvent(process_event):
199 continue
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 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 +0000201 event = process_event
202 self.done = True
Greg Clayton52e63782013-03-23 01:44:48 +0000203 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 +0000204 continue
Greg Clayton52e63782013-03-23 01:44:48 +0000205 elif state == lldb.eStateStopped:
206 event = process_event
207 call_test_step = True
208 fatal = False
209 selected_thread = False
210 for thread in self.process:
211 frame = thread.GetFrameAtIndex(0)
212 select_thread = False
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213
Greg Clayton7b619fc2013-04-03 22:59:27 +0000214 stop_reason = thread.GetStopReason()
Greg Clayton52e63782013-03-23 01:44:48 +0000215 if self.verbose:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216 print "tid = %#x pc = %#x " % (thread.GetThreadID(), frame.GetPC()),
Greg Clayton52e63782013-03-23 01:44:48 +0000217 if stop_reason == lldb.eStopReasonNone:
218 if self.verbose:
219 print "none"
220 elif stop_reason == lldb.eStopReasonTrace:
221 select_thread = True
222 if self.verbose:
223 print "trace"
224 elif stop_reason == lldb.eStopReasonPlanComplete:
225 select_thread = True
226 if self.verbose:
227 print "plan complete"
228 elif stop_reason == lldb.eStopReasonThreadExiting:
229 if self.verbose:
230 print "thread exiting"
231 elif stop_reason == lldb.eStopReasonExec:
232 if self.verbose:
233 print "exec"
234 elif stop_reason == lldb.eStopReasonInvalid:
235 if self.verbose:
236 print "invalid"
237 elif stop_reason == lldb.eStopReasonException:
238 select_thread = True
239 if self.verbose:
240 print "exception"
241 fatal = True
242 elif stop_reason == lldb.eStopReasonBreakpoint:
243 select_thread = True
Greg Clayton7b619fc2013-04-03 22:59:27 +0000244 bp_id = thread.GetStopReasonDataAtIndex(0)
245 bp_loc_id = thread.GetStopReasonDataAtIndex(1)
Greg Clayton52e63782013-03-23 01:44:48 +0000246 if self.verbose:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000247 print "breakpoint id = %d.%d" % (bp_id, bp_loc_id)
Greg Clayton52e63782013-03-23 01:44:48 +0000248 elif stop_reason == lldb.eStopReasonWatchpoint:
249 select_thread = True
250 if self.verbose:
251 print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0))
252 elif stop_reason == lldb.eStopReasonSignal:
253 select_thread = True
254 if self.verbose:
255 print "signal %d" % (thread.GetStopReasonDataAtIndex(0))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256
Greg Clayton52e63782013-03-23 01:44:48 +0000257 if select_thread and not selected_thread:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000258 self.thread = thread
Kate Stoneb9c1b512016-09-06 20:57:50 +0000259 selected_thread = self.process.SetSelectedThread(
260 thread)
261
Greg Clayton7b619fc2013-04-03 22:59:27 +0000262 for action in self.user_actions:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263 action.ThreadStopped(thread)
Greg Clayton7b619fc2013-04-03 22:59:27 +0000264
Greg Clayton52e63782013-03-23 01:44:48 +0000265 if fatal:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000266 # if self.verbose:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000267 # Xcode.RunCommand(self.debugger,"bt all",true)
268 sys.exit(1)
Greg Clayton52e63782013-03-23 01:44:48 +0000269 return event
Kate Stoneb9c1b512016-09-06 20:57:50 +0000270
271
Greg Clayton2d95f352013-03-26 21:00:29 +0000272class Measurement:
273 '''A class that encapsulates a measurement'''
Kate Stoneb9c1b512016-09-06 20:57:50 +0000274
Greg Clayton7b619fc2013-04-03 22:59:27 +0000275 def __init__(self):
276 object.__init__(self)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277
Greg Clayton2d95f352013-03-26 21:00:29 +0000278 def Measure(self):
279 assert False, "performance.Measurement.Measure() must be subclassed"
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280
281
Greg Clayton2d95f352013-03-26 21:00:29 +0000282class MemoryMeasurement(Measurement):
283 '''A class that can measure memory statistics for a process.'''
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284
Greg Clayton2d95f352013-03-26 21:00:29 +0000285 def __init__(self, pid):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000286 Measurement.__init__(self)
Greg Clayton2d95f352013-03-26 21:00:29 +0000287 self.pid = pid
Kate Stoneb9c1b512016-09-06 20:57:50 +0000288 self.stats = [
289 "rprvt",
290 "rshrd",
291 "rsize",
292 "vsize",
293 "vprvt",
294 "kprvt",
295 "kshrd",
296 "faults",
297 "cow",
298 "pageins"]
299 self.command = "top -l 1 -pid %u -stats %s" % (
300 self.pid, ",".join(self.stats))
Greg Clayton2d95f352013-03-26 21:00:29 +0000301 self.value = dict()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302
Greg Clayton2d95f352013-03-26 21:00:29 +0000303 def Measure(self):
304 output = commands.getoutput(self.command).split("\n")[-1]
305 values = re.split('[-+\s]+', output)
306 for (idx, stat) in enumerate(values):
307 multiplier = 1
308 if stat:
309 if stat[-1] == 'K':
Greg Clayton7b619fc2013-04-03 22:59:27 +0000310 multiplier = 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000311 stat = stat[:-1]
312 elif stat[-1] == 'M':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 multiplier = 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000314 stat = stat[:-1]
315 elif stat[-1] == 'G':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000316 multiplier = 1024 * 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000317 elif stat[-1] == 'T':
Kate Stoneb9c1b512016-09-06 20:57:50 +0000318 multiplier = 1024 * 1024 * 1024 * 1024
Greg Clayton2d95f352013-03-26 21:00:29 +0000319 stat = stat[:-1]
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 self.value[self.stats[idx]] = int(stat) * multiplier
Greg Clayton2d95f352013-03-26 21:00:29 +0000321
322 def __str__(self):
323 '''Dump the MemoryMeasurement current value'''
324 s = ''
325 for key in self.value.keys():
326 if s:
327 s += "\n"
328 s += "%8s = %s" % (key, self.value[key])
329 return s
330
Greg Clayton52e63782013-03-23 01:44:48 +0000331
Kate Stoneb9c1b512016-09-06 20:57:50 +0000332class TesterTestCase(TestCase):
333
Greg Clayton7b619fc2013-04-03 22:59:27 +0000334 def __init__(self):
335 TestCase.__init__(self)
336 self.verbose = True
337 self.num_steps = 5
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338
339 def BreakpointHit(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000340 bp_id = thread.GetStopReasonDataAtIndex(0)
341 loc_id = thread.GetStopReasonDataAtIndex(1)
342 print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id))
343 thread.StepOver()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344
345 def PlanComplete(self, thread):
Greg Clayton7b619fc2013-04-03 22:59:27 +0000346 if self.num_steps > 0:
347 thread.StepOver()
348 self.num_steps = self.num_steps - 1
349 else:
350 thread.process.Kill()
351
Kate Stoneb9c1b512016-09-06 20:57:50 +0000352 def Run(self, args):
Greg Clayton52e63782013-03-23 01:44:48 +0000353 self.Setup(args)
Greg Clayton2d95f352013-03-26 21:00:29 +0000354 with Timer() as total_time:
355 self.target = self.debugger.CreateTarget(args[0])
356 if self.target:
Greg Clayton52e63782013-03-23 01:44:48 +0000357 with Timer() as breakpoint_timer:
Greg Clayton7b619fc2013-04-03 22:59:27 +0000358 bp = self.target.BreakpointCreateByName("main")
Kate Stoneb9c1b512016-09-06 20:57:50 +0000359 print(
360 'Breakpoint time = %.03f sec.' %
361 breakpoint_timer.interval)
362
363 self.user_actions.append(
364 BreakpointAction(
365 breakpoint=bp,
366 callback=TesterTestCase.BreakpointHit,
367 callback_owner=self))
368 self.user_actions.append(
369 PlanCompleteAction(
370 callback=TesterTestCase.PlanComplete,
371 callback_owner=self))
372
Greg Clayton2d95f352013-03-26 21:00:29 +0000373 if self.Launch():
Greg Clayton7b619fc2013-04-03 22:59:27 +0000374 while not self.done:
375 self.WaitForNextProcessEvent()
Greg Clayton2d95f352013-03-26 21:00:29 +0000376 else:
377 print "error: failed to launch process"
Greg Clayton52e63782013-03-23 01:44:48 +0000378 else:
Greg Clayton2d95f352013-03-26 21:00:29 +0000379 print "error: failed to create target with '%s'" % (args[0])
380 print('Total time = %.03f sec.' % total_time.interval)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000381
Greg Clayton52e63782013-03-23 01:44:48 +0000382
383if __name__ == '__main__':
384 lldb.SBDebugger.Initialize()
385 test = TesterTestCase()
Kate Stoneb9c1b512016-09-06 20:57:50 +0000386 test.Run(sys.argv[1:])
Greg Clayton2d95f352013-03-26 21:00:29 +0000387 mem = MemoryMeasurement(os.getpid())
388 mem.Measure()
389 print str(mem)
Greg Clayton52e63782013-03-23 01:44:48 +0000390 lldb.SBDebugger.Terminate()
Greg Clayton2d95f352013-03-26 21:00:29 +0000391 # print "sleeeping for 100 seconds"
392 # time.sleep(100)