3 #----------------------------------------------------------------------
4 # Be sure to add the python path that points to the LLDB shared library.
6 # setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
8 # export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
9 #----------------------------------------------------------------------
11 from __future__
import print_function
23 #----------------------------------------------------------------------
24 # Code that auto imports LLDB
25 #----------------------------------------------------------------------
27 # Just try for LLDB in case PYTHONPATH is already correctly setup
30 lldb_python_dirs
= list()
31 # lldb is not in the PYTHONPATH, try some defaults for the current platform
32 platform_system
= platform
.system()
33 if platform_system
== 'Darwin':
34 # On Darwin, try the currently selected Xcode directory
35 xcode_dir
= subprocess
.check_output("xcode-select --print-path", shell
=True)
37 lldb_python_dirs
.append(
40 '/../SharedFrameworks/LLDB.framework/Resources/Python'))
41 lldb_python_dirs
.append(
42 xcode_dir
+ '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
43 lldb_python_dirs
.append(
44 '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
46 for lldb_python_dir
in lldb_python_dirs
:
47 if os
.path
.exists(lldb_python_dir
):
48 if not (sys
.path
.__contains
__(lldb_python_dir
)):
49 sys
.path
.append(lldb_python_dir
)
55 print('imported lldb from: "%s"' % (lldb_python_dir
))
59 print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly")
66 self
.start
= time
.clock()
69 def __exit__(self
, *args
):
70 self
.end
= time
.clock()
71 self
.interval
= self
.end
- self
.start
75 """Class that encapsulates actions to take when a thread stops for a reason."""
77 def __init__(self
, callback
=None, callback_owner
=None):
78 self
.callback
= callback
79 self
.callback_owner
= callback_owner
81 def ThreadStopped(self
, thread
):
82 assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
85 class PlanCompleteAction (Action
):
87 def __init__(self
, callback
=None, callback_owner
=None):
88 Action
.__init
__(self
, callback
, callback_owner
)
90 def ThreadStopped(self
, thread
):
91 if thread
.GetStopReason() == lldb
.eStopReasonPlanComplete
:
93 if self
.callback_owner
:
94 self
.callback(self
.callback_owner
, thread
)
101 class BreakpointAction (Action
):
112 Action
.__init
__(self
, callback
, callback_owner
)
113 self
.modules
= lldb
.SBFileSpecList()
114 self
.files
= lldb
.SBFileSpecList()
115 self
.breakpoints
= list()
116 # "module" can be a list or a string
118 self
.breakpoints
.append(breakpoint
)
121 if isinstance(module
, types
.ListType
):
122 for module_path
in module
:
124 lldb
.SBFileSpec(module_path
, False))
125 elif isinstance(module
, types
.StringTypes
):
126 self
.modules
.Append(lldb
.SBFileSpec(module
, False))
128 # "file" can be a list or a string
130 if isinstance(file, types
.ListType
):
131 self
.files
= lldb
.SBFileSpecList()
133 self
.files
.Append(lldb
.SBFileSpec(f
, False))
134 elif isinstance(file, types
.StringTypes
):
135 self
.files
.Append(lldb
.SBFileSpec(file, False))
136 self
.breakpoints
.append(
137 self
.target
.BreakpointCreateByName(
138 name
, self
.modules
, self
.files
))
140 self
.breakpoints
.append(
141 self
.target
.BreakpointCreateByLocation(
144 def ThreadStopped(self
, thread
):
145 if thread
.GetStopReason() == lldb
.eStopReasonBreakpoint
:
146 for bp
in self
.breakpoints
:
147 if bp
.GetID() == thread
.GetStopReasonDataAtIndex(0):
149 if self
.callback_owner
:
150 self
.callback(self
.callback_owner
, thread
)
152 self
.callback(thread
)
158 """Class that aids in running performance tests."""
162 self
.debugger
= lldb
.SBDebugger
.Create()
166 self
.launch_info
= None
168 self
.listener
= self
.debugger
.GetListener()
169 self
.user_actions
= list()
170 self
.builtin_actions
= list()
171 self
.bp_id_to_dict
= dict()
173 def Setup(self
, args
):
174 self
.launch_info
= lldb
.SBLaunchInfo(args
)
177 assert False, "performance.TestCase.Run(self, args) must be subclassed"
181 error
= lldb
.SBError()
182 self
.process
= self
.target
.Launch(self
.launch_info
, error
)
183 if not error
.Success():
184 print("error: %s" % error
.GetCString())
186 self
.process
.GetBroadcaster().AddListener(self
.listener
,
187 lldb
.SBProcess
.eBroadcastBitStateChanged | lldb
.SBProcess
.eBroadcastBitInterrupt
)
191 def WaitForNextProcessEvent(self
):
195 process_event
= lldb
.SBEvent()
196 if self
.listener
.WaitForEvent(lldb
.UINT32_MAX
, process_event
):
197 state
= lldb
.SBProcess
.GetStateFromEvent(process_event
)
199 print("event = %s" % (lldb
.SBDebugger
.StateAsCString(state
)))
200 if lldb
.SBProcess
.GetRestartedFromEvent(process_event
):
202 if state
== lldb
.eStateInvalid
or state
== lldb
.eStateDetached
or state
== lldb
.eStateCrashed
or state
== lldb
.eStateUnloaded
or state
== lldb
.eStateExited
:
203 event
= process_event
205 elif state
== lldb
.eStateConnected
or state
== lldb
.eStateAttaching
or state
== lldb
.eStateLaunching
or state
== lldb
.eStateRunning
or state
== lldb
.eStateStepping
or state
== lldb
.eStateSuspended
:
207 elif state
== lldb
.eStateStopped
:
208 event
= process_event
209 call_test_step
= True
211 selected_thread
= False
212 for thread
in self
.process
:
213 frame
= thread
.GetFrameAtIndex(0)
214 select_thread
= False
216 stop_reason
= thread
.GetStopReason()
218 print("tid = %#x pc = %#x " % (thread
.GetThreadID(), frame
.GetPC()), end
=' ')
219 if stop_reason
== lldb
.eStopReasonNone
:
222 elif stop_reason
== lldb
.eStopReasonTrace
:
226 elif stop_reason
== lldb
.eStopReasonPlanComplete
:
229 print("plan complete")
230 elif stop_reason
== lldb
.eStopReasonThreadExiting
:
232 print("thread exiting")
233 elif stop_reason
== lldb
.eStopReasonExec
:
236 elif stop_reason
== lldb
.eStopReasonInvalid
:
239 elif stop_reason
== lldb
.eStopReasonException
:
244 elif stop_reason
== lldb
.eStopReasonBreakpoint
:
246 bp_id
= thread
.GetStopReasonDataAtIndex(0)
247 bp_loc_id
= thread
.GetStopReasonDataAtIndex(1)
249 print("breakpoint id = %d.%d" % (bp_id
, bp_loc_id
))
250 elif stop_reason
== lldb
.eStopReasonWatchpoint
:
253 print("watchpoint id = %d" % (thread
.GetStopReasonDataAtIndex(0)))
254 elif stop_reason
== lldb
.eStopReasonSignal
:
257 print("signal %d" % (thread
.GetStopReasonDataAtIndex(0)))
259 if select_thread
and not selected_thread
:
261 selected_thread
= self
.process
.SetSelectedThread(
264 for action
in self
.user_actions
:
265 action
.ThreadStopped(thread
)
269 # Xcode.RunCommand(self.debugger,"bt all",true)
275 '''A class that encapsulates a measurement'''
278 object.__init
__(self
)
281 assert False, "performance.Measurement.Measure() must be subclassed"
284 class MemoryMeasurement(Measurement
):
285 '''A class that can measure memory statistics for a process.'''
287 def __init__(self
, pid
):
288 Measurement
.__init
__(self
)
301 self
.command
= "top -l 1 -pid %u -stats %s" % (
302 self
.pid
, ",".join(self
.stats
))
306 output
= subprocess
.getoutput(self
.command
).split("\n")[-1]
307 values
= re
.split('[-+\s]+', output
)
308 for (idx
, stat
) in enumerate(values
):
314 elif stat
[-1] == 'M':
315 multiplier
= 1024 * 1024
317 elif stat
[-1] == 'G':
318 multiplier
= 1024 * 1024 * 1024
319 elif stat
[-1] == 'T':
320 multiplier
= 1024 * 1024 * 1024 * 1024
322 self
.value
[self
.stats
[idx
]] = int(stat
) * multiplier
325 '''Dump the MemoryMeasurement current value'''
327 for key
in self
.value
.keys():
330 s
+= "%8s = %s" % (key
, self
.value
[key
])
334 class TesterTestCase(TestCase
):
337 TestCase
.__init
__(self
)
341 def BreakpointHit(self
, thread
):
342 bp_id
= thread
.GetStopReasonDataAtIndex(0)
343 loc_id
= thread
.GetStopReasonDataAtIndex(1)
344 print("Breakpoint %i.%i hit: %s" % (bp_id
, loc_id
, thread
.process
.target
.FindBreakpointByID(bp_id
)))
347 def PlanComplete(self
, thread
):
348 if self
.num_steps
> 0:
350 self
.num_steps
= self
.num_steps
- 1
352 thread
.process
.Kill()
356 with
Timer() as total_time
:
357 self
.target
= self
.debugger
.CreateTarget(args
[0])
359 with
Timer() as breakpoint_timer
:
360 bp
= self
.target
.BreakpointCreateByName("main")
362 'Breakpoint time = %.03f sec.' %
363 breakpoint_timer
.interval
)
365 self
.user_actions
.append(
368 callback
=TesterTestCase
.BreakpointHit
,
369 callback_owner
=self
))
370 self
.user_actions
.append(
372 callback
=TesterTestCase
.PlanComplete
,
373 callback_owner
=self
))
377 self
.WaitForNextProcessEvent()
379 print("error: failed to launch process")
381 print("error: failed to create target with '%s'" % (args
[0]))
382 print('Total time = %.03f sec.' % total_time
.interval
)
385 if __name__
== '__main__':
386 lldb
.SBDebugger
.Initialize()
387 test
= TesterTestCase()
388 test
.Run(sys
.argv
[1:])
389 mem
= MemoryMeasurement(os
.getpid())
392 lldb
.SBDebugger
.Terminate()
393 # print "sleeeping for 100 seconds"