diff --git a/benchmarks/files/lines/bench.sh b/benchmarks/files/lines/bench.sh index 0c251fe..41d156f 100755 --- a/benchmarks/files/lines/bench.sh +++ b/benchmarks/files/lines/bench.sh @@ -19,7 +19,7 @@ BENCH_NAME="coreutils" printf 'benchmarking %s wc vs fastwc: lines, file input (%s interleaved runs each, minimum kept)\n' \ "$BENCH_NAME" "$BENCH_REPS" -printf '%-28s %10s %10s %8s %s\n' 'test' 'wc' 'fastwc' 'ratio' 'status' +printf '%-28s %10s %22s %8s %s\n' 'test' 'wc' 'fastwc (ms µs)' 'ratio' 'status' printf '%s\n' '--- lines ---' if ! run_cases lines -l 10000 100000 1000000 10000000; then diff --git a/benchmarks/files/words/bench.sh b/benchmarks/files/words/bench.sh index e14449a..8ea852b 100755 --- a/benchmarks/files/words/bench.sh +++ b/benchmarks/files/words/bench.sh @@ -17,7 +17,7 @@ BENCH_NAME="coreutils" printf 'benchmarking %s wc vs fastwc: words, file input (%s interleaved runs each, minimum kept)\n' \ "$BENCH_NAME" "$BENCH_REPS" -printf '%-28s %10s %10s %8s %s\n' 'test' 'wc' 'fastwc' 'ratio' 'status' +printf '%-28s %10s %22s %8s %s\n' 'test' 'wc' 'fastwc (ms µs)' 'ratio' 'status' printf '%s\n' '--- words ---' if ! run_cases words -w 1 10 100 1000 10000 100000; then diff --git a/benchmarks/std.sh b/benchmarks/std.sh index c505e53..3c8c6b5 100755 --- a/benchmarks/std.sh +++ b/benchmarks/std.sh @@ -131,6 +131,17 @@ time_ms() { printf '%s\n' "$(( (e - s) / 1000000 ))" } +# time_us — run a command once and print elapsed wall time in µs. +# More precise than time_ms: sub-millisecond runs come out as e.g. 812, +# not 0. The benchmark keeps the µs reading for fastwc and derives the ms. +time_us() { + local s e + s=$(date +%s%N) + "$@" >/dev/null 2>&1 + e=$(date +%s%N) + printf '%s\n' "$(( (e - s) / 1000 ))" +} + # capture_count — print the first whitespace-separated field of a # command's output, i.e. the count reported by `wc -w/-l` or `fastwc -w/-l`. capture_count() { @@ -151,7 +162,7 @@ write_failed_report() { printf 'failure : %s\n' "$reason" printf '\nresults\n' printf '%s\n' '-------' - printf '%-28s %10s %10s %8s %s\n' 'test' 'wc' 'fastwc' 'ratio' 'status' + printf '%-28s %10s %22s %8s %s\n' 'test' 'wc' 'fastwc (ms µs)' 'ratio' 'status' printf '%s' "$RESULT_ROWS" printf '\nfastwc must never be slower than %s wc — benchmark aborted.\n' "$BENCH_NAME" } > "$report" @@ -167,7 +178,7 @@ run_case() { local mode="$1" lines="$2" flag="$3" local noun='lines'; [[ "$lines" -eq 1 ]] && noun='line' local label="${mode} (${lines} ${noun})" - local file wc_count fast_count wc_ms fast_ms ratio verdict reason row + local file wc_count fast_count wc_ms fast_us fast_ms ratio verdict reason row local i d file=$(createtxt "$lines") || return 1 @@ -177,16 +188,18 @@ run_case() { fast_count=$(capture_count "$FASTWC" "$flag" "$file") # speed: interleaved timing so both commands see identical cache warmth; - # keep the minimum of $BENCH_REPS runs each to reduce noise + # keep the minimum of $BENCH_REPS runs each to reduce noise; fastwc is + # timed in µs so sub-millisecond wins are visible in the report wc_ms='' - fast_ms='' + fast_us='' for ((i = 0; i < BENCH_REPS; i++)); do d=$(time_ms "${WC_CMD[@]}" "$flag" "$file") [[ -z "$wc_ms" || "$d" -lt "$wc_ms" ]] && wc_ms="$d" - d=$(time_ms "$FASTWC" "$flag" "$file") - [[ -z "$fast_ms" || "$d" -lt "$fast_ms" ]] && fast_ms="$d" + d=$(time_us "$FASTWC" "$flag" "$file") + [[ -z "$fast_us" || "$d" -lt "$fast_us" ]] && fast_us="$d" done + fast_ms=$(( fast_us / 1000 )) # ratio: how many times faster fastwc is than the reference (wc / fastwc) if [[ -n "$wc_ms" && "$wc_ms" -gt 0 ]]; then @@ -209,8 +222,9 @@ run_case() { reason="fastwc was slower (fastwc: ${fast_ms}ms vs ${BENCH_NAME} wc: ${wc_ms}ms)" fi - row=$(printf '%-28s %10s %10s %8s %s\n' \ - "$label" "wc: ${wc_ms}ms" "fastwc: ${fast_ms}ms" "$ratio" "$verdict") + row=$(printf '%-28s %10s %22s %8s %s\n' \ + "$label" "wc: ${wc_ms}ms" "fastwc: ${fast_ms}ms (${fast_us}µs)" \ + "$ratio" "$verdict") RESULT_ROWS+="${row}"$'\n' printf '%s\n' "$row" @@ -228,7 +242,7 @@ run_stdin_case() { local mode="$1" lines="$2" flag="$3" local noun='lines'; [[ "$lines" -eq 1 ]] && noun='line' local label="stdin ${mode} (${lines} ${noun})" - local file wc_count fast_count wc_ms fast_ms ratio verdict reason row + local file wc_count fast_count wc_ms fast_us fast_ms ratio verdict reason row local i d file=$(createtxt "$lines") || return 1 @@ -237,14 +251,15 @@ run_stdin_case() { fast_count=$(capture_count "$FASTWC" "$flag" < "$file") wc_ms='' - fast_ms='' + fast_us='' for ((i = 0; i < BENCH_REPS; i++)); do d=$(time_ms "${WC_CMD[@]}" "$flag" < "$file") [[ -z "$wc_ms" || "$d" -lt "$wc_ms" ]] && wc_ms="$d" - d=$(time_ms "$FASTWC" "$flag" < "$file") - [[ -z "$fast_ms" || "$d" -lt "$fast_ms" ]] && fast_ms="$d" + d=$(time_us "$FASTWC" "$flag" < "$file") + [[ -z "$fast_us" || "$d" -lt "$fast_us" ]] && fast_us="$d" done + fast_ms=$(( fast_us / 1000 )) # ratio: how many times faster fastwc is than the reference (wc / fastwc) if [[ -n "$wc_ms" && "$wc_ms" -gt 0 ]]; then @@ -267,8 +282,9 @@ run_stdin_case() { reason="fastwc was slower (fastwc: ${fast_ms}ms vs ${BENCH_NAME} wc: ${wc_ms}ms)" fi - row=$(printf '%-28s %10s %10s %8s %s\n' \ - "$label" "wc: ${wc_ms}ms" "fastwc: ${fast_ms}ms" "$ratio" "$verdict") + row=$(printf '%-28s %10s %22s %8s %s\n' \ + "$label" "wc: ${wc_ms}ms" "fastwc: ${fast_ms}ms (${fast_us}µs)" \ + "$ratio" "$verdict") RESULT_ROWS+="${row}"$'\n' printf '%s\n' "$row" @@ -286,7 +302,7 @@ run_solo_case() { local lines="$1" flag="$2" local noun='lines'; [[ "$lines" -eq 1 ]] && noun='line' local label="solo ${lines} ${noun}" - local file ms best='' bytes gbps mlps i d + local file best_us='' best_ms bytes gbps mlps i d file=$(createtxt "$lines") || { printf '%-28s %s\n' "$label" 'SKIP (could not create test data)' @@ -294,16 +310,17 @@ run_solo_case() { } for ((i = 0; i < BENCH_REPS; i++)); do - d=$(time_ms "$FASTWC" "$flag" "$file") - [[ -z "$best" || "$d" -lt "$best" ]] && best="$d" + d=$(time_us "$FASTWC" "$flag" "$file") + [[ -z "$best_us" || "$d" -lt "$best_us" ]] && best_us="$d" done + best_ms=$(( best_us / 1000 )) bytes=$((lines * 11)) - gbps=$(awk -v b="$bytes" -v ms="$best" 'BEGIN { printf "%.2f", b / ms / 1e6 }') - mlps=$(awk -v l="$lines" -v ms="$best" 'BEGIN { printf "%.1f", l / ms / 1e3 }') + gbps=$(awk -v b="$bytes" -v ms="$best_ms" 'BEGIN { if (ms < 1) ms = 1; printf "%.2f", b / ms / 1e6 }') + mlps=$(awk -v l="$lines" -v ms="$best_ms" 'BEGIN { if (ms < 1) ms = 1; printf "%.1f", l / ms / 1e3 }') - printf '%-28s %12s %12s %14s\n' \ - "$label" "fastwc: ${best}ms" "${gbps} GB/s" "${mlps} Mlines/s" + printf '%-28s %25s %12s %14s\n' \ + "$label" "fastwc: ${best_ms}ms (${best_us}µs)" "${gbps} GB/s" "${mlps} Mlines/s" } # run_cases <-w|-l> — run run_case for every size, diff --git a/benchmarks/stdin/piping/bench.sh b/benchmarks/stdin/piping/bench.sh index f8b3b0a..c7ce272 100755 --- a/benchmarks/stdin/piping/bench.sh +++ b/benchmarks/stdin/piping/bench.sh @@ -19,7 +19,7 @@ BENCH_NAME="coreutils" printf 'benchmarking %s wc vs fastwc: stdin (%s interleaved runs each, minimum kept)\n' \ "$BENCH_NAME" "$BENCH_REPS" -printf '%-28s %10s %10s %8s %s\n' 'test' 'wc' 'fastwc' 'ratio' 'status' +printf '%-28s %10s %22s %8s %s\n' 'test' 'wc' 'fastwc (ms µs)' 'ratio' 'status' printf '%s\n' '--- stdin lines ---' if ! run_stdin_cases lines -l 10000 100000 1000000 10000000; then