1# -*- tab-width: 4 -*- ;; Emacs 2# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM 3############################################################ IDENT(1) 4# 5# $Title: dwatch(8) module for malloc(9) type activity $ 6# $Copyright: 2026 Devin Teske. All rights reserved. $ 7# 8############################################################ DESCRIPTION 9# 10# Print kernel malloc(9) and free(9) activity by malloc type, via the 11# dtmalloc provider (one malloc and one free probe per type; see 12# vmstat -m for the types). The default profile prints allocations and 13# frees meeting a size threshold (default 65536 bytes; tunable via 14# DWATCH_MALLOC_MIN in the environment, 0 to show everything), 15# answering "who is allocating huge kernel buffers?" Use 16# dtmalloc-NAME to watch a single type (e.g., dtmalloc-devbuf). 17# The dtmalloc-top profile maintains a running catalog, updated every 18# 3 seconds, of net bytes and outstanding allocation balance by type: 19# a type whose net bytes climb without bound while the system is in 20# steady state is a leak suspect. NB: the catalog reflects activity 21# since the watch began, not preexisting allocations, and caches 22# legitimately hold what they allocate. 23# 24############################################################ PRAGMAS 25 26case "$PROFILE" in 27dtmalloc-top) 28 DTRACE_PRAGMA=" 29 option quiet 30 option aggsortrev 31 " # END-QUOTE 32 ;; 33esac 34 35############################################################ PROBE 36 37case "$PROFILE" in 38dtmalloc) 39 : ${PROBE:=dtmalloc:::malloc, dtmalloc:::free} ;; 40dtmalloc-top) 41 : ${PROBE:=profile:::tick-3s} ;; 42*) 43 : ${PROBE:=$( echo \ 44 dtmalloc::${PROFILE#dtmalloc-}:malloc, \ 45 dtmalloc::${PROFILE#dtmalloc-}:free )} ;; 46esac 47 48############################################################ EVENT ACTION 49 50: ${DWATCH_MALLOC_MIN:=65536} 51 52case "$DWATCH_MALLOC_MIN" in 53""|*[!0-9]*) die "DWATCH_MALLOC_MIN must be a number" ;; # NOTREACHED 54esac 55 56[ "$CUSTOM_TEST" ] || case "$PROFILE" in 57dtmalloc-top) ;; 58*) EVENT_TEST="(uint64_t)arg3 >= $DWATCH_MALLOC_MIN" 59esac 60 61############################################################ ACTIONS 62 63if [ "$PROFILE" = "dtmalloc-top" ]; then 64exec 9<<EOF 65this int64_t dtmalloc_delta; 66 67BEGIN { printf("Cataloging malloc(9) activity ...") } /* probe ID $ID */ 68 69dtmalloc:::malloc /* probe ID $(( $ID + 1 )) */ 70{ 71 this->dtmalloc_delta = (int64_t)arg3; 72} 73 74dtmalloc:::free /* probe ID $(( $ID + 2 )) */ 75{ 76 this->dtmalloc_delta = -(int64_t)arg3; 77} 78 79dtmalloc:::malloc, dtmalloc:::free /* probe ID $(( $ID + 3 )) */ 80{ 81 @dtmalloc_bytes[probefunc] = sum(this->dtmalloc_delta); 82 @dtmalloc_allocs[probefunc] = 83 sum(this->dtmalloc_delta > 0 ? 1 : -1); 84} 85EOF 86ACTIONS=$( cat <&9 ) 87ID=$(( $ID + 4 )) 88fi 89 90############################################################ EVENT TAG 91 92# For the running catalog, override the default `UID.GID CMD[PID]: ' tag 93# with ANSI cursor-homing and screen-clearing codes plus column headers. 94 95if [ "$PROFILE" = "dtmalloc-top" ]; then 96size=$( stty size 2> /dev/null ) 97rows="${size%% *}" 98cols="${size#* }" 99 100exec 9<<EOF 101 printf("\033[H"); /* Position the cursor at top-left */ 102 printf("\033[J"); /* Clear display from cursor to end */ 103 104 /* Header line containing probe (left) and date (right) */ 105 printf("%-*s%s%Y%s\n", 106 $(( ${cols:-80} - 20 )), "$PROBE", 107 console ? "\033[32m" : "", 108 walltimestamp, 109 console ? "\033[39m" : ""); 110 111 /* Column headers */ 112 printf("%s%14s %10s %s%s\n", 113 console ? "\033[1m" : "", 114 "NET(B)", 115 "BALANCE", 116 "TYPE", 117 console ? "\033[22m" : ""); 118EOF 119EVENT_TAG=$( cat <&9 ) 120fi 121 122############################################################ EVENT DETAILS 123 124if [ "$PROFILE" = "dtmalloc-top" ]; then 125exec 9<<EOF 126 /* NB: Cumulative; not truncated between updates */ 127 printa("%@14d %@10d %s\n", @dtmalloc_bytes, @dtmalloc_allocs); 128EOF 129EVENT_DETAILS=$( cat <&9 ) 130elif [ ! "$CUSTOM_DETAILS" ]; then 131exec 9<<EOF 132 /* 133 * Print malloc(9) activity details 134 */ 135 printf("%s(9) type %s %d byte%s", 136 probename, 137 probefunc, 138 (long)arg3, 139 (long)arg3 == 1 ? "" : "s"); 140EOF 141EVENT_DETAILS=$( cat <&9 ) 142fi 143 144################################################################################ 145# END 146################################################################################ 147