1#!/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 15import re 16import resource 17import sys 18import time 19 20#---------------------------------------------------------------------- 21# Code that auto imports LLDB 22#---------------------------------------------------------------------- 23try: 24 # Just try for LLDB in case PYTHONPATH is already correctly setup 25 import lldb 26except ImportError: 27 lldb_python_dirs = list() 28 # lldb is not in the PYTHONPATH, try some defaults for the current platform 29 platform_system = platform.system() 30 if platform_system == 'Darwin': 31 # On Darwin, try the currently selected Xcode directory 32 xcode_dir = commands.getoutput("xcode-select --print-path") 33 if xcode_dir: 34 lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) 35 lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 36 lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 37 success = False 38 for lldb_python_dir in lldb_python_dirs: 39 if os.path.exists(lldb_python_dir): 40 if not (sys.path.__contains__(lldb_python_dir)): 41 sys.path.append(lldb_python_dir) 42 try: 43 import lldb 44 except ImportError: 45 pass 46 else: 47 print 'imported lldb from: "%s"' % (lldb_python_dir) 48 success = True 49 break 50 if not success: 51 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" 52 sys.exit(1) 53 54 55class Timer: 56 def __enter__(self): 57 self.start = time.clock() 58 return self 59 60 def __exit__(self, *args): 61 self.end = time.clock() 62 self.interval = self.end - self.start 63 64class TestCase: 65 """Class that aids in running performance tests.""" 66 def __init__(self): 67 self.verbose = False 68 self.debugger = lldb.SBDebugger.Create() 69 self.target = None 70 self.process = None 71 self.thread = None 72 self.launch_info = None 73 self.listener = self.debugger.GetListener() 74 75 def Setup(self, args): 76 self.launch_info = lldb.SBLaunchInfo(args) 77 78 def Run (self, args): 79 assert False, "performance.TestCase.Run() must be subclassed" 80 81 def Launch(self): 82 if self.target: 83 error = lldb.SBError() 84 self.process = self.target.Launch (self.launch_info, error); 85 if not error.Success(): 86 print "error: %s" % error.GetCString() 87 if self.process: 88 self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt); 89 return True 90 return False 91 92 def WaitForNextProcessEvent (self): 93 event = None 94 if self.process: 95 while event is None: 96 process_event = lldb.SBEvent() 97 if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event): 98 state = lldb.SBProcess.GetStateFromEvent (process_event) 99 if self.verbose: 100 print "event = %s" % (lldb.SBDebugger.StateAsCString(state)) 101 if lldb.SBProcess.GetRestartedFromEvent(process_event): 102 continue 103 if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited: 104 event = process_event 105 elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended: 106 continue 107 elif state == lldb.eStateStopped: 108 event = process_event 109 call_test_step = True 110 fatal = False 111 selected_thread = False 112 for thread in self.process: 113 frame = thread.GetFrameAtIndex(0) 114 select_thread = False 115 stop_reason = thread.GetStopReason(); 116 if self.verbose: 117 print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()), 118 if stop_reason == lldb.eStopReasonNone: 119 if self.verbose: 120 print "none" 121 elif stop_reason == lldb.eStopReasonTrace: 122 select_thread = True 123 if self.verbose: 124 print "trace" 125 elif stop_reason == lldb.eStopReasonPlanComplete: 126 select_thread = True 127 if self.verbose: 128 print "plan complete" 129 elif stop_reason == lldb.eStopReasonThreadExiting: 130 if self.verbose: 131 print "thread exiting" 132 elif stop_reason == lldb.eStopReasonExec: 133 if self.verbose: 134 print "exec" 135 elif stop_reason == lldb.eStopReasonInvalid: 136 if self.verbose: 137 print "invalid" 138 elif stop_reason == lldb.eStopReasonException: 139 select_thread = True 140 if self.verbose: 141 print "exception" 142 fatal = True 143 elif stop_reason == lldb.eStopReasonBreakpoint: 144 select_thread = True 145 if self.verbose: 146 print "breakpoint id = %d.%d" % (thread.GetStopReasonDataAtIndex(0),thread.GetStopReasonDataAtIndex(1)) 147 elif stop_reason == lldb.eStopReasonWatchpoint: 148 select_thread = True 149 if self.verbose: 150 print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0)) 151 elif stop_reason == lldb.eStopReasonSignal: 152 select_thread = True 153 if self.verbose: 154 print "signal %d" % (thread.GetStopReasonDataAtIndex(0)) 155 156 if select_thread and not selected_thread: 157 self.thread = thread; 158 selected_thread = self.process.SetSelectedThread(thread); 159 if fatal: 160 # if self.verbose: 161 # Xcode.RunCommand(self.debugger,"bt all",true); 162 sys.exit(1); 163 return event 164 165class Measurement: 166 '''A class that encapsulates a measurement''' 167 def Measure(self): 168 assert False, "performance.Measurement.Measure() must be subclassed" 169 170class MemoryMeasurement(Measurement): 171 '''A class that can measure memory statistics for a process.''' 172 def __init__(self, pid): 173 self.pid = pid 174 self.stats = ["rprvt","rshrd","rsize","vsize","vprvt","kprvt","kshrd","faults","cow","pageins"] 175 self.command = "top -l 1 -pid %u -stats %s" % (self.pid, ",".join(self.stats)) 176 self.value = dict() 177 178 def Measure(self): 179 output = commands.getoutput(self.command).split("\n")[-1] 180 values = re.split('[-+\s]+', output) 181 for (idx, stat) in enumerate(values): 182 multiplier = 1 183 if stat: 184 if stat[-1] == 'K': 185 multiplier = 1024; 186 stat = stat[:-1] 187 elif stat[-1] == 'M': 188 multiplier = 1024*1024; 189 stat = stat[:-1] 190 elif stat[-1] == 'G': 191 multiplier = 1024*1024*1024; 192 elif stat[-1] == 'T': 193 multiplier = 1024*1024*1024*1024; 194 stat = stat[:-1] 195 self.value[self.stats[idx]] = int (stat) * multiplier 196 197 def __str__(self): 198 '''Dump the MemoryMeasurement current value''' 199 s = '' 200 for key in self.value.keys(): 201 if s: 202 s += "\n" 203 s += "%8s = %s" % (key, self.value[key]) 204 return s 205 206 207class TesterTestCase(TestCase): 208 209 def Run (self, args): 210 self.Setup(args) 211 self.verbose = True 212 #self.breakpoints = { 'name' : { 'main' } : , 'malloc' {} 213 with Timer() as total_time: 214 self.target = self.debugger.CreateTarget(args[0]) 215 if self.target: 216 with Timer() as breakpoint_timer: 217 self.target.BreakpointCreateByName("main") 218 print('Breakpoint time = %.03f sec.' % breakpoint_timer.interval) 219 if self.Launch(): 220 self.WaitForNextProcessEvent(); 221 self.process.Kill() 222 else: 223 print "error: failed to launch process" 224 else: 225 print "error: failed to create target with '%s'" % (args[0]) 226 print('Total time = %.03f sec.' % total_time.interval) 227 228 229if __name__ == '__main__': 230 lldb.SBDebugger.Initialize() 231 test = TesterTestCase() 232 test.Run (sys.argv[1:]) 233 mem = MemoryMeasurement(os.getpid()) 234 mem.Measure() 235 print str(mem) 236 lldb.SBDebugger.Terminate() 237 # print "sleeeping for 100 seconds" 238 # time.sleep(100) 239