# scripts/lib/trace-extract.awk
# Extract instrumented source locations from xtrace logs produced via
# scripts/lib/trace-init.sh.
#
# Marker lines look like (bash repeats the leading '@' once per nesting level):
# @@TBL@@ /path/to/trbldoc.sh:1234 1712345678.123456
#
# Variables:
# MODE=cov (default) -> prints "\t" per marker line
# MODE=time -> prints "\t\t\t" at END,
# computing per-line durations from consecutive markers
# WITHIN each trace file (one file == one process, so
# parallel xargs workers are not cross-attributed).
function basename(p) {
sub(/.*\//, "", p) # strip up to last forward slash
sub(/.*\\/, "", p) # strip up to last backslash (defensive)
return p
}
# Parse a marker line into globals g_base and g_line (and g_epoch for time).
# Returns 1 on success, 0 if the line is not a usable marker.
function parse(line, s, n, f, loc, rest) {
if (line !~ /@+TBL@@ /) return 0
s = line
sub(/^.*TBL@@ /, "", s) # drop marker and everything before it
n = split(s, f, " ")
if (n < 1) return 0
loc = f[1] # :
if (!match(loc, /:[0-9]+$/)) return 0
g_line = substr(loc, RSTART + 1)
g_base = basename(substr(loc, 1, RSTART - 1))
if (MODE == "time") {
g_epoch = (n >= 2 ? f[2] : "")
}
return 1
}
BEGIN { if (MODE == "") MODE = "cov" }
# Reset per-process state at the start of each trace file.
FNR == 1 { have_prev = 0 }
{
if (!parse($0)) next
if (MODE == "cov") {
print g_base "\t" g_line
next
}
# MODE == time: attribute elapsed time to the PREVIOUS marker.
if (have_prev && g_epoch != "" && prev_epoch != "") {
d = g_epoch - prev_epoch
if (d < 0) d = 0
key = prev_base SUBSEP prev_line
ms[key] += d * 1000.0
hits[key] += 1
base_of[key] = prev_base
line_of[key] = prev_line
}
prev_base = g_base
prev_line = g_line
prev_epoch = g_epoch
have_prev = 1
}
END {
if (MODE != "time") exit
for (k in ms) {
printf "%.3f\t%d\t%s\t%s\n", ms[k], hits[k], base_of[k], line_of[k]
}
}