diff options
Diffstat (limited to 'examples/python/performance.py')
-rwxr-xr-x | examples/python/performance.py | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/examples/python/performance.py b/examples/python/performance.py new file mode 100755 index 0000000000000..a225d7b731e07 --- /dev/null +++ b/examples/python/performance.py @@ -0,0 +1,335 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# On MacOSX csh, tcsh: +# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +# On MacOSX sh, bash: +# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +#---------------------------------------------------------------------- + +import commands +import optparse +import os +import platform +import re +import resource +import sys +import time +import types + +#---------------------------------------------------------------------- +# Code that auto imports LLDB +#---------------------------------------------------------------------- +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + + +class Timer: + def __enter__(self): + self.start = time.clock() + return self + + def __exit__(self, *args): + self.end = time.clock() + self.interval = self.end - self.start + +class Action(object): + """Class that encapsulates actions to take when a thread stops for a reason.""" + def __init__(self, callback = None, callback_owner = None): + self.callback = callback + self.callback_owner = callback_owner + def ThreadStopped (self, thread): + assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass" + +class PlanCompleteAction (Action): + def __init__(self, callback = None, callback_owner = None): + Action.__init__(self, callback, callback_owner) + def ThreadStopped (self, thread): + if thread.GetStopReason() == lldb.eStopReasonPlanComplete: + if self.callback: + if self.callback_owner: + self.callback (self.callback_owner, thread) + else: + self.callback (thread) + return True + return False + + +class BreakpointAction (Action): + def __init__(self, callback = None, callback_owner = None, name = None, module = None, file = None, line = None, breakpoint = None): + Action.__init__(self, callback, callback_owner) + self.modules = lldb.SBFileSpecList() + self.files = lldb.SBFileSpecList() + self.breakpoints = list() + # "module" can be a list or a string + if breakpoint: + self.breakpoints.append(breakpoint) + else: + if module: + if isinstance(module, types.ListType): + for module_path in module: + self.modules.Append(lldb.SBFileSpec(module_path, False)) + elif isinstance(module, types.StringTypes): + self.modules.Append(lldb.SBFileSpec(module, False)) + if name: + # "file" can be a list or a string + if file: + if isinstance(file, types.ListType): + self.files = lldb.SBFileSpecList() + for f in file: + self.files.Append(lldb.SBFileSpec(f, False)) + elif isinstance(file, types.StringTypes): + self.files.Append(lldb.SBFileSpec(file, False)) + self.breakpoints.append (self.target.BreakpointCreateByName(name, self.modules, self.files)) + elif file and line: + self.breakpoints.append (self.target.BreakpointCreateByLocation(file, line)) + def ThreadStopped (self, thread): + if thread.GetStopReason() == lldb.eStopReasonBreakpoint: + for bp in self.breakpoints: + if bp.GetID() == thread.GetStopReasonDataAtIndex(0): + if self.callback: + if self.callback_owner: + self.callback (self.callback_owner, thread) + else: + self.callback (thread) + return True + return False +class TestCase: + """Class that aids in running performance tests.""" + def __init__(self): + self.verbose = False + self.debugger = lldb.SBDebugger.Create() + self.target = None + self.process = None + self.thread = None + self.launch_info = None + self.done = False + self.listener = self.debugger.GetListener() + self.user_actions = list() + self.builtin_actions = list() + self.bp_id_to_dict = dict() + + def Setup(self, args): + self.launch_info = lldb.SBLaunchInfo(args) + + def Run (self, args): + assert False, "performance.TestCase.Run(self, args) must be subclassed" + + def Launch(self): + if self.target: + error = lldb.SBError() + self.process = self.target.Launch (self.launch_info, error) + if not error.Success(): + print "error: %s" % error.GetCString() + if self.process: + self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt) + return True + return False + + def WaitForNextProcessEvent (self): + event = None + if self.process: + while event is None: + process_event = lldb.SBEvent() + if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event): + state = lldb.SBProcess.GetStateFromEvent (process_event) + if self.verbose: + print "event = %s" % (lldb.SBDebugger.StateAsCString(state)) + if lldb.SBProcess.GetRestartedFromEvent(process_event): + continue + if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited: + event = process_event + self.done = True + elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended: + continue + elif state == lldb.eStateStopped: + event = process_event + call_test_step = True + fatal = False + selected_thread = False + for thread in self.process: + frame = thread.GetFrameAtIndex(0) + select_thread = False + + stop_reason = thread.GetStopReason() + if self.verbose: + print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()), + if stop_reason == lldb.eStopReasonNone: + if self.verbose: + print "none" + elif stop_reason == lldb.eStopReasonTrace: + select_thread = True + if self.verbose: + print "trace" + elif stop_reason == lldb.eStopReasonPlanComplete: + select_thread = True + if self.verbose: + print "plan complete" + elif stop_reason == lldb.eStopReasonThreadExiting: + if self.verbose: + print "thread exiting" + elif stop_reason == lldb.eStopReasonExec: + if self.verbose: + print "exec" + elif stop_reason == lldb.eStopReasonInvalid: + if self.verbose: + print "invalid" + elif stop_reason == lldb.eStopReasonException: + select_thread = True + if self.verbose: + print "exception" + fatal = True + elif stop_reason == lldb.eStopReasonBreakpoint: + select_thread = True + bp_id = thread.GetStopReasonDataAtIndex(0) + bp_loc_id = thread.GetStopReasonDataAtIndex(1) + if self.verbose: + print "breakpoint id = %d.%d" % (bp_id, bp_loc_id) + elif stop_reason == lldb.eStopReasonWatchpoint: + select_thread = True + if self.verbose: + print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0)) + elif stop_reason == lldb.eStopReasonSignal: + select_thread = True + if self.verbose: + print "signal %d" % (thread.GetStopReasonDataAtIndex(0)) + + if select_thread and not selected_thread: + self.thread = thread + selected_thread = self.process.SetSelectedThread(thread) + + for action in self.user_actions: + action.ThreadStopped (thread) + + + if fatal: + # if self.verbose: + # Xcode.RunCommand(self.debugger,"bt all",true) + sys.exit(1) + return event + +class Measurement: + '''A class that encapsulates a measurement''' + def __init__(self): + object.__init__(self) + def Measure(self): + assert False, "performance.Measurement.Measure() must be subclassed" + +class MemoryMeasurement(Measurement): + '''A class that can measure memory statistics for a process.''' + def __init__(self, pid): + Measurement.__init__(self) + self.pid = pid + self.stats = ["rprvt","rshrd","rsize","vsize","vprvt","kprvt","kshrd","faults","cow","pageins"] + self.command = "top -l 1 -pid %u -stats %s" % (self.pid, ",".join(self.stats)) + self.value = dict() + + def Measure(self): + output = commands.getoutput(self.command).split("\n")[-1] + values = re.split('[-+\s]+', output) + for (idx, stat) in enumerate(values): + multiplier = 1 + if stat: + if stat[-1] == 'K': + multiplier = 1024 + stat = stat[:-1] + elif stat[-1] == 'M': + multiplier = 1024*1024 + stat = stat[:-1] + elif stat[-1] == 'G': + multiplier = 1024*1024*1024 + elif stat[-1] == 'T': + multiplier = 1024*1024*1024*1024 + stat = stat[:-1] + self.value[self.stats[idx]] = int (stat) * multiplier + + def __str__(self): + '''Dump the MemoryMeasurement current value''' + s = '' + for key in self.value.keys(): + if s: + s += "\n" + s += "%8s = %s" % (key, self.value[key]) + return s + + +class TesterTestCase(TestCase): + def __init__(self): + TestCase.__init__(self) + self.verbose = True + self.num_steps = 5 + + def BreakpointHit (self, thread): + bp_id = thread.GetStopReasonDataAtIndex(0) + loc_id = thread.GetStopReasonDataAtIndex(1) + print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id)) + thread.StepOver() + + def PlanComplete (self, thread): + if self.num_steps > 0: + thread.StepOver() + self.num_steps = self.num_steps - 1 + else: + thread.process.Kill() + + def Run (self, args): + self.Setup(args) + with Timer() as total_time: + self.target = self.debugger.CreateTarget(args[0]) + if self.target: + with Timer() as breakpoint_timer: + bp = self.target.BreakpointCreateByName("main") + print('Breakpoint time = %.03f sec.' % breakpoint_timer.interval) + + self.user_actions.append (BreakpointAction(breakpoint=bp, callback=TesterTestCase.BreakpointHit, callback_owner=self)) + self.user_actions.append (PlanCompleteAction(callback=TesterTestCase.PlanComplete, callback_owner=self)) + + if self.Launch(): + while not self.done: + self.WaitForNextProcessEvent() + else: + print "error: failed to launch process" + else: + print "error: failed to create target with '%s'" % (args[0]) + print('Total time = %.03f sec.' % total_time.interval) + + +if __name__ == '__main__': + lldb.SBDebugger.Initialize() + test = TesterTestCase() + test.Run (sys.argv[1:]) + mem = MemoryMeasurement(os.getpid()) + mem.Measure() + print str(mem) + lldb.SBDebugger.Terminate() + # print "sleeeping for 100 seconds" + # time.sleep(100) |