xref: /freebsd/cddl/usr.sbin/dwatch/libexec/lock (revision 434283fda99e89af20c3fe95fde427624ae96d04)
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