Skip to content

Commit fb421c5

Browse files
author
Delta-Kronecker
committed
launcher: bound warmup to ~65 s, keep 1 request/s cadence, show clock
The old warmup loop tried up to 3 hosts sequentially per second, each with a 5 s timeout, and slept to fill the second. On a slow tunnel a single iteration could stretch to 15 s (all hosts timing out), so a 60 s warmup took several minutes and the counter froze for seconds at a time. Requests are now dispatched on worker threads, one per second (hosts rotated), each allowed up to 5 s for a response and counted as ok/fail/timeout. A slow request no longer stalls the cadence and the whole phase is bounded to about warmupSeconds + 5 s (~65 s). The progress line gains a clock (elapsed/max) and the final summary reports the real elapsed time.
1 parent 569ea66 commit fb421c5

2 files changed

Lines changed: 87 additions & 60 deletions

File tree

README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,15 +208,18 @@ the circuit set stable (relaxed during tunnel warmup). Disable it with
208208
### Tunnel warmup
209209

210210
Once bootstrap hits 100%, TorJet warms the tunnel immediately with lightweight
211-
`generate_204` pings through the HTTP proxy (one per second for 60 s, 5 s
212-
timeout each, latency is measured), in parallel with the circuit health
213-
monitor. The old 1 MiB download check was replaced:
211+
`generate_204` pings sent through the **SOCKS5 proxy (127.0.0.1:9050)** — the
212+
same port you test — one request dispatched every second for 60 s, each allowed
213+
up to 5 s for a response (recorded as ok / fail / timeout). Requests overlap, so
214+
a slow circuit never stalls the 1/s cadence and the whole phase is bounded to
215+
about 65 s. The old 1 MiB download check was replaced:
214216
it gave false negatives on cold single-stream circuits and added ~1 MiB of
215-
padding traffic. Each ping is timed and the run ends with a summary
216-
(ok/fail/timeouts, average, best and worst latency). The tunnel is considered
217-
ready after at least 5 successful pings; otherwise Tor is stopped and the main
218-
menu is shown again. During warmup the monitor's close cooldown is relaxed, so
219-
weak legs are replaced immediately. Adjust the duration with
217+
padding traffic. The progress line shows a **clock** (elapsed/max, e.g.
218+
`[00:47/01:05]`) plus live ok/fail/timeout/avg/worst; the run ends with a
219+
summary (ok/fail/timeouts, average, best and worst latency). The tunnel is
220+
considered ready after at least 5 successful pings; otherwise Tor is stopped
221+
and the main menu is shown again. During warmup the monitor's close cooldown is
222+
relaxed, so weak legs are replaced immediately. Adjust the duration with
220223
`--warmup <seconds>` (default 60).
221224

222225
## Building

scripts/start-tor.cs

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ internal static class Program
176176
// replaced immediately instead of waiting out the normal gap.
177177
private static volatile bool circuitWatchWarmup;
178178

179-
// Ping-based tunnel warmup: one generate_204 request per second for
180-
// warmupSeconds, replacing the old 1 MiB download check (which gave
181-
// false negatives on cold single-stream circuits).
179+
// Ping-based tunnel warmup: one generate_204 request dispatched every
180+
// second for warmupSeconds, replacing the old 1 MiB download check
181+
// (which gave false negatives on cold single-stream circuits).
182182
private static int warmupSeconds = 60;
183183

184184
[DllImport("wininet.dll", SetLastError = true)]
@@ -2245,27 +2245,50 @@ private static int PingSocks(string host, string path, out long elapsedMs)
22452245
}
22462246
}
22472247

2248-
// Warms the tunnel with generate_204 pings through the HTTP proxy
2249-
// (127.0.0.1:8118) instead of a 1 MiB download, which produced false
2250-
// negatives on cold single-stream circuits. One request per second for
2251-
// warmupSeconds, each with a 5 s timeout. Every request is timed and
2252-
// counted; the tunnel is ready when at least 5 pings succeeded. C
2253-
// aborts (stops tor, back to the main menu).
2254-
// The ping loop runs on a worker thread while the caller polls for C, so
2248+
// Warms the tunnel with real SOCKS5 generate_204 pings (127.0.0.1:9050)
2249+
// instead of a 1 MiB download, which produced false negatives on cold
2250+
// single-stream circuits. One request is dispatched every second for
2251+
// warmupSeconds; each request is allowed up to 5 s to get a response and
2252+
// is recorded as ok / fail / timeout. Requests overlap: a slow one never
2253+
// stalls the 1/s cadence (the old loop tried up to 3 hosts sequentially
2254+
// with 5 s timeouts each, stretching a 60 s warmup to many minutes on a
2255+
// slow tunnel). The whole phase is therefore bounded to about
2256+
// warmupSeconds + 5 s (the last request's timeout), i.e. ~65 s. The
2257+
// tunnel is ready when at least 5 pings succeeded. C aborts (stops tor,
2258+
// back to the main menu).
2259+
// The ping loop runs on worker threads while the caller polls for C, so
22552260
// abort works even when a request is stuck on a slow circuit. After the
22562261
// loop, conflux linkage is reported honestly: pings succeed on plain
22572262
// circuits even when no conflux leg has linked yet.
2263+
private static readonly object warmupLock = new object();
22582264
private static volatile bool warmupAbort;
22592265
private static volatile bool warmupRunning;
22602266
private static volatile int warmupDone, warmupOk, warmupFail, warmupTimeouts;
22612267
private static long warmupTotalMs, warmupBestMs, warmupWorstMs;
2268+
private static Stopwatch warmupPhaseSw;
2269+
2270+
private static string FormatClock(long ms)
2271+
{
2272+
TimeSpan ts = TimeSpan.FromMilliseconds(ms);
2273+
return ((int)ts.TotalMinutes).ToString("D2") + ":" + ts.Seconds.ToString("D2");
2274+
}
22622275

22632276
private static void DrawWarmupLine()
22642277
{
2265-
string line = "warmup " + warmupDone + "/" + warmupSeconds + " ok=" +
2266-
warmupOk + " fail=" + warmupFail + " avg=" +
2267-
(warmupOk > 0 ? warmupTotalMs / warmupOk : 0) +
2268-
"ms worst=" + warmupWorstMs + "ms";
2278+
int done = 0, ok = 0, fail = 0, timeouts = 0;
2279+
long total = 0, worst = 0, phase = 0;
2280+
lock (warmupLock)
2281+
{
2282+
done = warmupDone; ok = warmupOk; fail = warmupFail; timeouts = warmupTimeouts;
2283+
total = warmupTotalMs; worst = warmupWorstMs;
2284+
if (warmupPhaseSw != null) phase = warmupPhaseSw.ElapsedMilliseconds;
2285+
}
2286+
long cap = (long)(warmupSeconds + 5) * 1000;
2287+
string line = "warmup " + done + "/" + warmupSeconds + " [" +
2288+
FormatClock(phase) + "/" + FormatClock(cap) +
2289+
"] ok=" + ok + " fail=" + fail + " timeout=" + timeouts +
2290+
" avg=" + (ok > 0 ? total / ok : 0) +
2291+
"ms worst=" + worst + "ms";
22692292
lock (consoleLock)
22702293
{
22712294
if (line.Length < progressLineLen) line = line.PadRight(progressLineLen);
@@ -2274,10 +2297,31 @@ private static void DrawWarmupLine()
22742297
}
22752298
}
22762299

2300+
private static void WarmupPingWorker(PingTarget target)
2301+
{
2302+
long ems;
2303+
int r = PingSocks(target.Host, target.Path, out ems);
2304+
lock (warmupLock)
2305+
{
2306+
warmupDone++;
2307+
if (r == 1)
2308+
{
2309+
if (ems < 0) ems = 0;
2310+
warmupOk++;
2311+
warmupTotalMs += ems;
2312+
if (ems < warmupBestMs) warmupBestMs = ems;
2313+
if (ems > warmupWorstMs) warmupWorstMs = ems;
2314+
}
2315+
else if (r == -1) warmupTimeouts++;
2316+
else warmupFail++;
2317+
}
2318+
}
2319+
22772320
private static bool WarmupTunnel()
22782321
{
2279-
Console.WriteLine("warming tunnel: real delay test via SOCKS 127.0.0.1:9050 " +
2280-
"every second for " + warmupSeconds + " s (C = stop Tor)...");
2322+
Console.WriteLine("warming tunnel: real delay test via SOCKS 127.0.0.1:9050, " +
2323+
"1 request/s for " + warmupSeconds + " s, 5 s timeout " +
2324+
"(C = stop Tor)...");
22812325
warmupAbort = false;
22822326
warmupRunning = true;
22832327
warmupDone = 0;
@@ -2287,47 +2331,26 @@ private static bool WarmupTunnel()
22872331
warmupTotalMs = 0;
22882332
warmupBestMs = long.MaxValue;
22892333
warmupWorstMs = 0;
2334+
warmupPhaseSw = Stopwatch.StartNew();
22902335

22912336
Thread worker = new Thread(delegate ()
22922337
{
2338+
var inflight = new List<Thread>();
22932339
for (int i = 1; i <= warmupSeconds; i++)
22942340
{
22952341
if (warmupAbort) break;
2296-
bool success = false;
2297-
bool anyTimeout = false;
2298-
long okMs = -1;
2299-
Stopwatch sw = Stopwatch.StartNew();
2300-
foreach (PingTarget t in PingTargets)
2301-
{
2302-
long ems;
2303-
int r = PingSocks(t.Host, t.Path, out ems);
2304-
if (r == 1)
2305-
{
2306-
success = true;
2307-
okMs = ems >= 0 ? ems : sw.ElapsedMilliseconds;
2308-
break;
2309-
}
2310-
if (r == -1) anyTimeout = true;
2311-
}
2312-
sw.Stop();
2313-
long elapsedMs = okMs >= 0 ? okMs : sw.ElapsedMilliseconds;
2314-
if (success)
2315-
{
2316-
warmupOk++;
2317-
warmupTotalMs += elapsedMs;
2318-
if (elapsedMs < warmupBestMs) warmupBestMs = elapsedMs;
2319-
if (elapsedMs > warmupWorstMs) warmupWorstMs = elapsedMs;
2320-
}
2321-
else if (anyTimeout) warmupTimeouts++;
2322-
else warmupFail++;
2323-
warmupDone = i;
2324-
long remaining = 1000 - elapsedMs;
2325-
if (remaining > 0 && !warmupAbort)
2326-
{
2327-
long step = Math.Min(remaining, 200);
2328-
for (long t = 0; t < remaining && !warmupAbort; t += step)
2329-
Thread.Sleep((int)step);
2330-
}
2342+
PingTarget target = PingTargets[(i - 1) % PingTargets.Length];
2343+
Thread t = new Thread(delegate () { WarmupPingWorker(target); });
2344+
t.IsBackground = true;
2345+
t.Start();
2346+
inflight.Add(t);
2347+
long targetMs = (long)i * 1000;
2348+
while (!warmupAbort && warmupPhaseSw.ElapsedMilliseconds < targetMs)
2349+
Thread.Sleep(50);
2350+
}
2351+
if (!warmupAbort)
2352+
{
2353+
foreach (Thread t in inflight) t.Join();
23312354
}
23322355
warmupRunning = false;
23332356
});
@@ -2373,8 +2396,9 @@ private static bool WarmupTunnel()
23732396
}
23742397
int ok = warmupOk, fail = warmupFail, timeouts = warmupTimeouts;
23752398
long totalMs = warmupTotalMs, bestMs = warmupBestMs, worstMs = warmupWorstMs;
2399+
long phaseMs = warmupPhaseSw == null ? 0 : warmupPhaseSw.ElapsedMilliseconds;
23762400
string summary = "warmup done: " + ok + " ok / " + fail + " fail / " + timeouts +
2377-
" timeouts in " + warmupSeconds + " s - avg " +
2401+
" timeouts in " + FormatClock(phaseMs) + " - avg " +
23782402
(ok > 0 ? totalMs / ok : 0) + " ms, best " +
23792403
(bestMs == long.MaxValue ? "-" : bestMs.ToString()) +
23802404
" ms, worst " + worstMs + " ms.";

0 commit comments

Comments
 (0)