1"""Disassemble lldb's Driver::MainLoop() functions comparing lldb against gdb."""
2
3import os, sys
4import unittest2
5import lldb
6import pexpect
7from lldbbench import *
8
9def is_exe(fpath):
10    """Returns true if fpath is an executable."""
11    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
12
13class DisassembleDriverMainLoop(BenchBase):
14
15    mydir = os.path.join("benchmarks", "disassembly")
16
17    def setUp(self):
18        """
19        Note that lldbExec can be specified with the LLDB_EXEC env variable (see
20        dotest.py), and gdbExec can be specified with the GDB_EXEC env variable.
21        This provides a flexibility in specifying different versions of gdb for
22        comparison purposes.
23        """
24        BenchBase.setUp(self)
25        # If env var GDB_EXEC is specified, use it; otherwise, use gdb in your
26        # PATH env var.
27        if "GDB_EXEC" in os.environ and is_exe(os.environ["GDB_EXEC"]):
28            self.gdbExec = os.environ["GDB_EXEC"]
29        else:
30            self.gdbExec = "gdb"
31
32        self.exe = self.lldbHere
33        self.function = 'Driver::MainLoop()'
34        self.lldb_avg = None
35        self.gdb_avg = None
36        self.count = lldb.bmIterationCount
37        if self.count <= 0:
38            self.count = 5
39
40    @benchmarks_test
41    def test_run_lldb_then_gdb(self):
42        """Test disassembly on a large function with lldb vs. gdb."""
43        print
44        print "lldb path: %s" % self.lldbExec
45        print "gdb path: %s" % self.gdbExec
46
47        print
48        self.run_lldb_disassembly(self.exe, self.function, self.count)
49        print "lldb benchmark:", self.stopwatch
50        self.run_gdb_disassembly(self.exe, self.function, self.count)
51        print "gdb benchmark:", self.stopwatch
52        print "lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)
53
54    @benchmarks_test
55    def test_run_gdb_then_lldb(self):
56        """Test disassembly on a large function with lldb vs. gdb."""
57        print
58        print "lldb path: %s" % self.lldbExec
59        print "gdb path: %s" % self.gdbExec
60
61        print
62        self.run_gdb_disassembly(self.exe, self.function, self.count)
63        print "gdb benchmark:", self.stopwatch
64        self.run_lldb_disassembly(self.exe, self.function, self.count)
65        print "lldb benchmark:", self.stopwatch
66        print "lldb_avg/gdb_avg: %f" % (self.lldb_avg/self.gdb_avg)
67
68    def run_lldb_disassembly(self, exe, function, count):
69        # Set self.child_prompt, which is "(lldb) ".
70        self.child_prompt = '(lldb) '
71        prompt = self.child_prompt
72
73        # So that the child gets torn down after the test.
74        self.child = pexpect.spawn('%s %s %s' % (self.lldbExec, self.lldbOption, exe))
75        child = self.child
76
77        # Turn on logging for what the child sends back.
78        if self.TraceOn():
79            child.logfile_read = sys.stdout
80
81        child.expect_exact(prompt)
82        child.sendline('breakpoint set -F %s' % function)
83        child.expect_exact(prompt)
84        child.sendline('run')
85        child.expect_exact(prompt)
86
87        # Reset the stopwatch now.
88        self.stopwatch.reset()
89        for i in range(count):
90            with self.stopwatch:
91                # Disassemble the function.
92                child.sendline('disassemble -f')
93                child.expect_exact(prompt)
94            child.sendline('next')
95            child.expect_exact(prompt)
96
97        child.sendline('quit')
98        try:
99            self.child.expect(pexpect.EOF)
100        except:
101            pass
102
103        self.lldb_avg = self.stopwatch.avg()
104        if self.TraceOn():
105            print "lldb disassembly benchmark:", str(self.stopwatch)
106        self.child = None
107
108    def run_gdb_disassembly(self, exe, function, count):
109        # Set self.child_prompt, which is "(gdb) ".
110        self.child_prompt = '(gdb) '
111        prompt = self.child_prompt
112
113        # So that the child gets torn down after the test.
114        self.child = pexpect.spawn('%s --nx %s' % (self.gdbExec, exe))
115        child = self.child
116
117        # Turn on logging for what the child sends back.
118        if self.TraceOn():
119            child.logfile_read = sys.stdout
120
121        child.expect_exact(prompt)
122        child.sendline('break %s' % function)
123        child.expect_exact(prompt)
124        child.sendline('run')
125        child.expect_exact(prompt)
126
127        # Reset the stopwatch now.
128        self.stopwatch.reset()
129        for i in range(count):
130            with self.stopwatch:
131                # Disassemble the function.
132                child.sendline('disassemble')
133                child.expect_exact(prompt)
134            child.sendline('next')
135            child.expect_exact(prompt)
136
137        child.sendline('quit')
138        child.expect_exact('The program is running.  Exit anyway?')
139        child.sendline('y')
140        try:
141            self.child.expect(pexpect.EOF)
142        except:
143            pass
144
145        self.gdb_avg = self.stopwatch.avg()
146        if self.TraceOn():
147            print "gdb disassembly benchmark:", str(self.stopwatch)
148        self.child = None
149
150
151if __name__ == '__main__':
152    import atexit
153    lldb.SBDebugger.Initialize()
154    atexit.register(lambda: lldb.SBDebugger.Terminate())
155    unittest2.main()
156