[BugFix] Dense multinode DP rescope with regression test (#49212)

Signed-off-by: Andy Lo <andy@mistral.ai> Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Andy Lo <andy@mistral.ai>

aoshen02 committed Aug 6, 2026 at 09:12 UTC 8cfa01cdd2357b4137f06c605e11634bef7cf8ba
3 files changed +38 -7
tests/test_config.py
+25
@@ -382,6 +382,31 @@ def test_async_scheduling_with_pipeline_parallelism_is_allowed():
382 assert cfg.scheduler_config.async_scheduling is True
383
384
385 +def test_reconfigure_for_independent_dp_rank_on_multinode_dense_model():
386 + parallel_config = ParallelConfig(
387 + tensor_parallel_size=8,
388 + data_parallel_size=2,
389 + data_parallel_size_local=1,
390 + data_parallel_rank=1,
391 + distributed_executor_backend="mp",
392 + nnodes=2,
393 + node_rank=1,
394 + )
395 +
396 + assert parallel_config.nnodes_within_dp == 1
397 + assert parallel_config.node_rank_within_dp == 0
398 +
399 + parallel_config.reconfigure_for_independent_dp_rank()
400 +
401 + assert parallel_config.data_parallel_size == 1
402 + assert parallel_config.data_parallel_size_local == 1
403 + assert parallel_config.data_parallel_rank == 0
404 + assert parallel_config.data_parallel_index == 1
405 + assert parallel_config.nnodes == 1
406 + assert parallel_config.node_rank == 0
407 + assert parallel_config.world_size == 8
408 +
409 +
410 @dataclass
411 class _TestConfigFields:
412 a: int
vllm/config/parallel.py
+11
@@ -1034,3 +1034,14 @@ class ParallelConfig:
1034 )
1035
1036 return self
1037 +
1038 + def reconfigure_for_independent_dp_rank(self) -> None:
1039 + """Reconfigure for a single independent non-MoE DP rank."""
1040 + # Capture these before changing DP fields.
1041 + nnodes = self.nnodes_within_dp
1042 + node_rank = self.node_rank_within_dp
1043 + self.data_parallel_size = 1
1044 + self.data_parallel_size_local = 1
1045 + self.data_parallel_rank = 0
1046 + self.nnodes = nnodes
1047 + self.node_rank = node_rank
vllm/v1/engine/core.py
+2 -7
@@ -1308,9 +1308,7 @@ class EngineCoreProc(EngineCore):
1308 # Non-MoE DP ranks are completely independent, so treat like DP=1.
1309 # Note that parallel_config.data_parallel_index will still reflect
1310 # the original DP rank.
1311 - parallel_config.data_parallel_size = 1
1312 - parallel_config.data_parallel_size_local = 1
1313 - parallel_config.data_parallel_rank = 0
1311 + parallel_config.reconfigure_for_independent_dp_rank()
1312 engine_core = EngineCoreProc(*args, engine_index=dp_rank, **kwargs)
1313
1314 assert engine_core is not None
@@ -2466,10 +2464,7 @@ class EngineCoreActor(EngineCoreActorMixin, EngineCoreProc):
2464 dp_rank: int = 0,
2465 local_dp_rank: int = 0,
2466 ):
2469 - vllm_config.parallel_config.data_parallel_size = 1
2470 - vllm_config.parallel_config.data_parallel_size_local = 1
2471 - vllm_config.parallel_config.data_parallel_rank = 0
2472 -
2467 + vllm_config.parallel_config.reconfigure_for_independent_dp_rank()
2468 EngineCoreActorMixin.__init__(
2469 self, vllm_config, addresses, dp_rank, local_dp_rank
2470 )