TensorRT batch inference timeout on GPU during high concurrency

Problem – TensorRT Batch Inference Times Out Under High Concurrency

In a production GPU inference service the following symptoms appear when the request rate spikes:

  • Requests that submit a batched input to IExecutionContext::enqueueV2 return false after ~10 s.
  • Server logs contain messages such as:

[ERROR] Failed to enqueue inference: Timeout while waiting for GPU
[TensorRT] Execution context timed out after 10000 ms
CUDA driver error: CUDA_ERROR_LAUNCH_TIMEOUT
  • GPU utilization plateaus at ~90 % and nvidia-smi shows GPU-Util stuck at 99 % while the driver resets the device.
  • On Windows the Event Viewer records “CUDA driver timeout: kernel execution took too long”.

The issue only manifests when the number of simultaneous inference streams exceeds ~30 or when the per‑batch size is increased beyond the previously stable value (e.g., from 64 to 256).

Root Cause – Interaction of Watchdog Timers, Stream Saturation, and Asynchronous Execution

TensorRT’s asynchronous execution model (see the Developer Guide – Asynchronous Execution) relies on CUDA streams to overlap kernel launches and data transfers. Two independent mechanisms can abort a kernel:

  1. CUDA watchdog timer – On Windows the WDDM driver enforces a 2 s execution limit per kernel launch (CUDA_ERROR_LAUNCH_TIMEOUT). When a single batch or a collection of concurrent kernels exceeds this window the driver aborts the launch, resets the GPU, and returns the error observed.
  2. TensorRT internal timeout – The execution context tracks the elapsed time from the moment enqueueV2 is called until the completion callback fires. If the elapsed time exceeds the value configured by setTimingCache or the default 10 s, TensorRT logs “Execution context timed out after X ms” and returns false.

High concurrency amplifies both effects:

  • Each request creates its own CUDA stream. When >30 streams are active the driver’s scheduler cannot guarantee that every kernel finishes within the watchdog window, especially for large batch sizes that increase kernel runtime (see the Performance Guide – Batch Size).
  • TensorRT’s default stream priority is 0. Without explicit stream management, kernels compete for the same hardware resources, causing longer queuing delays that push execution past the watchdog limit.

Therefore the timeout is not a “configuration mistake” per se; it is the result of exceeding the runtime guarantees of the underlying driver under a workload that scales both batch size and concurrency.

Debug – Systematic Investigation Steps

1. Capture Immediate Symptoms


$ journalctl -u inference-service -f
[2026-07-11 14:32:07] INFO  Enqueue batch id=1024 size=256
[2026-07-11 14:32:07] ERROR Failed to enqueue inference: Timeout while waiting for GPU
[2026-07-11 14:32:07] TensorRT: Execution context timed out after 10000 ms

2. Verify Driver‑Level Timeout

On Windows, check the Event Viewer for CUDA driver timeout. On Linux, inspect dmesg for “GPU reset” entries.


$ dmesg | grep -i reset
[ 12345.678901] NVRM: GPU at PCI:0000:65:00.0: Resetting GPU due to timeout

3. Profile Kernel Execution Time

Use nvprof or Nsight Systems to measure the longest kernel in a batch.


$ nvprof --profile-from-start off -f -o profile.nvvp ./inference_server
# After reproducing the failure:
$ nsys stats profile.nvvp | grep kernel
kernel_name                     avg(ms)   min(ms)   max(ms)
__launch_bounds__...           1850      1800      2100

If the max exceeds 2000 ms, the watchdog on WDDM will definitely trigger.

4. Inspect Stream Usage


$ cat /proc/$(pidof inference_server)/fdinfo/* | grep -i stream

Alternatively, instrument the code to log the number of active streams at enqueue time.

5. Review TensorRT Context Settings


IExecutionContext* ctx = engine->createExecutionContext();
bool ok = ctx->setTimingCache(timingCache, false);
if (!ok) { LOG_ERROR("Failed to set timing cache"); }

If setTimingCache is never called, the default 10 s timeout applies.

Solution – Architectural and Configuration Adjustments

1. Move to TCC Driver (Linux) or Use Dedicated Compute Mode (Windows)

On Windows, switch from the default WDDM driver to the TCC (Tesla Compute Cluster) driver, which disables the 2 s watchdog. This requires a GPU that supports TCC (e.g., Tesla, RTX A-series).


# Check current mode
nvidia-smi -q | grep "Compute Mode"
# Set to TCC
nvidia-smi -dm 1

2. Limit Concurrency per GPU

Introduce a semaphore that caps the number of simultaneous streams to a safe threshold (e.g., 24).


// Before enqueue
static std::counting_semaphore<24> gpu_sem;
gpu_sem.acquire();

std::thread([&, request]{
    // ...prepare input...
    bool ok = context->enqueueV2(buffers, stream, nullptr);
    if (!ok) { LOG_ERROR("Enqueue failed"); }
    // ...post‑process...
    gpu_sem.release();
}).detach();

3. Reduce Per‑Batch Size or Split Large Batches

Empirically determine the batch size that keeps the longest kernel < 1.8 s. For a model that scales linearly, a size of 128 may be safe.

4. Prioritize Streams and Use Explicit Synchronization

Assign higher priority to latency‑critical streams.


cudaStream_t high_pri_stream;
cudaStreamCreateWithPriority(&high_pri_stream, cudaStreamNonBlocking, -1); // -1 = highest priority
bool ok = context->enqueueV2(buffers, high_pri_stream, nullptr);

Ensure callbacks are cleared to avoid dead‑locks (see the “dead‑locks when async callbacks were not cleared” incident).

5. Extend TensorRT Timeout (if driver timeout is already mitigated)

If the GPU driver no longer aborts kernels, increase the internal timeout:


context->setTimingCache(timingCache, false); // reuse cache
context->setProfiler(&myProfiler); // optional
// No direct API to change timeout, but you can wrap enqueue in a larger host‑side timeout.

Before / After Comparison

Aspect Before After
Driver mode WDDM (2 s watchdog) TCC (no watchdog)
Max concurrent streams Unlimited (≈40) 24 (semaphore‑limited)
Batch size 256 128 (or dynamic split)
Stream priority Default (0) High‑priority for latency paths
Timeout observed CUDA_ERROR_LAUNCH_TIMEOUT Successful completion, latency ~1.5 s

Verification – Confirming the Fix

  1. Re‑run a load test with wrk or a custom client that opens 40 parallel connections.
  2. Monitor nvidia-smi for GPU reset events; there should be none.
  3. Check server logs for the absence of “Failed to enqueue inference” messages.
  4. Collect a new nvprof run; the longest kernel should stay < 1900 ms.
  5. Validate end‑to‑end latency meets SLA (e.g., 95th percentile < 2 s).

Prevention – Operational Guardrails

  • Capacity planning: Use the TensorRT Performance Guide to benchmark kernel runtime versus batch size on the target GPU.
  • Watchdog awareness: On Windows, enforce TCC mode for any production inference workload.
  • Dynamic throttling: Implement a back‑pressure mechanism that reduces batch size or stalls new requests when gpu_sem cannot be acquired.
  • Metrics & alerts: Emit a Prometheus metric inference_enqueue_timeout_total and alert if it spikes.
  • Stream hygiene: Always destroy streams and clear callbacks after each request to avoid resource leaks.

Related Topic Hub: Model Serving Troubleshooting Hub

FAQ

Q1: Why does the timeout only appear after increasing the batch size?

A1: Larger batches increase the compute workload per kernel, lengthening execution time. When the kernel runtime exceeds the driver’s watchdog limit (2 s on WDDM) the GPU is reset, producing CUDA_ERROR_LAUNCH_TIMEOUT.

Q2: Can I keep using WDDM and still avoid timeouts?

A2: Only if you guarantee that every kernel finishes < 2 s. This usually requires aggressive batch‑size limits and strict concurrency caps, which may hurt throughput. Switching to TCC is the recommended production approach.

Q3: Does setting IExecutionContext::setTimingCache change the watchdog behavior?

A3: No. The timing cache only affects TensorRT’s internal profiling. The watchdog is enforced by the CUDA driver, independent of TensorRT settings.

Q4: How can I detect that the GPU watchdog is the culprit without looking at driver logs?

A4: When enqueueV2 returns false and the log contains “CUDA_ERROR_LAUNCH_TIMEOUT”, the error originates from the driver. A concurrent dmesg or Windows Event Viewer entry confirming a GPU reset further corroborates this.

Q5: Is there a way to increase the watchdog timeout on Windows?

A5: The WDDM watchdog timeout is fixed (≈2 s) and cannot be configured. The only supported method to bypass it is to switch the GPU to TCC mode, which removes the watchdog entirely.