| #!/usr/bin/env python3 | |
| # | |
| # KVM Flight Recorder - ring buffer tracing script | |
| # | |
| # Copyright (C) 2012 IBM Corp | |
| # | |
| # Author: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> | |
| # | |
| # This script provides a command-line interface to kvm ftrace and is designed | |
| # to be used as a flight recorder that is always running. To start in-memory | |
| # recording: | |
| # | |
| # sudo kvm_flightrecorder start 8192 # 8 MB per-cpu ring buffers | |
| # | |
| # The per-cpu ring buffer size can be given in KB as an optional argument to | |
| # the 'start' subcommand. | |
| # | |
| # To stop the flight recorder: | |
| # | |
| # sudo kvm_flightrecorder stop | |
| # | |
| # To dump the contents of the flight recorder (this can be done when the | |
| # recorder is stopped or while it is running): | |
| # | |
| # sudo kvm_flightrecorder dump >/path/to/dump.txt | |
| # | |
| # To observe the trace while it is running, use the 'tail' subcommand: | |
| # | |
| # sudo kvm_flightrecorder tail | |
| # | |
| # Note that the flight recorder may impact overall system performance by | |
| # consuming CPU cycles. No disk I/O is performed since the ring buffer holds a | |
| # fixed-size in-memory trace. | |
| import sys | |
| import os | |
| tracing_dir = '/sys/kernel/debug/tracing' | |
| def trace_path(*args): | |
| return os.path.join(tracing_dir, *args) | |
| def write_file(path, data): | |
| open(path, 'wb').write(data) | |
| def enable_event(subsystem, event, enable): | |
| write_file(trace_path('events', subsystem, event, 'enable'), '1' if enable else '0') | |
| def enable_subsystem(subsystem, enable): | |
| write_file(trace_path('events', subsystem, 'enable'), '1' if enable else '0') | |
| def start_tracing(): | |
| enable_subsystem('kvm', True) | |
| write_file(trace_path('tracing_on'), '1') | |
| def stop_tracing(): | |
| write_file(trace_path('tracing_on'), '0') | |
| enable_subsystem('kvm', False) | |
| write_file(trace_path('events', 'enable'), '0') | |
| write_file(trace_path('current_tracer'), 'nop') | |
| def dump_trace(): | |
| tracefile = open(trace_path('trace'), 'r') | |
| try: | |
| lines = True | |
| while lines: | |
| lines = tracefile.readlines(64 * 1024) | |
| sys.stdout.writelines(lines) | |
| except KeyboardInterrupt: | |
| pass | |
| def tail_trace(): | |
| try: | |
| for line in open(trace_path('trace_pipe'), 'r'): | |
| sys.stdout.write(line) | |
| except KeyboardInterrupt: | |
| pass | |
| def usage(): | |
| print('Usage: %s start [buffer_size_kb] | stop | dump | tail' % sys.argv[0]) | |
| print('Control the KVM flight recorder tracing.') | |
| sys.exit(0) | |
| def main(): | |
| if len(sys.argv) < 2: | |
| usage() | |
| cmd = sys.argv[1] | |
| if cmd == '--version': | |
| print('kvm_flightrecorder version 1.0') | |
| sys.exit(0) | |
| if not os.path.isdir(tracing_dir): | |
| print('Unable to tracing debugfs directory, try:') | |
| print('mount -t debugfs none /sys/kernel/debug') | |
| sys.exit(1) | |
| if not os.access(tracing_dir, os.W_OK): | |
| print('Unable to write to tracing debugfs directory, please run as root') | |
| sys.exit(1) | |
| if cmd == 'start': | |
| stop_tracing() # clean up first | |
| if len(sys.argv) == 3: | |
| try: | |
| buffer_size_kb = int(sys.argv[2]) | |
| except ValueError: | |
| print('Invalid per-cpu trace buffer size in KB') | |
| sys.exit(1) | |
| write_file(trace_path('buffer_size_kb'), str(buffer_size_kb)) | |
| print('Per-CPU ring buffer size set to %d KB' % buffer_size_kb) | |
| start_tracing() | |
| print('KVM flight recorder enabled') | |
| elif cmd == 'stop': | |
| stop_tracing() | |
| print('KVM flight recorder disabled') | |
| elif cmd == 'dump': | |
| dump_trace() | |
| elif cmd == 'tail': | |
| tail_trace() | |
| else: | |
| usage() | |
| if __name__ == '__main__': | |
| sys.exit(main()) |