1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# 3*387f9dfdSAndroid Build Coastguard Worker# dbstat Display a histogram of MySQL and PostgreSQL query latencies. 4*387f9dfdSAndroid Build Coastguard Worker# 5*387f9dfdSAndroid Build Coastguard Worker# USAGE: dbstat [-v] [-p PID [PID ...]] [-m THRESHOLD] [-u] 6*387f9dfdSAndroid Build Coastguard Worker# [-i INTERVAL] {mysql,postgres} 7*387f9dfdSAndroid Build Coastguard Worker# 8*387f9dfdSAndroid Build Coastguard Worker# This tool uses USDT probes, which means it needs MySQL and PostgreSQL built 9*387f9dfdSAndroid Build Coastguard Worker# with USDT (DTrace) support. 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# Copyright 2017, Sasha Goldshtein 12*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# 15-Feb-2017 Sasha Goldshtein Created this. 15*387f9dfdSAndroid Build Coastguard Worker 16*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT 17*387f9dfdSAndroid Build Coastguard Workerimport argparse 18*387f9dfdSAndroid Build Coastguard Workerimport subprocess 19*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 20*387f9dfdSAndroid Build Coastguard Worker 21*387f9dfdSAndroid Build Coastguard Workerexamples = """ 22*387f9dfdSAndroid Build Coastguard Worker dbstat postgres # display a histogram of PostgreSQL query latencies 23*387f9dfdSAndroid Build Coastguard Worker dbstat mysql -v # display MySQL latencies and print the BPF program 24*387f9dfdSAndroid Build Coastguard Worker dbstat mysql -u # display query latencies in microseconds (default: ms) 25*387f9dfdSAndroid Build Coastguard Worker dbstat mysql -m 5 # trace only queries slower than 5ms 26*387f9dfdSAndroid Build Coastguard Worker dbstat mysql -p 408 # trace queries in a specific process 27*387f9dfdSAndroid Build Coastguard Worker""" 28*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 29*387f9dfdSAndroid Build Coastguard Worker description="", 30*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 31*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true", 33*387f9dfdSAndroid Build Coastguard Worker help="print the BPF program") 34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("db", choices=["mysql", "postgres"], 35*387f9dfdSAndroid Build Coastguard Worker help="the database engine to use") 36*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", type=int, nargs='*', 37*387f9dfdSAndroid Build Coastguard Worker dest="pids", metavar="PID", help="the pid(s) to trace") 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-m", "--threshold", type=int, default=0, 39*387f9dfdSAndroid Build Coastguard Worker help="trace queries slower than this threshold (ms)") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-u", "--microseconds", action="store_true", 41*387f9dfdSAndroid Build Coastguard Worker help="display query latencies in microseconds (default: milliseconds)") 42*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-i", "--interval", type=int, default=99999999, 43*387f9dfdSAndroid Build Coastguard Worker help="print summary at this interval (seconds)") 44*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 45*387f9dfdSAndroid Build Coastguard Worker 46*387f9dfdSAndroid Build Coastguard Workerif not args.pids or len(args.pids) == 0: 47*387f9dfdSAndroid Build Coastguard Worker if args.db == "mysql": 48*387f9dfdSAndroid Build Coastguard Worker args.pids = map(int, subprocess.check_output( 49*387f9dfdSAndroid Build Coastguard Worker "pidof mysqld".split()).split()) 50*387f9dfdSAndroid Build Coastguard Worker elif args.db == "postgres": 51*387f9dfdSAndroid Build Coastguard Worker args.pids = map(int, subprocess.check_output( 52*387f9dfdSAndroid Build Coastguard Worker "pidof postgres".split()).split()) 53*387f9dfdSAndroid Build Coastguard Worker 54*387f9dfdSAndroid Build Coastguard Workerprogram = """ 55*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 56*387f9dfdSAndroid Build Coastguard Worker 57*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(temp, u64, u64); 58*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(latency); 59*387f9dfdSAndroid Build Coastguard Worker 60*387f9dfdSAndroid Build Coastguard Workerint probe_start(struct pt_regs *ctx) { 61*387f9dfdSAndroid Build Coastguard Worker u64 timestamp = bpf_ktime_get_ns(); 62*387f9dfdSAndroid Build Coastguard Worker u64 pid = bpf_get_current_pid_tgid(); 63*387f9dfdSAndroid Build Coastguard Worker temp.update(&pid, ×tamp); 64*387f9dfdSAndroid Build Coastguard Worker return 0; 65*387f9dfdSAndroid Build Coastguard Worker} 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Workerint probe_end(struct pt_regs *ctx) { 68*387f9dfdSAndroid Build Coastguard Worker u64 *timestampp; 69*387f9dfdSAndroid Build Coastguard Worker u64 pid = bpf_get_current_pid_tgid(); 70*387f9dfdSAndroid Build Coastguard Worker timestampp = temp.lookup(&pid); 71*387f9dfdSAndroid Build Coastguard Worker if (!timestampp) 72*387f9dfdSAndroid Build Coastguard Worker return 0; 73*387f9dfdSAndroid Build Coastguard Worker 74*387f9dfdSAndroid Build Coastguard Worker u64 delta = bpf_ktime_get_ns() - *timestampp; 75*387f9dfdSAndroid Build Coastguard Worker FILTER 76*387f9dfdSAndroid Build Coastguard Worker delta /= SCALE; 77*387f9dfdSAndroid Build Coastguard Worker latency.atomic_increment(bpf_log2l(delta)); 78*387f9dfdSAndroid Build Coastguard Worker temp.delete(&pid); 79*387f9dfdSAndroid Build Coastguard Worker return 0; 80*387f9dfdSAndroid Build Coastguard Worker} 81*387f9dfdSAndroid Build Coastguard Worker""" 82*387f9dfdSAndroid Build Coastguard Workerprogram = program.replace("SCALE", str(1000 if args.microseconds else 1000000)) 83*387f9dfdSAndroid Build Coastguard Workerprogram = program.replace("FILTER", "" if args.threshold == 0 else 84*387f9dfdSAndroid Build Coastguard Worker "if (delta / 1000000 < %d) { return 0; }" % args.threshold) 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Workerusdts = list(map(lambda pid: USDT(pid=pid), args.pids)) 87*387f9dfdSAndroid Build Coastguard Workerfor usdt in usdts: 88*387f9dfdSAndroid Build Coastguard Worker usdt.enable_probe("query__start", "probe_start") 89*387f9dfdSAndroid Build Coastguard Worker usdt.enable_probe("query__done", "probe_end") 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Workerif args.verbose: 92*387f9dfdSAndroid Build Coastguard Worker print('\n'.join(map(lambda u: u.get_text(), usdts))) 93*387f9dfdSAndroid Build Coastguard Worker print(program) 94*387f9dfdSAndroid Build Coastguard Worker 95*387f9dfdSAndroid Build Coastguard Workerbpf = BPF(text=program, usdt_contexts=usdts) 96*387f9dfdSAndroid Build Coastguard Worker 97*387f9dfdSAndroid Build Coastguard Workerprint("Tracing database queries for pids %s slower than %d ms..." % 98*387f9dfdSAndroid Build Coastguard Worker (', '.join(map(str, args.pids)), args.threshold)) 99*387f9dfdSAndroid Build Coastguard Worker 100*387f9dfdSAndroid Build Coastguard Workerlatencies = bpf["latency"] 101*387f9dfdSAndroid Build Coastguard Worker 102*387f9dfdSAndroid Build Coastguard Workerdef print_hist(): 103*387f9dfdSAndroid Build Coastguard Worker print("[%s]" % strftime("%H:%M:%S")) 104*387f9dfdSAndroid Build Coastguard Worker latencies.print_log2_hist("query latency (%s)" % 105*387f9dfdSAndroid Build Coastguard Worker ("us" if args.microseconds else "ms")) 106*387f9dfdSAndroid Build Coastguard Worker print("") 107*387f9dfdSAndroid Build Coastguard Worker latencies.clear() 108*387f9dfdSAndroid Build Coastguard Worker 109*387f9dfdSAndroid Build Coastguard Workerwhile True: 110*387f9dfdSAndroid Build Coastguard Worker try: 111*387f9dfdSAndroid Build Coastguard Worker sleep(args.interval) 112*387f9dfdSAndroid Build Coastguard Worker print_hist() 113*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 114*387f9dfdSAndroid Build Coastguard Worker print_hist() 115*387f9dfdSAndroid Build Coastguard Worker break 116