1*434283fdSDevin Teske# -*- tab-width: 4 -*- ;; Emacs 2*434283fdSDevin Teske# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM 3*434283fdSDevin Teske############################################################ IDENT(1) 4*434283fdSDevin Teske# 5*434283fdSDevin Teske# $Title: dwatch(8) module for dtrace_lockstat(4) contention $ 6*434283fdSDevin Teske# $Copyright: 2026 Devin Teske. All rights reserved. $ 7*434283fdSDevin Teske# 8*434283fdSDevin Teske############################################################ DESCRIPTION 9*434283fdSDevin Teske# 10*434283fdSDevin Teske# Print kernel lock contention events reported by dtrace_lockstat(4), 11*434283fdSDevin Teske# naming the lock, the thread held-off by it, and for how long. Answers 12*434283fdSDevin Teske# "the system is slow -- where is it fighting over locks?" The default 13*434283fdSDevin Teske# profile watches block events (thread went off-CPU waiting); lock-spin 14*434283fdSDevin Teske# watches spin events instead. Contention shorter than a threshold is 15*434283fdSDevin Teske# suppressed (default 1 ms; tunable via DWATCH_LOCK_MS in the environment, 16*434283fdSDevin Teske# 0 to show everything). 17*434283fdSDevin Teske# 18*434283fdSDevin Teske############################################################ PROBE 19*434283fdSDevin Teske 20*434283fdSDevin Teskecase "$PROFILE" in 21*434283fdSDevin Teskelock|lock-block) 22*434283fdSDevin Teske : ${PROBE:=$( echo \ 23*434283fdSDevin Teske lockstat:::adaptive-block, \ 24*434283fdSDevin Teske lockstat:::lockmgr-block, \ 25*434283fdSDevin Teske lockstat:::rw-block, \ 26*434283fdSDevin Teske lockstat:::sx-block )} ;; 27*434283fdSDevin Teskelock-spin) 28*434283fdSDevin Teske : ${PROBE:=$( echo \ 29*434283fdSDevin Teske lockstat:::adaptive-spin, \ 30*434283fdSDevin Teske lockstat:::rw-spin, \ 31*434283fdSDevin Teske lockstat:::spin-spin, \ 32*434283fdSDevin Teske lockstat:::sx-spin, \ 33*434283fdSDevin Teske lockstat:::thread-spin )} ;; 34*434283fdSDevin Teskelock-adaptive) 35*434283fdSDevin Teske : ${PROBE:=lockstat:::adaptive-block, lockstat:::adaptive-spin} ;; 36*434283fdSDevin Teskelock-lockmgr) 37*434283fdSDevin Teske : ${PROBE:=lockstat:::lockmgr-block} ;; 38*434283fdSDevin Teskelock-rw) 39*434283fdSDevin Teske : ${PROBE:=lockstat:::rw-block, lockstat:::rw-spin} ;; 40*434283fdSDevin Teskelock-sx) 41*434283fdSDevin Teske : ${PROBE:=lockstat:::sx-block, lockstat:::sx-spin} ;; 42*434283fdSDevin Teskelock-thread) 43*434283fdSDevin Teske : ${PROBE:=lockstat:::thread-spin} ;; 44*434283fdSDevin Teske*) 45*434283fdSDevin Teske : ${PROBE:=lockstat:::${PROFILE#lock-}} 46*434283fdSDevin Teskeesac 47*434283fdSDevin Teske 48*434283fdSDevin Teske############################################################ EVENT ACTION 49*434283fdSDevin Teske 50*434283fdSDevin Teske: ${DWATCH_LOCK_MS:=1} 51*434283fdSDevin Teske 52*434283fdSDevin Teskecase "$DWATCH_LOCK_MS" in 53*434283fdSDevin Teske""|*[!0-9]*) die "DWATCH_LOCK_MS must be a number" ;; # NOTREACHED 54*434283fdSDevin Teskeesac 55*434283fdSDevin Teske 56*434283fdSDevin Teske[ "$CUSTOM_TEST" ] || 57*434283fdSDevin Teske EVENT_TEST="(int64_t)arg1 >= (int64_t)$DWATCH_LOCK_MS * 1000000" 58*434283fdSDevin Teske 59*434283fdSDevin Teske############################################################ ACTIONS 60*434283fdSDevin Teske 61*434283fdSDevin Teskeexec 9<<EOF 62*434283fdSDevin Teskethis string lock_class; 63*434283fdSDevin Teskethis string lock_how; 64*434283fdSDevin Teskethis string lock_name; 65*434283fdSDevin Teskethis string lock_verb; 66*434283fdSDevin Teske 67*434283fdSDevin Teske/* 68*434283fdSDevin Teske * Lock classes from sys/lock.h as-witnessed by dtrace_lockstat(4) 69*434283fdSDevin Teske */ 70*434283fdSDevin Teskeinline string lockstat_class[string name] = 71*434283fdSDevin Teske name == "adaptive-block" ? "mtx" : 72*434283fdSDevin Teske name == "adaptive-spin" ? "mtx" : 73*434283fdSDevin Teske name == "lockmgr-block" ? "lockmgr" : 74*434283fdSDevin Teske name == "rw-block" ? "rw" : 75*434283fdSDevin Teske name == "rw-spin" ? "rw" : 76*434283fdSDevin Teske name == "spin-spin" ? "spin mtx" : 77*434283fdSDevin Teske name == "sx-block" ? "sx" : 78*434283fdSDevin Teske name == "sx-spin" ? "sx" : 79*434283fdSDevin Teske name == "thread-spin" ? "thread" : 80*434283fdSDevin Teske name; 81*434283fdSDevin Teske 82*434283fdSDevin Teskeinline string lockstat_verb[string name] = 83*434283fdSDevin Teske name == "adaptive-block" ? "blocked" : 84*434283fdSDevin Teske name == "lockmgr-block" ? "blocked" : 85*434283fdSDevin Teske name == "rw-block" ? "blocked" : 86*434283fdSDevin Teske name == "sx-block" ? "blocked" : 87*434283fdSDevin Teske "spun"; 88*434283fdSDevin Teske 89*434283fdSDevin Teske$PROBE /* probe ID $ID */ 90*434283fdSDevin Teske{${TRACE:+ 91*434283fdSDevin Teske printf("<$ID>"); 92*434283fdSDevin Teske} 93*434283fdSDevin Teske /* 94*434283fdSDevin Teske * struct lock_object * (first member of every kernel lock) 95*434283fdSDevin Teske */ 96*434283fdSDevin Teske this->lock_name = 97*434283fdSDevin Teske stringof(((struct lock_object *)arg0)->lo_name); 98*434283fdSDevin Teske this->lock_class = lockstat_class[probename]; 99*434283fdSDevin Teske this->lock_verb = lockstat_verb[probename]; 100*434283fdSDevin Teske this->lock_how = ""; 101*434283fdSDevin Teske} 102*434283fdSDevin Teske 103*434283fdSDevin Teskelockstat:::lockmgr-block, 104*434283fdSDevin Teskelockstat:::rw-block, 105*434283fdSDevin Teskelockstat:::sx-block /* probe ID $(( $ID + 1 )) */ 106*434283fdSDevin Teske{${TRACE:+ 107*434283fdSDevin Teske printf("<$(( $ID + 1 ))>"); 108*434283fdSDevin Teske} 109*434283fdSDevin Teske /* arg2 is 0 when acquiring as writer, 1 as reader */ 110*434283fdSDevin Teske this->lock_how = arg2 == 0 ? " as writer" : " as reader"; 111*434283fdSDevin Teske} 112*434283fdSDevin TeskeEOF 113*434283fdSDevin TeskeACTIONS=$( cat <&9 ) 114*434283fdSDevin TeskeID=$(( $ID + 2 )) 115*434283fdSDevin Teske 116*434283fdSDevin Teske############################################################ EVENT DETAILS 117*434283fdSDevin Teske 118*434283fdSDevin Teskeif [ ! "$CUSTOM_DETAILS" ]; then 119*434283fdSDevin Teskeexec 9<<EOF 120*434283fdSDevin Teske /* 121*434283fdSDevin Teske * Print lock contention details 122*434283fdSDevin Teske */ 123*434283fdSDevin Teske printf("%s %d.%03d ms on %s \"%s\"%s", 124*434283fdSDevin Teske this->lock_verb, 125*434283fdSDevin Teske (int64_t)arg1 / 1000000, 126*434283fdSDevin Teske ((int64_t)arg1 % 1000000) / 1000, 127*434283fdSDevin Teske this->lock_class, 128*434283fdSDevin Teske this->lock_name, 129*434283fdSDevin Teske this->lock_how); 130*434283fdSDevin TeskeEOF 131*434283fdSDevin TeskeEVENT_DETAILS=$( cat <&9 ) 132*434283fdSDevin Teskefi 133*434283fdSDevin Teske 134*434283fdSDevin Teske################################################################################ 135*434283fdSDevin Teske# END 136*434283fdSDevin Teske################################################################################ 137