xref: /llvm-project/lldb/examples/python/delta.py (revision b9c1b51e45b845debb76d8658edabca70ca56079)
1#!/usr/bin/python
2
3#----------------------------------------------------------------------
4# This module will enable GDB remote packet logging when the
5# 'start_gdb_log' command is called with a filename to log to. When the
6# 'stop_gdb_log' command is called, it will disable the logging and
7# print out statistics about how long commands took to execute and also
8# will primnt ou
9# Be sure to add the python path that points to the LLDB shared library.
10#
11# To use this in the embedded python interpreter using "lldb" just
12# import it with the full path using the "command script import"
13# command. This can be done from the LLDB command line:
14#   (lldb) command script import /path/to/gdbremote.py
15# Or it can be added to your ~/.lldbinit file so this module is always
16# available.
17#----------------------------------------------------------------------
18
19import commands
20import optparse
21import os
22import shlex
23import re
24import tempfile
25
26
27def start_gdb_log(debugger, command, result, dict):
28    '''Start logging GDB remote packets by enabling logging with timestamps and
29    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
30    in order to dump out the commands.'''
31    global log_file
32    if log_file:
33        result.PutCString(
34            'error: logging is already in progress with file "%s"',
35            log_file)
36    else:
37        args_len = len(args)
38        if args_len == 0:
39            log_file = tempfile.mktemp()
40        elif len(args) == 1:
41            log_file = args[0]
42
43        if log_file:
44            debugger.HandleCommand(
45                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
46                log_file)
47            result.PutCString(
48                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
49                log_file)
50            return
51
52        result.PutCString('error: invalid log file path')
53    result.PutCString(usage)
54
55
56def parse_time_log(debugger, command, result, dict):
57    # Any commands whose names might be followed by more valid C identifier
58    # characters must be listed here
59    command_args = shlex.split(command)
60    parse_time_log_args(command_args)
61
62
63def parse_time_log_args(command_args):
64    usage = "usage: parse_time_log [options] [<LOGFILEPATH>]"
65    description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.'''
66    parser = optparse.OptionParser(
67        description=description,
68        prog='parse_time_log',
69        usage=usage)
70    parser.add_option(
71        '-v',
72        '--verbose',
73        action='store_true',
74        dest='verbose',
75        help='display verbose debug info',
76        default=False)
77    try:
78        (options, args) = parser.parse_args(command_args)
79    except:
80        return
81    for log_file in args:
82        parse_log_file(log_file, options)
83
84
85def parse_log_file(file, options):
86    '''Parse a log file that was contains timestamps. These logs are typically
87    generated using:
88    (lldb) log enable --threadsafe --timestamp --file <FILE> ....
89
90    This log file will contain timestamps and this function will then normalize
91    those packets to be relative to the first value timestamp that is found and
92    show delta times between log lines and also keep track of how long it takes
93    for GDB remote commands to make a send/receive round trip. This can be
94    handy when trying to figure out why some operation in the debugger is taking
95    a long time during a preset set of debugger commands.'''
96
97    print '#----------------------------------------------------------------------'
98    print "# Log file: '%s'" % file
99    print '#----------------------------------------------------------------------'
100
101    timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
102
103    base_time = 0.0
104    last_time = 0.0
105    file = open(file)
106    lines = file.read().splitlines()
107    for line in lines:
108        match = timestamp_regex.match(line)
109        if match:
110            curr_time = float(match.group(2))
111            delta = 0.0
112            if base_time:
113                delta = curr_time - last_time
114            else:
115                base_time = curr_time
116
117            print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3))
118            last_time = curr_time
119        else:
120            print line
121
122
123if __name__ == '__main__':
124    import sys
125    parse_time_log_args(sys.argv[1:])
126
127else:
128    import lldb
129    if lldb.debugger:
130        # This initializer is being run from LLDB in the embedded command interpreter
131        # Add any commands contained in this module to LLDB
132        lldb.debugger.HandleCommand(
133            'command script add -f delta.parse_time_log parse_time_log')
134        print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information'
135