Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs_new/docs/references/environment_variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1961,8 +1961,8 @@ SGLang supports various environment variables that can be used to configure its
</tr>
<tr>
<td style={{padding: "9px 12px", fontWeight: 500, backgroundColor: "rgba(255,255,255,0.02)"}}><code>SGLANG_USE_IPC_POOL_HANDLE_CACHE</code></td>
<td style={{padding: "9px 12px", backgroundColor: "rgba(255,255,255,0.05)"}}>Cache CUDA IPC pool handles.</td>
<td style={{padding: "9px 12px", backgroundColor: "rgba(255,255,255,0.02)"}}><code>false</code></td>
<td style={{padding: "9px 12px", backgroundColor: "rgba(255,255,255,0.05)"}}>When CUDA IPC multimodal feature transport is selected, reuse mappings to its existing bounded pool. This does not enable CUDA IPC transport or reserve another pool.</td>
<td style={{padding: "9px 12px", backgroundColor: "rgba(255,255,255,0.02)"}}><code>true</code></td>
</tr>
<tr>
<td style={{padding: "9px 12px", fontWeight: 500, backgroundColor: "rgba(255,255,255,0.02)"}}><code>SGLANG_MM_FEATURE_CACHE_MB</code></td>
Expand Down
4 changes: 3 additions & 1 deletion python/sglang/srt/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,9 @@ class Envs:

# VLM Item CUDA IPC Transport
SGLANG_USE_CUDA_IPC_TRANSPORT = EnvBool(False)
SGLANG_USE_IPC_POOL_HANDLE_CACHE = EnvBool(False)
# Reuse the mapping for the already-allocated bounded CUDA IPC pool. This
# has no effect unless CUDA IPC feature transport is explicitly selected.
SGLANG_USE_IPC_POOL_HANDLE_CACHE = EnvBool(True)
SGLANG_MM_FEATURE_CACHE_MB = EnvInt(1 * 1024)
SGLANG_MM_ITEM_MEM_POOL_RECYCLE_INTERVAL_SEC = EnvFloat(0.05)

Expand Down
7 changes: 4 additions & 3 deletions python/sglang/srt/multimodal/processors/base_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
_is_npu = is_npu()
_is_xpu = is_xpu()

_IPC_POOL_HANDLE_CACHE = envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.get()


@dataclasses.dataclass
class BaseMultiModalProcessorOutput:
Expand Down Expand Up @@ -198,6 +196,9 @@ def __init__(
else "cpu"
)
self.use_cuda_ipc = self.mm_feature_transport == "cuda_ipc"
self.use_ipc_pool_handle_cache = (
self.use_cuda_ipc and envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.get()
)
self.disable_fast_image_processor = server_args.disable_fast_image_processor
self.skip_tokenizer_init = server_args.skip_tokenizer_init

Expand Down Expand Up @@ -1255,7 +1256,7 @@ def _wrap_tensor_for_cuda_ipc(self, tensor: torch.Tensor):
sync_buffer_meta=sync_flag,
pool_ipc_handle=(
self.cudaipc_mmfeature_pool._pool_ipc_handle
if _IPC_POOL_HANDLE_CACHE
if self.use_ipc_pool_handle_cache
else None
),
Comment on lines 1257 to 1261

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To prevent potential AttributeErrors, it is safer to defensively check if self.cudaipc_mmfeature_pool is not None before attempting to access its _pool_ipc_handle attribute.

Suggested change
pool_ipc_handle=(
self.cudaipc_mmfeature_pool._pool_ipc_handle
if _IPC_POOL_HANDLE_CACHE
if self.use_ipc_pool_handle_cache
else None
),
pool_ipc_handle=(
self.cudaipc_mmfeature_pool._pool_ipc_handle
if (self.use_ipc_pool_handle_cache and self.cudaipc_mmfeature_pool is not None)
else None
),

pool_byte_offset=byte_offset,
Expand Down
10 changes: 10 additions & 0 deletions python/sglang/srt/server_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -6365,6 +6365,16 @@ def _handle_multimodal_feature_transport(self):
self.base_gpu_id,
self.tokenizer_worker_num,
)
logger.info(
"CUDA IPC pool-handle caching is %s. It reuses mappings to the "
"existing bounded pool without reserving another pool; set "
"SGLANG_USE_IPC_POOL_HANDLE_CACHE=0 to disable it.",
(
"enabled"
if envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.get()
else "disabled"
),
)

self.mm_feature_transport = requested_transport
# The bounded IPC pool owns device residency. Do not retain unpooled
Expand Down
24 changes: 22 additions & 2 deletions test/registered/unit/managers/test_mm_process_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from types import SimpleNamespace
from unittest.mock import MagicMock, patch

from sglang.srt.environ import envs
from sglang.srt.server_args import ServerArgs
from sglang.test.ci.ci_register import register_amd_ci, register_cuda_ci

Expand Down Expand Up @@ -128,7 +129,7 @@ def test_cuda_ipc_pool_uses_resolved_server_arg(self):
# transport policy must still resolve from the instance's ServerArgs.
from sglang.srt.multimodal.processors import base_processor

with patch.object(
with envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.override(True), patch.object(
base_processor.BaseMultimodalProcessor, "__abstractmethods__", set()
), patch.object(base_processor, "MmItemMemoryPool") as memory_pool:
processor = base_processor.BaseMultimodalProcessor(
Expand All @@ -140,12 +141,30 @@ def test_cuda_ipc_pool_uses_resolved_server_arg(self):

self.assertEqual(processor.mm_feature_transport, "cuda_ipc")
self.assertTrue(processor.use_cuda_ipc)
self.assertTrue(processor.use_ipc_pool_handle_cache)
memory_pool.assert_called_once()

def test_cuda_ipc_pool_handle_cache_can_be_disabled(self):
from sglang.srt.multimodal.processors import base_processor

with envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.override(False), patch.object(
base_processor.BaseMultimodalProcessor, "__abstractmethods__", set()
), patch.object(base_processor, "MmItemMemoryPool") as memory_pool:
processor = base_processor.BaseMultimodalProcessor(
hf_config=MagicMock(),
server_args=self._server_args("cuda_ipc"),
_processor=self._processor(),
transport_mode=None,
)

self.assertTrue(processor.use_cuda_ipc)
self.assertFalse(processor.use_ipc_pool_handle_cache)
memory_pool.assert_called_once()

def test_cpu_transport_does_not_allocate_ipc_pool(self):
from sglang.srt.multimodal.processors import base_processor

with patch.object(
with envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.override(True), patch.object(
base_processor.BaseMultimodalProcessor, "__abstractmethods__", set()
), patch.object(base_processor, "MmItemMemoryPool") as memory_pool:
processor = base_processor.BaseMultimodalProcessor(
Expand All @@ -157,6 +176,7 @@ def test_cpu_transport_does_not_allocate_ipc_pool(self):

self.assertEqual(processor.mm_feature_transport, "cpu")
self.assertFalse(processor.use_cuda_ipc)
self.assertFalse(processor.use_ipc_pool_handle_cache)
memory_pool.assert_not_called()


Expand Down
10 changes: 9 additions & 1 deletion test/registered/unit/server_args/test_server_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ def test_cuda_ipc_is_explicit_and_bounded(self, _mock_is_cuda):
base_gpu_id=2,
)

with patch.dict(os.environ, {"SGLANG_USE_CUDA_IPC_TRANSPORT": "0"}):
with patch.dict(
os.environ,
{
"SGLANG_USE_CUDA_IPC_TRANSPORT": "0",
"SGLANG_USE_IPC_POOL_HANDLE_CACHE": "1",
},
):
with self.assertLogs(server_args_module.logger, level="INFO") as logs:
server_args._handle_multimodal_feature_transport()

Expand All @@ -79,6 +85,8 @@ def test_cuda_ipc_is_explicit_and_bounded(self, _mock_is_cuda):
output = "\n".join(logs.output)
self.assertIn("base GPU 2", output)
self.assertIn("4 tokenizer worker", output)
self.assertIn("pool-handle caching is enabled", output)
self.assertIn("without reserving another pool", output)

@patch("sglang.srt.server_args.is_cuda", return_value=True)
def test_legacy_keep_flag_maps_to_cuda_ipc(self, _mock_is_cuda):
Expand Down
Loading