Skip to content

perf: avoid allocating the assigned worker path prefix - #2755

Merged
henderkes merged 4 commits into
php:mainfrom
andreybolonin:perf/worker-script-path
Oct 24, 2026
Merged

henderkes merged 4 commits into
php:mainfrom
andreybolonin:perf/worker-script-path

Conversation

@andreybolonin

Copy link
Copy Markdown
Contributor

When a worker is explicitly assigned, deriving SCRIPT_NAME builds documentRoot + separator and then checks the document-root prefix a second time in TrimPrefix. For roots longer than the temporary string buffer, this also allocates on every request.

Check the length, separator byte and root prefix directly, then slice the verified root prefix. Keep filepath.ToSlash, the original handling of workers outside the root, and all SCRIPT_NAME/PATH_INFO values unchanged. No cache or request fields are added.

Added boundary cases and differential fuzzing against the previous full splitCgiPath, plus a reusable BenchmarkAssignedWorkerScriptPath. The benchmark includes the whole function for explicitly assigned workers, rather than only the prefix expression.

Validation

Covers inside/outside/neighboring roots, equal and empty paths, filesystem roots, trailing/repeated separators, long roots, Unicode, NUL and invalid UTF-8. Differential fuzzing varies root, worker filename and request path, comparing the complete resulting context with the previous implementation.

  • Isolated committed tests pass with -race against both versions.
  • Fuzzing the final implementation: 1,386,376 executions in 20 seconds, four workers, no failures.
  • gofmt and git diff --check pass.
  • Native package test was attempted via ./go.sh test -tags nowatcher -run '^TestAssignedWorkerScriptPath$' -count=1 .; compilation stops at missing sapi/embed/php_embed.h. Local PHP 8.5.12 is NTS. Native callback/C integration, full FrankenPHP/Caddy suites and end-to-end load tests have not passed locally; they require a supported embed/ZTS environment.

Time and allocation measurements

Baseline: d138a78717413a589cb9af097483024c19f6ae92 (main). PR head: 02313c063270e3497b5b35debb31a526a54fde2b. Apple M2, darwin/arm64, macOS 27.0, Go 1.27.3. This PR is independently based on main.

The standalone harness extracts splitCgiPath and its helpers from the baseline and this PR without changing their bodies. It uses the production context declaration, committed tests/benchmark, and minimal worker/server stubs. It does not link PHP. Neither version includes changes from the separate splitPos PR.

Ten before/after pairs, alternating which version runs first, -test.cpu=1 -test.benchmem, 150ms per sub-benchmark. Separate optimized binaries, without race instrumentation or PGO. Setup is outside b.Loop, and results are consumed. Table entries are median and observed min-max in ns/op, not confidence intervals. Positive time reduction means faster. These are operation microbenchmarks, not whole HTTP-request throughput. These final measurements supersede the earlier narrower helper timings.

Scenario Before ns/op (min-max) After ns/op (min-max) Time reduction B/op before -> after allocs/op before -> after
short_root 28.400 (28.330-32.800) 15.750 (15.720-18.360) +44.5% 0 -> 0 0 -> 0
long_root 49.940 (49.670-50.250) 17.240 (17.170-17.440) +65.5% 64 -> 0 1 -> 0
outside_root 42.715 (42.470-43.010) 14.555 (14.490-14.580) +65.9% 64 -> 0 1 -> 0
empty_root 21.045 (20.950-23.990) 15.445 (15.410-15.550) +26.6% 0 -> 0 0 -> 0
trailing_separator 28.505 (28.360-28.690) 15.760 (15.700-16.320) +44.7% 0 -> 0 0 -> 0
exact_root 25.785 (25.700-26.620) 14.545 (14.520-14.570) +43.6% 0 -> 0 0 -> 0

Heap allocation numbers count Go allocations during each operation. The optimization adds no cache or persistent state. Whole-process RSS, retained-process memory and PHP/C allocations were not measured, so zero/reduced B/op is not claimed to prove unchanged RSS.

Stack measurements

Generated optimized compiler assembly (go test -c -gcflags=-S) for the same standalone function bodies:

Target Before direct frame After direct frame Change
darwin/arm64 160 B 128 B -32 B
linux/amd64 144 B 88 B -56 B
windows/amd64 144 B 88 B -56 B

These are direct frames in the isolated Go compilation, not total nested stack peaks or native cgo-export wrapper frames. Linux and Windows were cross-compiled only; no runtime speed or test execution on those targets is claimed.

Reproduction

With supported PHP embed/ZTS development libraries installed, run the committed tests in the repository:

./go.sh test -race -run '^(TestAssignedWorkerScriptPath|FuzzAssignedWorkerScriptPath)' .
./go.sh test -run '^$' -bench '^BenchmarkAssignedWorkerScriptPath$' -benchmem -count=10 -benchtime=150ms -cpu=1 .
./go.sh test -run '^$' -fuzz '^FuzzAssignedWorkerScriptPath$' -fuzztime=20s -parallel=4 .

The following script reproduces the actual isolated timing setup without PHP. Save it outside the checkout and run it with Python 3 from this PR checkout. It extracts the baseline/current source, copies the committed tests, runs race checks, emits compiler assembly, and alternates ten benchmark pairs. For the output PR, the script also includes its Go-only benchmark fixture.

Standalone reproduction script
from pathlib import Path
import os
import subprocess
import tempfile

BASE="d138a78717413a589cb9af097483024c19f6ae92"
TASK="path"
root=Path(tempfile.mkdtemp(prefix="frankenphp-"+TASK+"-"))
env=dict(os.environ,GO111MODULE="off",CGO_ENABLED="0",GOCACHE=str(root/"cache"))
ctx=Path("context.go").read_text()
start=ctx.index("type frankenPHPContext struct {")
declaration=ctx[start:ctx.index("// NewRequestWithContext",start)]
start=ctx.index("func (fc *frankenPHPContext) clientHasClosed(")
client=ctx[start:ctx.index("// reject sends",start)]
shared='package frankenphp\nimport("context";"log/slog";"net/http";"time")\ntype mercureContext struct{}\ntype PreparedEnv=map[string]string\ntype worker struct{fileName string}\ntype Server struct{workersByPath map[string]*worker}\nvar globalWorkersByPath map[string]*worker\n'+declaration+client
filename="cgi.go" if TASK=="path" else "frankenphp.go"
testfile="cgi_workerpath_test.go" if TASK=="path" else "ubwrite_test.go"
for variant in ["before","after"]:
 directory=root/variant
 directory.mkdir()
 directory.joinpath("context.go").write_text(shared)
 directory.joinpath(testfile).write_text(Path(testfile).read_text())
 source=subprocess.check_output(["git","show",BASE+":"+filename],text=True) if variant=="before" else Path(filename).read_text()
 if TASK=="path":
  functions=[]
  for begin,end in [("func splitCgiPath(","// splitPos returns"),("func splitPos(","// go_update_request_info"),("func sanitizedPathJoin(","// splitRemoteAddr"),("func ensureLeadingSlash(","// toUnsafeChar")]:
   start=source.index(begin)
   functions.append(source[start:source.index(end,start)])
  code='package frankenphp\nimport("path";"path/filepath";"runtime";"strings";"unicode/utf8")\nconst separator=string(filepath.Separator)\n'+"".join(functions)
 else:
  start=source.index("func go_ub_write(")
  function=source[start:source.index("//export go_apache_request_headers",start)]
  for original,alias in [("C.uintptr_t","cUintptr"),("C.char","cChar"),("C.size_t","cSize"),("C.bool","cBool")]:
   function=function.replace(original,alias)
  imports='"log/slog";"unsafe"'+(';"bytes";"io"' if variant=="before" else '')
  code="package frankenphp\nimport("+imports+")\n"+'type cUintptr uintptr\ntype cChar int8\ntype cSize uint64\ntype cBool bool\ntype phpThread struct{handler threadHandler}\ntype threadHandler interface{frankenPHPContext()*frankenPHPContext}\ntype regularThread struct{fc *frankenPHPContext}\nfunc(h *regularThread) frankenPHPContext()*frankenPHPContext{return h.fc}\nvar phpThreads []*phpThread\n'+function
  directory.joinpath("benchmark_test.go").write_text('package frankenphp\nimport("context";"fmt";"log/slog";"net/http";"strings";"testing";"unsafe")\ntype benchHandler struct{level slog.Level}\nfunc(h benchHandler) Enabled(_ context.Context,l slog.Level)bool{return l>=h.level}\nfunc(h benchHandler) Handle(context.Context,slog.Record)error{return nil}\nfunc(h benchHandler) WithAttrs([]slog.Attr)slog.Handler{return h}\nfunc(h benchHandler) WithGroup(string)slog.Handler{return h}\ntype benchWriter struct{}\nfunc(benchWriter) Header()http.Header{return nil}\nfunc(benchWriter) WriteHeader(int){}\nfunc(benchWriter) Write(p []byte)(int,error){return len(p),nil}\nvar benchN cSize\nvar benchClosed cBool\nfunc BenchmarkUBWrite(b *testing.B){\n for _,n:=range []int{0,1,64,1024}{for _,mode:=range []string{"log_disabled","log_enabled","http_response","done"}{b.Run(fmt.Sprintf("bytes_%d/%s",n,mode),func(b *testing.B){\n  fc:=&frankenPHPContext{ctx:context.Background(),request:&http.Request{},logger:slog.New(benchHandler{slog.LevelWarn})}\n  switch mode{case "log_enabled":fc.logger=slog.New(benchHandler{slog.LevelInfo});case "http_response":fc.responseWriter=benchWriter{};case "done":fc.isDone=true}\n  phpThreads=[]*phpThread{{handler:&regularThread{fc:fc}}}\n  data:=[]byte(strings.Repeat("x",n));pointer:=(*cChar)(unsafe.Pointer(unsafe.SliceData(data)))\n  b.ReportAllocs()\n  for b.Loop(){benchN,benchClosed=go_ub_write(0,pointer,cSize(len(data)))}\n })}}\n}\n')
 directory.joinpath("production.go").write_text(code)
 files=[str(p) for p in sorted(directory.glob("*.go"))]
 subprocess.run(["go","test","-race",*files],env=dict(env,CGO_ENABLED="1"),check=True)
 with root.joinpath(variant+"-assembly.txt").open("w") as stream:
  subprocess.run(["go","test","-c","-gcflags=-S","-o",str(root/(variant+".test")),*files],env=env,stdout=stream,stderr=subprocess.STDOUT,check=True)
pattern="^BenchmarkAssignedWorkerScriptPath$" if TASK=="path" else "^BenchmarkUBWrite$"
duration="150ms" if TASK=="path" else "120ms"
for pair in range(10):
 for variant in (("before","after") if pair%2==0 else ("after","before")):
  result=subprocess.run([str(root/(variant+".test")),"-test.run=^$","-test.bench="+pattern,"-test.benchmem","-test.benchtime="+duration,"-test.cpu=1"],capture_output=True,text=True,check=True)
  with root.joinpath(variant+".txt").open("a") as stream:
   stream.write(result.stdout)
 print("Completed pair",pair+1,flush=True)
print("Artifacts:",root)
All baseline benchmark samples
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 5227292	        32.80 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3648780	        49.70 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4255759	        42.70 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8659362	        21.02 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6327500	        28.48 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6718569	        25.97 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6333446	        28.40 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3644701	        49.89 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4181581	        43.01 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8345809	        21.32 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6286461	        28.44 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6916060	        25.70 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6247378	        28.40 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3668679	        49.95 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4228946	        42.66 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8235927	        20.99 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6338278	        28.36 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6949404	        25.78 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6368431	        28.37 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3666889	        49.93 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4210250	        42.73 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8314455	        21.11 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6348002	        28.36 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6954550	        25.72 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6299395	        28.33 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3626485	        49.98 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4235667	        42.47 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8279445	        23.99 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6226066	        28.69 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6986108	        25.77 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6382798	        28.40 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3714885	        49.67 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4244756	        42.53 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8521028	        21.01 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6301969	        28.56 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 7011302	        25.92 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6328714	        28.37 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3633778	        50.25 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4202767	        42.79 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8457039	        21.00 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6271986	        28.61 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6957921	        25.79 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6277718	        28.45 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3604974	        50.24 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4197116	        42.82 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8356222	        21.07 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6338966	        28.47 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6981524	        26.62 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6295824	        28.53 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3622959	        50.21 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4219564	        42.95 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8271123	        21.19 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6336187	        28.53 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6950455	        25.77 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 6327000	        28.47 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	 3702906	        49.76 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	 4248676	        42.59 ns/op	      64 B/op	       1 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	 8654174	        20.95 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	 6294512	        28.58 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	 6906153	        25.83 ns/op	       0 B/op	       0 allocs/op
PASS
All optimized benchmark samples
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	 9053406	        18.36 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10385563	        17.27 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12379960	        14.56 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11709728	        15.44 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11408832	        15.75 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12305482	        14.54 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	10934106	        15.87 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10529497	        17.18 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12354540	        14.50 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11602641	        15.46 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11490858	        15.70 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12166957	        14.56 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11355511	        15.76 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10449750	        17.44 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12022575	        14.58 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11595229	        15.46 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11201112	        15.80 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12456171	        14.52 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11346444	        15.73 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10317920	        17.40 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12465553	        14.55 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11723424	        15.41 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11378690	        16.32 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12424825	        14.54 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11411694	        15.83 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10429038	        17.22 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12455238	        14.56 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11736865	        15.47 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11341737	        15.77 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12254414	        14.57 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11459888	        15.72 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10469478	        17.24 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12252885	        14.56 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11733645	        15.43 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11084425	        15.75 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12289171	        14.56 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11384149	        15.73 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10544995	        17.17 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12316710	        14.49 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11599401	        15.45 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11463172	        15.75 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12181916	        14.56 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11264020	        15.82 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10449194	        17.24 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12355884	        14.52 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11707252	        15.42 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11497556	        15.86 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12344655	        14.53 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11400612	        15.74 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10498839	        17.28 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12410510	        14.53 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11652590	        15.55 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11456970	        15.78 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12250731	        14.54 ns/op	       0 B/op	       0 allocs/op
PASS
goos: darwin
goarch: arm64
cpu: Apple M2
BenchmarkAssignedWorkerScriptPath/short_root         	11289010	        15.74 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/long_root          	10534888	        17.23 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/outside_root       	12336969	        14.56 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/empty_root         	11616243	        15.41 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/trailing_separator 	11382828	        15.72 ns/op	       0 B/op	       0 allocs/op
BenchmarkAssignedWorkerScriptPath/exact_root         	12453370	        14.55 ns/op	       0 B/op	       0 allocs/op
PASS
Fuzzing output
fuzz: elapsed: 0s, gathering baseline coverage: 0/4 completed
fuzz: elapsed: 0s, gathering baseline coverage: 4/4 completed, now fuzzing with 4 workers
fuzz: elapsed: 3s, execs: 45373 (15122/sec), new interesting: 23 (total: 27)
fuzz: elapsed: 6s, execs: 196635 (50410/sec), new interesting: 26 (total: 30)
fuzz: elapsed: 9s, execs: 294973 (32779/sec), new interesting: 26 (total: 30)
fuzz: elapsed: 12s, execs: 395799 (33619/sec), new interesting: 26 (total: 30)
fuzz: elapsed: 15s, execs: 773146 (125753/sec), new interesting: 26 (total: 30)
fuzz: elapsed: 18s, execs: 918445 (48437/sec), new interesting: 27 (total: 31)
fuzz: elapsed: 20s, execs: 1386376 (224603/sec), new interesting: 27 (total: 31)
PASS
ok  	command-line-arguments	20.424s

@dunglas dunglas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general approach LGTM

Comment thread cgi_workerpath_test.go Outdated
Comment thread cgi.go Outdated
Comment thread cgi_test.go Outdated
@henderkes
henderkes merged commit aa882f0 into php:main Oct 24, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants