aboutsummaryrefslogtreecommitdiff
path: root/scripts/lib/trace-extract.awk
blob: 7b8682a9e277dae103131bc64029e52e018a7e5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 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  "<base>\t<line>"            per marker line
#   MODE=time           -> prints  "<total_ms>\t<hits>\t<base>\t<line>" 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]                        # <source>:<lineno>
  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]
  }
}