summaryrefslogtreecommitdiff
path: root/benchmarks/turbo_vs_normal_bench.sh
blob: 162d12a537a9952eb7ba67043dad9fa36f9893a9 (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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/bin/bash
#
# HISTORICAL / DEFUNCT A/B HARNESS: DTAIL_TURBOBOOST_DISABLE (and the older
# DTAIL_TURBOBOOST_ENABLE) are now inert no-ops. The former "turbo" path is the
# single, default read/output path, so the "turbo" and "non-turbo" arms below now
# exercise the SAME code path and any measured difference is noise. Kept as a
# historical harness (it produced the dated benchmark reports under benchmarks/
# and docs/); it no longer performs a meaningful turbo-vs-non-turbo comparison.
#
# Turbo vs non-turbo end-to-end benchmark for the DTail tools
# (dcat, dgrep, dmap, dtail follow).
#
# Turbo is ON by default; non-turbo runs set DTAIL_TURBOBOOST_DISABLE=yes on
# the process that runs the server handlers: the client itself in serverless
# mode, dserver in server mode. Server mode uses real SSH auth (dedicated
# throwaway key + CacheDir authorized_keys) instead of
# DTAIL_INTEGRATION_TEST_RUN_MODE, because integration-test mode force-
# disables turbo (internal/config/initializer.go) and would compare
# non-turbo against non-turbo.
#
# Note: turbo boost is opt-out via DTAIL_TURBOBOOST_DISABLE (default-on since
# commit aa2f547); the stale DTAIL_TURBOBOOST_ENABLE env var is no longer read.
# This script does whole-tool A/B timing; the companion benchmark scripts
# (e.g. turbo_comparison.sh) drive the same DTAIL_TURBOBOOST_DISABLE toggle.
#
# Usage: ./turbo_vs_normal_bench.sh [workdir]
#   workdir defaults to a fresh mktemp dir; results land in
#   $workdir/results.csv. Requires binaries built in the repo root
#   (make build) and benchmarks/testdata/{medium,large}.log (make of the
#   regular benchmark suite generates them, or see testdata_generator.go).
set -u

BENCHMARK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(dirname "$BENCHMARK_DIR")"
DATA="$BENCHMARK_DIR/testdata"
WORKDIR="${1:-$(mktemp -d /tmp/dtail_turbo_bench.XXXXXX)}"
CSV="$WORKDIR/results.csv"
PORT_TURBO=14201
PORT_NOTURBO=14202
mkdir -p "$WORKDIR/server/cache" "$WORKDIR/data"

echo "Workdir: $WORKDIR"
echo "scenario,mode,iter,seconds,note" > "$CSV"

# --- SSH auth for server mode ---
KEY=$WORKDIR/bench_key
if [ ! -f "$KEY" ]; then
    ssh-keygen -t rsa -b 2048 -N "" -f "$KEY" -q
    cp "$KEY.pub" "$WORKDIR/server/cache/$(id -un).authorized_keys"
fi
CLIENT_COMMON=(--cfg none --plain --noColor --trustAllHosts --auth-key-path "$KEY")

# --- test data ---
STATS=$WORKDIR/data/stats_100mb.log
if [ ! -f "$STATS" ]; then
    awk 'BEGIN{for(i=0;i<800000;i++){printf "INFO|0626-140021|1|stats.go:56|%d|%d|%d|0.%02d|1h0m0s|MAPREDUCE:STATS|hostname=host%d|currentConnections=%d|lifetimeConnections=%d\n", i%8, i%100, i%10, i%100, i%50, i%20, 1000+i}}' > "$STATS"
fi
CHUNK=$WORKDIR/data/burst_10mb.log
if [ ! -f "$CHUNK" ]; then
    awk 'BEGIN{for(i=0;i<100000;i++) printf "[2026-07-10 12:00:00.000] INFO - Follow benchmark line %d payload abcdefghijklmnopqrstuvwxyz0123456789\n", i}' > "$CHUNK"
fi

now_ns() { date +%s%N; }

time_run() { # scenario mode iter cmd...
    local scenario=$1 mode=$2 iter=$3; shift 3
    local t0 t1 rc
    t0=$(now_ns)
    "$@" > /dev/null 2>>"$WORKDIR/client_stderr.log"
    rc=$?
    t1=$(now_ns)
    if [ $rc -ne 0 ]; then
        echo "FAILED rc=$rc: $scenario $mode iter $iter" >&2
        echo "$scenario,$mode,$iter,,failed-rc$rc" >> "$CSV"
        return 1
    fi
    echo "$scenario,$mode,$iter,$(awk "BEGIN{printf \"%.3f\", ($t1-$t0)/1e9}")," >> "$CSV"
}

run_serverless() { # scenario N cmd... (A/B alternating iterations)
    local scenario=$1 n=$2; shift 2
    "$@" > /dev/null 2>/dev/null                                # warmup turbo
    DTAIL_TURBOBOOST_DISABLE=yes "$@" > /dev/null 2>/dev/null   # warmup non-turbo
    for i in $(seq 1 "$n"); do
        time_run "$scenario" turbo "$i" "$@"
        time_run "$scenario" noturbo "$i" env DTAIL_TURBOBOOST_DISABLE=yes "$@"
    done
    echo "done: $scenario"
}

run_server() { # scenario N timeout clientcmd... (__PORT__ replaced per mode)
    local scenario=$1 n=$2 tmo=$3; shift 3
    local args_turbo=() args_noturbo=() a
    for a in "$@"; do
        args_turbo+=("${a//__PORT__/$PORT_TURBO}")
        args_noturbo+=("${a//__PORT__/$PORT_NOTURBO}")
    done
    timeout "$tmo" "${args_turbo[@]}" > /dev/null 2>/dev/null    # warmup
    timeout "$tmo" "${args_noturbo[@]}" > /dev/null 2>/dev/null  # warmup
    for i in $(seq 1 "$n"); do
        time_run "$scenario" turbo "$i" timeout "$tmo" "${args_turbo[@]}"
        time_run "$scenario" noturbo "$i" timeout "$tmo" "${args_noturbo[@]}"
    done
    echo "done: $scenario"
}

start_servers() {
    cd "$WORKDIR/server" || exit 1
    "$ROOT/dserver" --cfg none --logger stdout --logLevel error \
        --bindAddress localhost --port $PORT_TURBO > dserver_turbo.log 2>&1 &
    SRV_TURBO_PID=$!
    DTAIL_TURBOBOOST_DISABLE=yes "$ROOT/dserver" --cfg none --logger stdout \
        --logLevel error --bindAddress localhost --port $PORT_NOTURBO \
        > dserver_noturbo.log 2>&1 &
    SRV_NOTURBO_PID=$!
    sleep 2
}

stop_servers() {
    kill $SRV_TURBO_PID $SRV_NOTURBO_PID 2>/dev/null
    wait $SRV_TURBO_PID $SRV_NOTURBO_PID 2>/dev/null
}

# dtail follow: append a 10MB burst to a followed file; measure time until the
# end marker reaches the client, and count delivered lines (the non-turbo tail
# path drops lines when the consumer lags, so completeness matters here).
run_dtail_follow() {
    local scenario=$1 n=$2 mode port i
    for mode in turbo noturbo; do
        if [ "$mode" = turbo ]; then port=$PORT_TURBO; else port=$PORT_NOTURBO; fi
        for i in $(seq 0 "$n"); do  # iter 0 = warmup
            local follow=$WORKDIR/data/follow_$mode.log
            local out=$WORKDIR/data/follow_out_${mode}_$i.txt
            : > "$follow"
            "$ROOT/dtail" "${CLIENT_COMMON[@]}" --servers "localhost:$port" \
                --files "$follow" > "$out" 2>/dev/null &
            local dtail_pid=$!
            local probes=0  # wait until the follow stream is live
            while true; do
                echo "PROBE-$mode-$i-$probes" >> "$follow"; sleep 0.2
                grep -q "PROBE-$mode-$i-" "$out" 2>/dev/null && break
                probes=$((probes+1)); [ $probes -gt 75 ] && break
            done
            local marker="BENCHEND-$mode-$i" t0 t1 w=0
            t0=$(now_ns)
            cat "$CHUNK" >> "$follow"; echo "$marker" >> "$follow"
            while ! grep -q "$marker" "$out" 2>/dev/null; do
                sleep 0.05; w=$((w+1)); [ $w -gt 1800 ] && break
            done
            t1=$(now_ns)
            sleep 1  # let trailing lines land before counting
            local lines
            lines=$(grep -c "Follow benchmark line" "$out")
            kill $dtail_pid 2>/dev/null; wait $dtail_pid 2>/dev/null
            local res=ok; [ $w -gt 1800 ] && res="timeout_gt90s"
            if [ "$i" -gt 0 ]; then
                echo "$scenario,$mode,$i,$(awk "BEGIN{printf \"%.3f\", ($t1-$t0)/1e9}"),$res delivered=$lines/100000" >> "$CSV"
            fi
            rm -f "$out"
        done
    done
    echo "done: $scenario"
}

echo "=== Serverless scenarios ==="
run_serverless sl_dcat_100mb 7 "$ROOT/dcat" --cfg none --plain "$DATA/medium.log"
run_serverless sl_dcat_1gb 3 "$ROOT/dcat" --cfg none --plain "$DATA/large.log"
run_serverless sl_dgrep_low_100mb 7 "$ROOT/dgrep" --cfg none --plain --regex "user999 " --files "$DATA/medium.log"
run_serverless sl_dgrep_high_100mb 7 "$ROOT/dgrep" --cfg none --plain --regex "ERROR" --files "$DATA/medium.log"
run_serverless sl_dmap_agg_100mb 5 "$ROOT/dmap" --cfg none --plain \
    --query "from STATS select count(\$line),avg(\$goroutines),max(\$goroutines),sum(\$goroutines) group by \$goroutines" \
    --files "$STATS"

echo "=== Server-mode scenarios ==="
start_servers
run_server sv_dcat_100mb 7 120 "$ROOT/dcat" "${CLIENT_COMMON[@]}" --servers localhost:__PORT__ --files "$DATA/medium.log"
run_server sv_dgrep_low_100mb 7 120 "$ROOT/dgrep" "${CLIENT_COMMON[@]}" --servers localhost:__PORT__ --regex "user999 " --files "$DATA/medium.log"
run_server sv_dgrep_high_100mb 7 120 "$ROOT/dgrep" "${CLIENT_COMMON[@]}" --servers localhost:__PORT__ --regex "ERROR" --files "$DATA/medium.log"
# NOTE: as of 2026-07-10 the turbo halves of the two dmap scenarios hang
# (client never exits; see turbo_vs_normal_report_20260710.md). The timeout
# converts the hang into failed-rc124 rows instead of blocking the suite.
run_server sv_dmap_count_100mb 5 120 "$ROOT/dmap" "${CLIENT_COMMON[@]}" --servers localhost:__PORT__ \
    --query "from STATS select count(\$line) group by \$hostname" --files "$STATS"
run_server sv_dmap_agg_100mb 5 120 "$ROOT/dmap" "${CLIENT_COMMON[@]}" --servers localhost:__PORT__ \
    --query "from STATS select count(\$line),avg(\$goroutines),max(\$goroutines),sum(\$goroutines) group by \$goroutines" \
    --files "$STATS"
run_dtail_follow sv_dtail_follow_10mb 3
stop_servers

echo "=== ALL DONE ==="
echo "Results: $CSV"