|  | #!/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()) |