diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py index 7776a6f5e147..1b963dab1c47 100755 --- a/tools/biolatpcts.py +++ b/tools/biolatpcts.py @@ -15,21 +15,31 @@ from __future__ import print_function from bcc import BPF from time import sleep +from threading import Event import argparse import json import sys import os +import signal description = """ Monitor IO latency distribution of a block device """ -parser = argparse.ArgumentParser(description = description, +epilog = """ +When interval is infinite, biolatpcts will print out result once the +initialization is complete to indicate readiness. Once initialized, +biolatpcts will output whenever it receives SIGUSR1 and before exiting on +SIGINT, SIGTERM or SIGHUP. This can be used to obtain latency distribution +between two events. +""" + +parser = argparse.ArgumentParser(description = description, epilog = epilog, formatter_class = argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('dev', metavar='DEV', type=str, help='Target block device (/dev/DEVNAME, DEVNAME or MAJ:MIN)') parser.add_argument('-i', '--interval', type=int, default=3, - help='Report interval') + help='Report interval (0: exit after startup, -1: infinite)') parser.add_argument('-w', '--which', choices=['from-rq-alloc', 'after-rq-alloc', 'on-device'], default='on-device', help='Which latency to measure') parser.add_argument('-p', '--pcts', metavar='PCT,...', type=str, @@ -206,8 +216,28 @@ def format_usec(lat): if args.interval == 0: sys.exit(0) -while True: - sleep(args.interval) +# Set up signal handling so that we print the result on USR1 and before +# exiting on a signal. Combined with infinite interval, this can be used to +# obtain overall latency distribution between two events. +keep_running = True +result_req = Event() +def sig_handler(sig, frame): + global keep_running, result_req + if sig != signal.SIGUSR1: + keep_running = False + result_req.set() + +for sig in (signal.SIGUSR1, signal.SIGINT, signal.SIGTERM, signal.SIGHUP): + signal.signal(sig, sig_handler) + +# If infinite interval, always trigger the first output so that the caller +# can tell when initialization is complete. +if args.interval < 0: + result_req.set(); + +while keep_running: + result_req.wait(args.interval if args.interval > 0 else None) + result_req.clear() rwdf_total = [0] * 4;