xref: /openbmc/qemu/scripts/kvm/kvm_flightrecorder (revision a9a5c473)
1#!/usr/bin/env python3
2#
3# KVM Flight Recorder - ring buffer tracing script
4#
5# Copyright (C) 2012 IBM Corp
6#
7# Author: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
8#
9# This script provides a command-line interface to kvm ftrace and is designed
10# to be used as a flight recorder that is always running.  To start in-memory
11# recording:
12#
13# sudo kvm_flightrecorder start 8192  # 8 MB per-cpu ring buffers
14#
15# The per-cpu ring buffer size can be given in KB as an optional argument to
16# the 'start' subcommand.
17#
18# To stop the flight recorder:
19#
20# sudo kvm_flightrecorder stop
21#
22# To dump the contents of the flight recorder (this can be done when the
23# recorder is stopped or while it is running):
24#
25# sudo kvm_flightrecorder dump >/path/to/dump.txt
26#
27# To observe the trace while it is running, use the 'tail' subcommand:
28#
29# sudo kvm_flightrecorder tail
30#
31# Note that the flight recorder may impact overall system performance by
32# consuming CPU cycles.  No disk I/O is performed since the ring buffer holds a
33# fixed-size in-memory trace.
34
35import sys
36import os
37
38tracing_dir = '/sys/kernel/debug/tracing'
39
40def trace_path(*args):
41    return os.path.join(tracing_dir, *args)
42
43def write_file(path, data):
44    open(path, 'wb').write(data)
45
46def enable_event(subsystem, event, enable):
47    write_file(trace_path('events', subsystem, event, 'enable'), '1' if enable else '0')
48
49def enable_subsystem(subsystem, enable):
50    write_file(trace_path('events', subsystem, 'enable'), '1' if enable else '0')
51
52def start_tracing():
53    enable_subsystem('kvm', True)
54    write_file(trace_path('tracing_on'), '1')
55
56def stop_tracing():
57    write_file(trace_path('tracing_on'), '0')
58    enable_subsystem('kvm', False)
59    write_file(trace_path('events', 'enable'), '0')
60    write_file(trace_path('current_tracer'), 'nop')
61
62def dump_trace():
63    tracefile = open(trace_path('trace'), 'r')
64    try:
65        lines = True
66        while lines:
67            lines = tracefile.readlines(64 * 1024)
68            sys.stdout.writelines(lines)
69    except KeyboardInterrupt:
70        pass
71
72def tail_trace():
73    try:
74        for line in open(trace_path('trace_pipe'), 'r'):
75            sys.stdout.write(line)
76    except KeyboardInterrupt:
77        pass
78
79def usage():
80    print('Usage: %s start [buffer_size_kb] | stop | dump | tail' % sys.argv[0])
81    print('Control the KVM flight recorder tracing.')
82    sys.exit(0)
83
84def main():
85    if len(sys.argv) < 2:
86        usage()
87
88    cmd = sys.argv[1]
89    if cmd == '--version':
90        print('kvm_flightrecorder version 1.0')
91        sys.exit(0)
92
93    if not os.path.isdir(tracing_dir):
94        print('Unable to tracing debugfs directory, try:')
95        print('mount -t debugfs none /sys/kernel/debug')
96        sys.exit(1)
97    if not os.access(tracing_dir, os.W_OK):
98        print('Unable to write to tracing debugfs directory, please run as root')
99        sys.exit(1)
100
101    if cmd == 'start':
102        stop_tracing() # clean up first
103
104        if len(sys.argv) == 3:
105            try:
106                buffer_size_kb = int(sys.argv[2])
107            except ValueError:
108                print('Invalid per-cpu trace buffer size in KB')
109                sys.exit(1)
110            write_file(trace_path('buffer_size_kb'), str(buffer_size_kb))
111            print('Per-CPU ring buffer size set to %d KB' % buffer_size_kb)
112
113        start_tracing()
114        print('KVM flight recorder enabled')
115    elif cmd == 'stop':
116        stop_tracing()
117        print('KVM flight recorder disabled')
118    elif cmd == 'dump':
119        dump_trace()
120    elif cmd == 'tail':
121        tail_trace()
122    else:
123        usage()
124
125if __name__ == '__main__':
126    sys.exit(main())
127