Skip to content

fix(serve): normalize worker TP for GPU assignment - #1085

Closed
smfirmin wants to merge 4 commits into
smg-project:mainfrom
smfirmin:sfirmin/serve-worker-tp-normalization
Closed

smfirmin wants to merge 4 commits into
smg-project:mainfrom
smfirmin:sfirmin/serve-worker-tp-normalization

Conversation

@smfirmin

@smfirmin smfirmin commented Apr 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

Problem

smg serve computes worker CUDA_VISIBLE_DEVICES before launching backend workers. For SGLang and vLLM, that computation depended on backend-specific parsed argument names.

In practice, SGLang accepts --tensor-parallel-size / --tp-size, but its TP value may be normalized differently from the raw CLI spelling. This causes SMG to compute worker GPU visibility as if tp=1 even when the worker itself starts with tp=4, leading to CUDA error: invalid device ordinal during worker startup.

There was a related mismatch risk for TRT-LLM as well: SMG could normalize hyphenated TP flags for the launched worker command, while still failing to use the same TP value for its own GPU assignment.

Solution

Normalize tensor parallel size once during parse_serve_args() into a single SMG-internal value used for worker GPU assignment.

This PR:

  • adds a canonical internal TP field for smg serve worker launch
  • resolves TP once per backend during parsing
  • makes gpu_env() use that canonical value instead of inferring TP from backend parser internals
  • keeps backend-specific parsing behavior intact while making SMG worker GPU slicing consistent

Changes

  • add canonical worker TP normalization in bindings/python/src/smg/serve.py
  • resolve SGLang/vLLM/TRT-LLM TP into one SMG-internal value during parse_serve_args()
  • update gpu_env() to use the canonical normalized TP value
  • preserve invalid TP values like 0 so existing validation still fails fast
  • support TRT-LLM TP flag spellings --tp_size, --tp-size, and --tensor-parallel-size for SMG-side GPU assignment
  • add tests covering:
    • SGLang normalization for worker launch
    • vLLM normalization for worker launch
    • invalid TP preservation
    • TP=4 GPU slices for dp rank 0 and 1
    • TRT-LLM TP flag spellings
    • TRT-LLM config fallback precedence

Test Plan

Repro before fix:

  1. Launch smg serve with SGLang and --tensor-parallel-size 4 or --tp-size 4.
  2. Observe SMG launching the worker with CUDA_VISIBLE_DEVICES=0.
  3. Observe the SGLang worker start with tp_size=4 and then fail with CUDA error: invalid device ordinal.

Expected behavior after fix:

  1. Launch smg serve with SGLang and --tensor-parallel-size 4.
  2. SMG should normalize TP to 4 before worker launch.
  3. gpu_env() should assign:
    • dp_rank=0 -> CUDA_VISIBLE_DEVICES=0,1,2,3
    • dp_rank=1 -> CUDA_VISIBLE_DEVICES=4,5,6,7

Targeted test run used for this change:

python - <<'PY'
import sys
import types
import pytest

sys.path.insert(0, 'bindings/python/src')

smg_rs = types.ModuleType('smg.smg_rs')
smg_rs.get_available_reasoning_parsers = lambda: []
smg_rs.get_available_tool_call_parsers = lambda: []
smg_rs.print_banner = lambda *args, **kwargs: None
sys.modules['smg.smg_rs'] = smg_rs

raise SystemExit(
    pytest.main([
        '-q',
        'bindings/python/tests/test_serve.py',
        '-k',
        'sglang_normalizes_tp_size_for_worker_launch or '
        'vllm_normalizes_tp_size_for_worker_launch or '
        'sglang_zero_tp_is_preserved_for_validation or '
        'sglang_tp_from_cli or '
        'vllm_tp_from_cli or '
        'trtllm_tp_from_cli or '
        'get_tp_size_sglang_and_vllm or '
        'get_tp_size_trtllm or '
        'gpu_env_tp_4_slices or '
        'launch_workers_passes_gpu_env or '
        'get_tp_size_from_config_tensor_parallel_size or '
        'get_tp_size_from_config_tp_size or '
        'get_tp_size_from_config_tensor_parallel_size_takes_precedence or '
        'get_tp_size_trtllm_explicit_cli_1_beats_config or '
        'gpu_env_raises_on_invalid_tp_size',
    ])
)
PY

Result:

  • 30 passed, 105 deselected

Note:

  • Full direct pytest collection is currently blocked in this environment by a local smg_rs extension mismatch during import, so the targeted serve test subset was run with a temporary import stub for smg.smg_rs.
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • (Optional) Documentation updated
  • (Optional) Please join us on Slack #sig-smg to discuss, review, and merge PRs

Summary by CodeRabbit

  • Improvements

    • Unified tensor-parallel size resolution across backends for consistent GPU worker assignment.
    • CLI accepts multiple aliases for tensor-parallel size and stores a single resolved value used for GPU partitioning.
    • Better precedence, defaults, and explicit warnings/errors when tensor-parallel size is missing or invalid.
  • Tests

    • Expanded coverage for CLI normalization, precedence, edge cases (including zero/invalid values), config errors, and GPU device partitioning.

@github-actions github-actions Bot added python-bindings Python bindings changes tests Test changes labels Apr 10, 2026
@coderabbitai

coderabbitai Bot commented Apr 10, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Centralized tensor-parallel (TP) size resolution: a shared resolver normalizes TP CLI/YAML inputs, stores a canonical TP on parsed args, and WorkerLauncher.gpu_env() uses this value across SGLang, vLLM, and TRT-LLM backends.

Changes

Cohort / File(s) Summary
Serve implementation
bindings/python/src/smg/serve.py
Added shared TP-size resolution that normalizes tensor_parallel_size/tp_size, stores _smg_worker_tp_size on parsed args, updated backend _get_tp_size() hooks to delegate to the resolver, unified TRT-LLM CLI stub aliases, and made WorkerLauncher.gpu_env() prefer the stored TP for CUDA_VISIBLE_DEVICES slicing.
Unit tests
bindings/python/tests/test_serve.py
Expanded tests to assert _SMG_TP_SIZE_ATTR normalization, TP alias/precedence behavior for SGLang/vLLM/TRT-LLM, TP edge cases (e.g., zero), TRT-LLM YAML/config error handling, and updated GPU partitioning expectations for TP=4.

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Parser
  participant Resolver
  participant Launcher
  participant Backend

  CLI->>Parser: provide args (aliases: --tp_size, --tp-size, --tensor-parallel-size)
  Parser->>Resolver: request canonical TP (check namespace & config)
  Resolver->>Parser: store `_smg_worker_tp_size` on namespace
  Launcher->>Parser: read `_smg_worker_tp_size` (preferred)
  alt `_smg_worker_tp_size` missing
    Launcher->>Backend: call backend._get_tp_size() (may read config/args)
    Backend->>Resolver: (backend-specific) resolver returns TP
    Resolver->>Launcher: TP value
  end
  Launcher->>Launcher: compute CUDA_VISIBLE_DEVICES slice using TP and dp_rank
  Launcher->>Backend: launch worker with computed GPU env
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested reviewers

  • CatherineSue
  • key4ng
  • slin1237
  • gongwei-130

Poem

🐰
I hopped through flags both hyphen and snake,
Found one true TP for each parsed intake.
Parsers now stash it—canonical and neat,
Workers carve devices so launches seat.
Carrots for tests, and bugs take a backseat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(serve): normalize worker TP for GPU assignment' directly and specifically describes the main change—normalizing tensor-parallel size computation for proper GPU assignment to backend workers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify

mergify Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Hi @smfirmin, the DCO sign-off check has failed. All commits must include a Signed-off-by line.

To fix existing commits:

# Sign off the last N commits (replace N with the number of unsigned commits)
git rebase HEAD~N --signoff
git push --force-with-lease

To sign off future commits automatically:

  • Use git commit -s every time, or
  • VSCode: enable Git: Always Sign Off in Settings
  • PyCharm: enable Sign-off commit in the Commit tool window

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request centralizes Tensor Parallel (TP) size resolution across SGLang, vLLM, and TRT-LLM backends by introducing normalized resolution helpers and updating worker launchers. Feedback highlights the omission of the --config argument in the TRT-LLM parser and suggests implementing explicit encoding and type validation when parsing YAML configuration files.

Comment thread bindings/python/src/smg/serve.py
Comment thread bindings/python/src/smg/serve.py Outdated
@smfirmin
smfirmin force-pushed the sfirmin/serve-worker-tp-normalization branch from 3246ba2 to 5447bd4 Compare April 10, 2026 03:51
@slin1237

Copy link
Copy Markdown
Member

@gongwei-130 can you take a look at this PR
much appreciated

@smfirmin
smfirmin force-pushed the sfirmin/serve-worker-tp-normalization branch from 1808a50 to 6609400 Compare April 10, 2026 05:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/python/src/smg/serve.py`:
- Around line 73-74: Open the YAML config file with an explicit encoding (e.g.,
use open(config_path, encoding='utf-8')) to avoid platform-dependent behavior,
and after yaml.safe_load(f) validate that the returned config is a mapping/dict
(the variable config) — if it is None or not a dict, raise a clear error
indicating the config is empty or malformed; update the code paths that use
config to rely on this validated dict (references: the open(config_path) call
and the config variable resulting from yaml.safe_load).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1cfc4316-e5d5-43e1-b3a8-49daa75827cf

📥 Commits

Reviewing files that changed from the base of the PR and between 3246ba2 and 582d79a.

📒 Files selected for processing (2)
  • bindings/python/src/smg/serve.py
  • bindings/python/tests/test_serve.py

Comment thread bindings/python/src/smg/serve.py Outdated
Signed-off-by: Sydney Firmin <sydney.firmin@oracle.com>
@smfirmin
smfirmin force-pushed the sfirmin/serve-worker-tp-normalization branch from 582d79a to f6ec618 Compare April 10, 2026 05:35
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had any activity within 14 days. It will be automatically closed if no further activity occurs within 16 days. Leave a comment if you feel this pull request should remain open. Thank you!

@github-actions github-actions Bot added the stale PR has been inactive for 14+ days label Apr 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindings/python/src/smg/serve.py`:
- Around line 483-490: parse_serve_args() is caching _smg_worker_tp_size before
args.config is available because the stub parser never parses --config; update
the flow so the TRT-LLM config is parsed into the same namespace before caching
TP (either by declaring --config on the stub parser or by explicitly
loading/parsing the config YAML into args.config prior to computing
_smg_worker_tp_size), ensuring _resolve_trtllm_tp_size() sees args.config and
gpu_env() gets the correct tensor_parallel_size (tensor_parallel_size,
_smg_worker_tp_size, backend_args, args.config, _resolve_trtllm_tp_size,
gpu_env()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b152ff33-ec74-4a61-988c-99bca8e4ae75

📥 Commits

Reviewing files that changed from the base of the PR and between 582d79a and a080b51.

📒 Files selected for processing (2)
  • bindings/python/src/smg/serve.py
  • bindings/python/tests/test_serve.py

Comment on lines +483 to +490
group.add_argument(
"--tp_size",
"--tp-size",
"--tensor-parallel-size",
dest="tensor_parallel_size",
type=int,
help="Tensor parallel size (overrides config file)",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Parse --config into the TRT-LLM namespace before caching TP.

parse_serve_args() now computes _smg_worker_tp_size from args, but --config is still left in backend_args because this stub parser never declares it. On a config-only TRT-LLM launch, _resolve_trtllm_tp_size() never sees args.config, caches 1, and gpu_env() slices GPUs for TP=1 even though the worker can still start with tensor_parallel_size > 1 from YAML. That recreates the same invalid-device-ordinal failure this PR is trying to eliminate.

🐛 Minimal fix
 def _add_trtllm_stub_args(parser: argparse.ArgumentParser) -> None:
     """Add TensorRT-LLM specific arguments.
@@
     group = parser.add_argument_group("TensorRT-LLM Options")
+    group.add_argument(
+        "--config",
+        type=str,
+        help="Path to TRT-LLM YAML config",
+    )
     group.add_argument(
         "--model",
         "--model-path",
         dest="model_path",
         type=str,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/python/src/smg/serve.py` around lines 483 - 490, parse_serve_args()
is caching _smg_worker_tp_size before args.config is available because the stub
parser never parses --config; update the flow so the TRT-LLM config is parsed
into the same namespace before caching TP (either by declaring --config on the
stub parser or by explicitly loading/parsing the config YAML into args.config
prior to computing _smg_worker_tp_size), ensuring _resolve_trtllm_tp_size() sees
args.config and gpu_env() gets the correct tensor_parallel_size
(tensor_parallel_size, _smg_worker_tp_size, backend_args, args.config,
_resolve_trtllm_tp_size, gpu_env()).

@github-actions github-actions Bot removed the stale PR has been inactive for 14+ days label Apr 29, 2026
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had any activity within 14 days. It will be automatically closed if no further activity occurs within 16 days. Leave a comment if you feel this pull request should remain open. Thank you!

@github-actions github-actions Bot added the stale PR has been inactive for 14+ days label May 13, 2026
@smfirmin

Copy link
Copy Markdown
Contributor Author

@gongwei-130 have you had a chance to review this?

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f114cca4a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +484 to +487
"--tp_size",
"--tp-size",
"--tensor-parallel-size",
dest="tensor_parallel_size",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept TRT-LLM's native tensor_parallel_size flag

For TRT-LLM, NVIDIA's trtllm-serve help documents the CLI spelling as --tensor_parallel_size, --tp_size <tensor_parallel_size>. If a user passes that native underscore form through smg serve --backend trtllm --tensor_parallel_size 4, parse_known_args leaves it in backend_args so the worker still launches with TP=4, but this stub never parses it and _resolve_worker_tp_size falls back to 1 for CUDA_VISIBLE_DEVICES; with DP workers this recreates the invalid GPU slicing this change is trying to prevent. Add --tensor_parallel_size to this alias list as well.

Useful? React with 👍 / 👎.

@github-actions github-actions Bot removed the stale PR has been inactive for 14+ days label May 16, 2026
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had any activity within 14 days. It will be automatically closed if no further activity occurs within 16 days. Leave a comment if you feel this pull request should remain open. Thank you!

@github-actions github-actions Bot added the stale PR has been inactive for 14+ days label May 30, 2026
@github-actions

Copy link
Copy Markdown

This pull request has been automatically closed due to inactivity. Please feel free to reopen if you intend to continue working on it. Thank you!

@github-actions github-actions Bot closed this Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python-bindings Python bindings changes stale PR has been inactive for 14+ days tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants