xref: /llvm-project/lldb/examples/python/performance.py (revision 2d95f357486dd9bd688ac16ceded159db2d7c1cd)
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