File size: 13,101 Bytes
63dd946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Protocols, binary tensors, shared memory and message limits

This note covers how a client talks to Triton: HTTP/REST against gRPC under the KServe v2 protocol, the binary
tensor extension, compression, system and CUDA shared memory, and the size limits on each path, with a note on what
the Python backend does with the bytes once they arrive. The facts apply to Triton 24.10 (`r24.10` branches of
`server`, `client` and `python_backend`); later branches are named where behaviour changed. Checked 9 October 2026.

## HTTP/REST and gRPC

- Triton serves both protocols from the KServe v2 standard plus Triton's own extensions; gRPC adds a bidirectional
  streaming form of the inference call, and NVIDIA "typically recommend[s] using the unary version" unless a stream
  is needed (for example to keep a sequence on one server behind a load balancer) [1].
- Default ports are 8000 (HTTP), 8001 (gRPC) and 8002 (metrics) [2, 3, 4]. `--http-thread-count` sets the number of
  threads handling HTTP requests; the default is 8 [2, 3].
- I found no statement in the r24.10 protocol, optimisation or performance-tuning documents comparing HTTP with gRPC
  for a given request size, so there is no documented basis for expecting one to be faster at about 1.7 MB [1, 5].
- In the KServe gRPC protocol, sending tensors as `raw_input_contents` / `raw_output_contents` "will typically allow
  higher performance" than the typed `contents` fields, because of how protobuf allocation interacts with gRPC [6].

## Binary tensor data extension (HTTP)

- The extension lets an HTTP request or response carry tensors as raw bytes after the JSON header; Triton reports
  `binary_tensor_data` among its server extensions [7].
- Binary data is little-endian, row-major, with no stride or padding; each type uses its native size [7].
- `binary_data_size` (int64, bytes) on an input or output marks it as binary; `binary_data: true` on a requested
  output asks for binary; `binary_data_output: true` on the request asks for all outputs in binary unless overridden [7].
- The body is the JSON object followed by the tensors in the order they appear in the JSON. When any binary data is
  present, `Inference-Header-Content-Length` gives the JSON length and `Content-Length` the whole body [7].
- A "raw binary request" (`Inference-Header-Content-Length: 0`, no JSON) is allowed only for models with one input
  and at most one variable dimension [7].
- Without the extension, tensor data travels as a JSON array of numbers in row-major order [6]. Inference: for
  435,200 fp32 samples that means formatting and parsing every value as text, several times the 1.74 MB of raw bytes.

## Compression

- The r24.10 HTTP server decompresses request bodies sent with `Content-Encoding: gzip` or `deflate`, and compresses
  responses when the client sends `Accept-Encoding: gzip` or `deflate` [8].
- The client libraries expose request and response compression for HTTP and a compression algorithm for gRPC; the
  default is no compression in both [9]. On the server, gRPC response compression is set with
  `--grpc-infer-response-compression-level` [1].
- Inference: on one host, compressing fp32 audio only adds CPU time on both sides.

## Message size limits

- gRPC server: `MAX_GRPC_MESSAGE_SIZE = INT32_MAX` (2,147,483,647 bytes) in `src/common.h`, applied with
  `builder_.SetMaxMessageSize(MAX_GRPC_MESSAGE_SIZE)` [10, 11].
- Triton's own gRPC clients raise their limits to the same value: the Python client sets
  `grpc.max_send_message_length` and `grpc.max_receive_message_length` to `INT32_MAX`, and the C++ client calls
  `SetMaxSendMessageSize` and `SetMaxReceiveMessageSize` with it [12, 13]. A third-party gRPC client keeps its own
  library default unless it is raised (the value of that default is not covered by Triton's sources).
- HTTP in r24.10 has no option for a maximum request size, and I found no size check in its `http_server.cc` [2, 8].
  `--http-max-input-size` first appears on the r25.06 branch (absent on r24.11 to r25.05): "Maximum allowed HTTP
  request input size in bytes. For compressed requests, this also limits the decompressed size", default `1 << 26`
  = 67,108,864 bytes (64 MiB) [14, 15].
- Where it applies (source reading, not tested): in r25.06 the limit is checked for each input sent as JSON data and
  for a raw binary request; r26.05 adds checks on the JSON header length and on decompressed size. I found no check
  on tensor bytes sent with `binary_data_size` in either branch [21, 22].

## Shared memory extensions

- Instead of sending tensor bytes in the request, a client can name a registered region with the input or output
  parameters `shared_memory_region` and `shared_memory_byte_size` (both required) and `shared_memory_offset`
  (optional, default 0); the input's `data` field must then be absent [16]. System and CUDA region names share one
  namespace; there is no Windows support, and Jetson supports only system shared memory [16].
- System shared memory, HTTP endpoints [16]: `GET v2/systemsharedmemory[/region/${REGION_NAME}]/status`,
  `POST v2/systemsharedmemory/region/${REGION_NAME}/register` with body `{"key", "offset", "byte_size"}` (the key of
  the underlying memory object), and `POST v2/systemsharedmemory[/region/${REGION_NAME}]/unregister` (no name
  unregisters all regions).
- CUDA shared memory, HTTP endpoints [16]: the same three under `v2/cudasharedmemory`, with a register body
  `{"raw_handle": {"b64": ...}, "device_id", "byte_size"}`, where `raw_handle` is the serialised cudaIPC handle,
  base64-encoded, and `device_id` is the GPU on which it was created.
- The gRPC service has matching `SystemSharedMemory*` and `CudaSharedMemory*` register, status and unregister calls,
  and the same parameters go in `InferInputTensor` / `InferRequestedOutputTensor` [16].
- In the r24.10 server, a system region is opened with `shm_open(key)` and `mmap`, and a CUDA region with
  `cudaSetDevice(device_id)` and `cudaIpcOpenMemHandle` [17]. The client therefore creates the region first (POSIX
  shared memory, or device memory exported with `cudaIpcGetMemHandle`, which "gets an interprocess memory handle for
  an existing device memory allocation" [18]). Inference: both mechanisms are host-local, so the client must run on
  the same host and, in containers, share the IPC namespace or `/dev/shm` with Triton.
- The client README says shared memory "can significantly improve performance in some cases", and ships helper
  modules for Python plus C++ and Python examples [9].

## What the Python backend does with the bytes

- The Python backend talks to its stub process through shared memory: 1 MB per model instance by default, grown in
  1 MB chunks, set with `shm-default-byte-size` and `shm-growth-byte-size`; inside Docker, `--shm-size` must cover
  the inputs and outputs because Docker's default is 64 MB [19].
- By default every input is moved to CPU before the model sees it; `FORCE_CPU_ONLY_INPUT_TENSORS: "no"` lets inputs
  stay in GPU memory where they were last used [19].
- In `python_be.cc` r24.10, a CPU input is allocated in the stub's shared-memory pool and the request data is copied
  into it (`SaveToSharedMemory`, then `ProcessTensor` or `ReadInputTensor`) [20]. Inference from that code: data that
  arrives through client system shared memory is still copied once into the Python backend's own pool; it saves the
  HTTP transfer and parsing, not this copy. GPU inputs take a separate path through a CUDA memory pool [20].

## Unverified

- The default receive limit of a non-Triton gRPC client library (often quoted as 4 MiB) was not checked against a
  primary source.
- Whether HTTP keep-alive is used and how idle connections are handled by Triton's HTTP server is not documented in
  the r24.10 docs I read.
- No measurement of HTTP against gRPC for this request size was found; any speed difference is unknown.
- That `--http-max-input-size` does not limit binary-extension tensors is read from source; it was not tested.

## What this means for the diarization model

- Each block is two requests of about 1.7 MB each, because the engine computes masks between the calls and sends the
  same `SPAN` twice (repo facts). HTTP with binary tensors is the documented efficient HTTP form; JSON would be far
  slower to encode and parse (inference).
- gRPC has no documented speed advantage at this size. If the engine ever used gRPC, its client would need a
  receive and send limit above 1.7 MB per block, or k x 1.7 MB when blocks are packed (inference).
- On 24.10 there is no HTTP body limit. On 25.06 and 26.05 the 64 MiB default appears not to cover binary tensors,
  so it would not cap packed blocks sent the way the engine sends them; if a later release extends it, 64 MiB is
  about 38 blocks of 1.74 MB (67,108,864 / 1,740,800 = 38.5) [14, 21, 22].
- System shared memory would remove the HTTP body copy but not the Python backend's own copy, and it ties the
  gateway to the same host and IPC namespace as Triton (inference).
- CUDA shared memory would need the Rust engine, a CPU-side HTTP client today, to allocate device memory and export
  IPC handles itself (inference).
- The container's `--shm-size` must hold the Python backend pools: with 2 requests in flight per GPU, inputs are a
  few MB per model instance, far below Docker's 64 MB default, but packed requests grow this linearly (inference).

## Sources

1. Inference Protocols and APIs - https://github.com/triton-inference-server/server/blob/r24.10/docs/customization_guide/inference_protocols.md - r24.10.
2. `command_line_parser.cc` (option text) - https://github.com/triton-inference-server/server/blob/r24.10/src/command_line_parser.cc - r24.10.
3. `command_line_parser.h` (defaults: `http_port_{8000}`, `http_thread_cnt_{8}`, `metrics_port_{8002}`) -
   https://github.com/triton-inference-server/server/blob/r24.10/src/command_line_parser.h#L193-L216 - r24.10.
4. `grpc_server.h` (`port_{8001}`) - https://github.com/triton-inference-server/server/blob/r24.10/src/grpc/grpc_server.h#L52 - r24.10.
5. Optimization; Performance Tuning - https://github.com/triton-inference-server/server/blob/r24.10/docs/user_guide/optimization.md and
   https://github.com/triton-inference-server/server/blob/r24.10/docs/user_guide/performance_tuning.md - r24.10.
6. KServe Open Inference Protocol v2, required API (Tensor Data, gRPC raw contents) -
   https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md - KServe master, 9 October 2026.
7. Binary Tensor Data Extension - https://github.com/triton-inference-server/server/blob/r24.10/docs/protocol/extension_binary_data.md - r24.10.
8. `http_server.cc` (compression handling) - https://github.com/triton-inference-server/server/blob/r24.10/src/http_server.cc#L2545-L2577 - r24.10.
9. Triton client README (Compression, System/CUDA Shared Memory) - https://github.com/triton-inference-server/client/blob/r24.10/README.md - r24.10.
10. `common.h` - https://github.com/triton-inference-server/server/blob/r24.10/src/common.h#L48 - r24.10.
11. `grpc_server.cc` - https://github.com/triton-inference-server/server/blob/r24.10/src/grpc/grpc_server.cc#L2285 - r24.10.
12. Python gRPC client - https://github.com/triton-inference-server/client/blob/r24.10/src/python/library/tritonclient/grpc/_client.py#L51-L54 (and L201-L202) - r24.10.
13. C++ gRPC client - https://github.com/triton-inference-server/client/blob/r24.10/src/c%2B%2B/library/grpc_client.cc#L479-L480 - r24.10.
14. `command_line_parser.cc` (`--http-max-input-size`) - https://github.com/triton-inference-server/server/blob/r25.06/src/command_line_parser.cc#L502-L506 - r25.06 (absent on r24.10 to r25.05; present on main).
15. `common.h` (`HTTP_DEFAULT_MAX_INPUT_SIZE = 1 << 26`) - https://github.com/triton-inference-server/server/blob/r25.06/src/common.h#L58 - r25.06.
16. Shared-Memory Extension - https://github.com/triton-inference-server/server/blob/r24.10/docs/protocol/extension_shared_memory.md - r24.10.
17. `shared_memory_manager.cc` - https://github.com/triton-inference-server/server/blob/r24.10/src/shared_memory_manager.cc#L139-L256 - r24.10.
18. CUDA Runtime API, Device Management (`cudaIpcGetMemHandle`, `cudaIpcOpenMemHandle`) -
    https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html - page shows CUDA 13.4.
19. Python backend README (Managing Shared Memory, Input Tensor Device Placement) -
    https://github.com/triton-inference-server/python_backend/blob/r24.10/README.md - r24.10.
20. Python backend `GetInputTensor` - https://github.com/triton-inference-server/python_backend/blob/r24.10/src/python_be.cc#L349-L556 - r24.10.
21. `http_server.cc` (uses of `max_input_size_` at L2812-L2822 and L3104-L3113) - https://github.com/triton-inference-server/server/blob/r25.06/src/http_server.cc - r25.06.
22. `http_server.cc` and `data_compressor.h` (JSON size, decompression limit) - https://github.com/triton-inference-server/server/blob/r26.05/src/http_server.cc and
    https://github.com/triton-inference-server/server/blob/r26.05/src/data_compressor.h - r26.05.