mirror of
https://github.com/89luca89/distrobox.git
synced 2026-08-19 01:14:49 -05:00
bench: add /usr/bin/time -v wrapper and parser
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
Command being timed: "sh -c sleep 0.05"
|
||||
User time (seconds): 0.00
|
||||
System time (seconds): 0.00
|
||||
Percent of CPU this job got: 1%
|
||||
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.05
|
||||
Average shared text size (kbytes): 0
|
||||
Average unshared data size (kbytes): 0
|
||||
Average stack size (kbytes): 0
|
||||
Average total size (kbytes): 0
|
||||
Maximum resident set size (kbytes): 2944
|
||||
Average resident set size (kbytes): 0
|
||||
Major (requiring I/O) page faults: 0
|
||||
Minor (reclaiming a frame) page faults: 117
|
||||
Voluntary context switches: 5
|
||||
Involuntary context switches: 1
|
||||
Swaps: 0
|
||||
File system inputs: 0
|
||||
File system outputs: 0
|
||||
Socket messages sent: 0
|
||||
Socket messages received: 0
|
||||
Signals delivered: 0
|
||||
Page size (bytes): 4096
|
||||
Exit status: 0
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
# /usr/bin/time -v wrapper and parser.
|
||||
|
||||
time_run() {
|
||||
local out_txt="$1" cmd="$2"
|
||||
/usr/bin/time -v -o "$out_txt" sh -c "$cmd"
|
||||
}
|
||||
|
||||
# Parse a /usr/bin/time -v output file into a JSON object.
|
||||
# Fields that don't appear in the input become null.
|
||||
time_parse_v() {
|
||||
local file="$1"
|
||||
awk '
|
||||
BEGIN {
|
||||
keys["peak_rss_kb"] = "null"
|
||||
keys["user_seconds"] = "null"
|
||||
keys["sys_seconds"] = "null"
|
||||
keys["wall_seconds"] = "null"
|
||||
keys["voluntary_ctx_switches"] = "null"
|
||||
keys["involuntary_ctx_switches"] = "null"
|
||||
keys["major_page_faults"] = "null"
|
||||
keys["minor_page_faults"] = "null"
|
||||
keys["fs_inputs"] = "null"
|
||||
keys["fs_outputs"] = "null"
|
||||
}
|
||||
function set(k, v) { keys[k] = v }
|
||||
function wall_to_seconds(s, parts, n, h, m, sec) {
|
||||
# Accept h:mm:ss(.frac) or m:ss(.frac)
|
||||
n = split(s, parts, ":")
|
||||
if (n == 3) { return parts[1]*3600 + parts[2]*60 + parts[3] + 0 }
|
||||
else if (n == 2) { return parts[1]*60 + parts[2] + 0 }
|
||||
else { return s + 0 }
|
||||
}
|
||||
/Maximum resident set size/ { set("peak_rss_kb", $NF + 0) }
|
||||
/User time/ { set("user_seconds", $NF + 0) }
|
||||
/System time/ { set("sys_seconds", $NF + 0) }
|
||||
/Elapsed \(wall clock\) time/ {
|
||||
# Last field is the formatted time
|
||||
v = wall_to_seconds($NF)
|
||||
set("wall_seconds", v)
|
||||
}
|
||||
/Voluntary context switches/ { set("voluntary_ctx_switches", $NF + 0) }
|
||||
/Involuntary context switches/ { set("involuntary_ctx_switches", $NF + 0) }
|
||||
/Major \(requiring I\/O\) page faults/ { set("major_page_faults", $NF + 0) }
|
||||
/Minor \(reclaiming a frame\) page faults/ { set("minor_page_faults", $NF + 0) }
|
||||
/File system inputs/ { set("fs_inputs", $NF + 0) }
|
||||
/File system outputs/ { set("fs_outputs", $NF + 0) }
|
||||
END {
|
||||
# Emit JSON. Numbers are emitted bare (jq -r will keep them as-is),
|
||||
# null literal stays null.
|
||||
printf "{"
|
||||
sep = ""
|
||||
# Stable key order:
|
||||
order = "peak_rss_kb user_seconds sys_seconds wall_seconds " \
|
||||
"voluntary_ctx_switches involuntary_ctx_switches " \
|
||||
"major_page_faults minor_page_faults fs_inputs fs_outputs"
|
||||
n = split(order, ord, " ")
|
||||
for (i = 1; i <= n; i++) {
|
||||
k = ord[i]
|
||||
v = keys[k]
|
||||
if (v == "null") {
|
||||
printf "%s\"%s\":null", sep, k
|
||||
} else {
|
||||
# User/system times are like "0.00"; keep as numeric literal
|
||||
printf "%s\"%s\":%s", sep, k, v
|
||||
}
|
||||
sep = ","
|
||||
}
|
||||
printf "}\n"
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
. "${SCRIPT_DIR}/test_helpers.sh"
|
||||
. "${SCRIPT_DIR}/common.sh"
|
||||
. "${SCRIPT_DIR}/time.sh"
|
||||
|
||||
FIXTURE="${SCRIPT_DIR}/../fixtures/time-sample.txt"
|
||||
|
||||
test_parse_peak_rss() {
|
||||
local got
|
||||
got=$(time_parse_v "$FIXTURE" | jq -r '.peak_rss_kb')
|
||||
assert_eq "2944" "$got" "peak_rss_kb"
|
||||
}
|
||||
|
||||
test_parse_user_seconds() {
|
||||
# jq normalises JSON numbers: 0.00 → 0
|
||||
local got
|
||||
got=$(time_parse_v "$FIXTURE" | jq -r '.user_seconds')
|
||||
assert_eq "0" "$got" "user_seconds"
|
||||
}
|
||||
|
||||
test_parse_wall_seconds_from_mm_ss() {
|
||||
# 0:00.05 → 0.05 seconds
|
||||
local got
|
||||
got=$(time_parse_v "$FIXTURE" | jq -r '.wall_seconds')
|
||||
assert_eq "0.05" "$got" "wall_seconds"
|
||||
}
|
||||
|
||||
test_parse_minor_faults() {
|
||||
local got
|
||||
got=$(time_parse_v "$FIXTURE" | jq -r '.minor_page_faults')
|
||||
assert_eq "117" "$got" "minor_page_faults"
|
||||
}
|
||||
|
||||
test_parse_voluntary_ctx() {
|
||||
local got
|
||||
got=$(time_parse_v "$FIXTURE" | jq -r '.voluntary_ctx_switches')
|
||||
assert_eq "5" "$got" "voluntary_ctx_switches"
|
||||
}
|
||||
|
||||
test_parse_missing_field_is_null() {
|
||||
local d; d=$(mktempdir)
|
||||
printf '\tMaximum resident set size (kbytes): 1024\n' > "$d/partial.txt"
|
||||
local got
|
||||
got=$(time_parse_v "$d/partial.txt" | jq -r '.user_seconds')
|
||||
assert_eq "null" "$got" "missing field becomes null"
|
||||
rm -rf "$d"
|
||||
}
|
||||
|
||||
test_time_run_captures_output() {
|
||||
local d; d=$(mktempdir)
|
||||
time_run "$d/out.txt" "true"
|
||||
assert_file_exists "$d/out.txt" "time_run writes output"
|
||||
assert_contains "Maximum resident set size" "$(cat "$d/out.txt")" "verbose output present"
|
||||
rm -rf "$d"
|
||||
}
|
||||
|
||||
test_parse_peak_rss
|
||||
test_parse_user_seconds
|
||||
test_parse_wall_seconds_from_mm_ss
|
||||
test_parse_minor_faults
|
||||
test_parse_voluntary_ctx
|
||||
test_parse_missing_field_is_null
|
||||
test_time_run_captures_output
|
||||
printf 'time_test.sh: ok\n'
|
||||
Reference in New Issue
Block a user