Skip to content
dgem has moved to github.com/GoogleCloudPlatform/dgem. Docs are moving to googlecloudplatform.github.io/dgem; this site stays up during the move.

Latency and Capacity

All numbers: serving image 504638d, 1× RTX PRO 6000, single client in the same region, 30 sequential requests per latency cell and 256 requests per concurrency cell (receipts). GPU time is the server-reported denoise time; end to end includes network and routing.

Request (3 questions unless noted)Vertex G4 GPU / e2eCloud Run GPU / e2e
samples: 155 / 150 ms61 / 153 ms
samples: 4 (one parallel batch)91 / 190 ms101 / 182 ms
3 questions + reversed-order check (6 slots), samples: 158 / 152 ms66 / 152 ms
Image + 2 questions, samples: 164 / 183 ms76 / 184 ms
120-token reasoning trace (think: 120) + 2 questions364 / 463 ms376 / 462 ms

Earlier measurements (image ab208dd) put samples: "auto" at ~150 ms GPU on G4, about 50 ms more than a fixed 4, because it usually runs a second sequential batch; the L4 was ~3× slower on every row (2026-09-25 run).

  • samples: 1 by default. One read is the fastest path. Use samples: 4 (one parallel batch, ~+35–40 ms) where you need agreement and standard error, for example to route to human review. Avoid "auto" on latency-sensitive paths. Schemas without samples use the server’s DEFAULT_SAMPLES (1).
  • Ask everything about one input in one request. All questions share one forward pass; three questions cost about the same as one.
  • Avoid depends_on / ask_if when latency matters. Conditional questions run in a second stage (two sequential passes). Gate in your client instead if you need a single pass.
  • At most 26 options per choice question. Wider taxonomies need a two-stage split (two passes).
  • Thinking costs ~300 ms per 120 tokens. Use think only where it measurably helps (e.g. taxonomy discovery).

Throughput and concurrency (one Vertex G4 replica)

Section titled “Throughput and concurrency (one Vertex G4 replica)”
Concurrent clientssamples: 1 decisions/s · p50 · p95samples: 4 decisions/s · p50 · p95Errors
15.4/s · 140 · 359 ms5.7/s · 176 · 182 ms0
420.9/s · 176 · 256 ms13.9/s · 208 · 1,106 ms0
838.2/s · 189 · 196 ms28.9/s · 256 · 266 ms0
1654.3/s · 254 · 386 ms39.0/s · 349 · 1,164 ms0 / 256
3272.3/s · 426 · 645 ms45.2/s · 685 · 717 ms0 / 256

Rows 1–8: 50 requests each on the same runtime before the final HTTP fixes; rows 16–32: final image, 256 requests each. Beyond ~16 clients requests queue: latency rises while throughput grows slowly. Add replicas for more throughput (Vertex autoscales on GPU duty cycle); Cloud Run runs one instance per service.

SettingDefaultEffect
MAX_INFLIGHT8Decisions processed at once per server; the rest wait up to INFLIGHT_WAIT_S (30 s), then 503. Protects the engine: an L4 replica without a cap crashed under 8 concurrent 4-sample requests.
DEFAULT_SAMPLES1Samples for schemas that don’t set samples
MAX_SEQS32vLLM sequences in one batch (4-sample requests use 4)
KV_CACHE_GB12 (Vertex G4), 2 (Cloud Run script)KV cache memory; more allows more concurrent sequences
DISABLE_MM01 turns off the vision tower (required on L4 Cloud Run, saves memory)
ENFORCE_EAGER1Eager mode: shorter start-up, no graph compilation

Keep-alive matters under load: the server speaks HTTP/1.1 with a 256-connection backlog. With HTTP/1.0 Vertex’s proxy returned 503 ... truncated headers for 1–8% of requests at 16–32 concurrent clients.

Terminal window
# Per-mode latency (repeat --target to compare deployments side by side)
python3 scripts/serving_speed.py modes --target mine=<BASE_URL>/v1/chat/completions -n 30 -o modes.json
# Concurrency sweep; any error is a finding
python3 scripts/serving_speed.py sweep --target mine=<BASE_URL>/v1/chat/completions \
--workers 1 4 8 16 32 --samples 1 4 --min-requests 256 -o sweep.json
# Cloud Run cold start for one configuration
python3 scripts/coldstart_probe.py --service <SERVICE> --project <PROJECT> --region <REGION> --label mine --vpc

<BASE_URL> is a Cloud Run URL or a Vertex invoke base (https://<ENDPOINT_ID>.<REGION>-<PROJECT_NUMBER>.prediction.vertexai.goog/v1/projects/<PROJECT>/locations/<REGION>/endpoints/<ENDPOINT_ID>/invoke). Tokens come from Application Default Credentials. Measure from the region your clients run in, and don’t run benchmarks against the same endpoint at the same time (they contaminate each other’s latency).