Skip to content

[None][build] Use cp -rL and skip up-to-date copies in copy_resolving_symlink#16020

Merged
brnguyen2 merged 2 commits into
NVIDIA:mainfrom
brnguyen2:brnguyen/build-wheel-copy-speedup
Jul 7, 2026
Merged

[None][build] Use cp -rL and skip up-to-date copies in copy_resolving_symlink#16020
brnguyen2 merged 2 commits into
NVIDIA:mainfrom
brnguyen2:brnguyen/build-wheel-copy-speedup

Conversation

@brnguyen2

@brnguyen2 brnguyen2 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • copy_resolving_symlink was unconditionally deleting and re-copying large directory trees (e.g. CUTLASS headers) on every build. On network-mounted filesystems this can take several minutes even when nothing changed.
  • Add an mtime check: if the destination already exists and is at least as new as the resolved source, skip the copy entirely.
  • When a copy is needed, shell out to cp -rL instead of Python copytree. cp uses copy_file_range(2) on Linux, which triggers a server-side copy on NFSv4.2 servers, and uses larger I/O buffers than Python shutil. Falls back to copytree if cp is unavailable.

Test plan

  • Incremental build: verify that the CUTLASS header copy is skipped when nothing changed
  • Clean build: verify that the copy runs and produces a correct result
  • Non-Linux / minimal container: verify fallback to copytree when cp is unavailable

Summary by CodeRabbit

  • Bug Fixes
    • Improved rebuild behavior so unchanged generated files are no longer recopied unnecessarily.
    • Reduced build time for incremental updates by skipping work when staged content is already current.
    • Made file copying more efficient when updates are needed, with a safe fallback if the faster path isn’t available.

…_symlink

copy_resolving_symlink was unconditionally deleting and re-copying large
directory trees (e.g. CUTLASS headers) on every build. On network-mounted
filesystems this can take several minutes even when nothing changed.

Add an mtime check: if the destination already exists and is at least as
new as the resolved source, skip the copy. The source mtime advances
whenever CMake rebuilds the target, so this correctly invalidates the
cache on real rebuilds while skipping no-op incremental runs.

When a copy is needed, shell out to cp -rL instead of Python copytree.
cp uses kernel-level copy primitives that are significantly faster on
NFS. Falls back to copytree if cp is unavailable.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The copy_resolving_symlink helper in scripts/build_wheel.py was modified to avoid unnecessary directory copies during DeepGEMM JIT header staging. It now compares source/destination modification times to skip up-to-date copies, and uses cp -rL for faster symlink-dereferencing copies, falling back to copytree if needed.

Changes

Incremental Copy Optimization

Layer / File(s) Summary
Skip-if-current copy with cp fallback
scripts/build_wheel.py
copy_resolving_symlink now skips directory copy when destination mtime is at least as new as source mtime; otherwise uses cp -rL for dereferencing symlinks, falling back to copytree if cp fails or is unavailable.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific, concise, and matches the main change to copy_resolving_symlink.
Description check ✅ Passed The description explains the change and includes a test plan, but it omits the template's PR Checklist section.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/build_wheel.py (1)

846-849: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Partial executable path for cp (S607).

Static analysis flags the partial path "cp" in the subprocess call. Args are static (no untrusted input, no shell=True), so exploitability is low, but resolving to an absolute path hardens against $PATH tampering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build_wheel.py` around lines 846 - 849, The subprocess call in the
build_wheel copy step uses a bare "cp" executable, which should be hardened
against PATH tampering. Update the run invocation in the copy logic to resolve
the cp binary via an absolute path (or an explicit, trusted executable location)
while keeping the same arguments and check=True behavior, so the existing copy
flow in the build_wheel script remains unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build_wheel.py`:
- Around line 845-851: The copy fallback in the wheel build logic is too broad
because `FileNotFoundError` is redundant with `Exception`, and the current
`except (FileNotFoundError, Exception)` around the `run(...)` call in
`build_wheel.py` will also hide real `CalledProcessError` failures from `cp`.
Update the `copytree` fallback in this block to catch only the specific
missing-command or missing-path case you actually want to recover from, and let
other subprocess failures propagate instead of being silently retried.
- Around line 836-840: The directory up-to-date check in the copy/sync logic can
incorrectly skip real updates because it only compares the top-level mtime for
resolved_src and dst_path. Update the logic in the directory-handling path of
the wheel build copy routine to use a recursive fingerprint of the directory
contents or a generated stamp file instead of relying on directory mtimes, so
nested changes under cutlass, cuda_ptx, or trtllm are detected before returning
early.

---

Nitpick comments:
In `@scripts/build_wheel.py`:
- Around line 846-849: The subprocess call in the build_wheel copy step uses a
bare "cp" executable, which should be hardened against PATH tampering. Update
the run invocation in the copy logic to resolve the cp binary via an absolute
path (or an explicit, trusted executable location) while keeping the same
arguments and check=True behavior, so the existing copy flow in the build_wheel
script remains unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 41381f2d-2335-4a01-903a-c345cc208fec

📥 Commits

Reviewing files that changed from the base of the PR and between a0c406f and 20b4740.

📒 Files selected for processing (1)
  • scripts/build_wheel.py

Comment thread scripts/build_wheel.py
Comment thread scripts/build_wheel.py Outdated
Replace mtime-on-dst check with a stamp file so partial/interrupted copies
are not incorrectly skipped on the next build. Narrow the except clause to
FileNotFoundError only so cp errors propagate instead of silently falling
back to copytree. Use shutil.which("cp") to resolve the binary path and
skip the subprocess path entirely when cp is not available.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
@brnguyen2

Copy link
Copy Markdown
Collaborator Author

/bot help

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

GitHub Bot Help

/bot [-h] ['run', 'kill', 'skip', 'reuse-pipeline'] ...

Provide a user friendly way for developers to interact with a Jenkins server.

Run /bot [-h|--help] to print this help message.

See details below for each supported subcommand.

Details

run [--reuse-test (optional)pipeline-id --disable-fail-fast --skip-test --stage-list "A10-PyTorch-1, xxx" --gpu-type "A30, H100_PCIe" --test-backend "pytorch, cpp" --add-multi-gpu-test --only-multi-gpu-test --disable-multi-gpu-test --post-merge --extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx" --detailed-log --debug(experimental) --high-priority]

Launch build/test pipelines. All previously running jobs will be killed.

--reuse-test (optional)pipeline-id (OPTIONAL) : Allow the new pipeline to reuse build artifacts and skip successful test stages from a specified pipeline or the last pipeline if no pipeline-id is indicated. If the Git commit ID has changed, this option will be always ignored. The DEFAULT behavior of the bot is to reuse build artifacts and successful test results from the last pipeline.

--disable-reuse-test (OPTIONAL) : Explicitly prevent the pipeline from reusing build artifacts and skipping successful test stages from a previous pipeline. Ensure that all builds and tests are run regardless of previous successes.

--disable-fail-fast (OPTIONAL) : Disable fail fast on build/tests/infra failures.

--skip-test (OPTIONAL) : Skip all test stages, but still run build stages, package stages and sanity check stages. Note: Does NOT update GitHub check status.

--stage-list "A10-PyTorch-1, xxx" (OPTIONAL) : Only run the specified test stages. Supports wildcard * for pattern matching (e.g., "*PerfSanity*" matches all stages containing PerfSanity). Examples: "A10-PyTorch-1, xxx", "PerfSanity". Note: Does NOT update GitHub check status.

--gpu-type "A30, H100_PCIe" (OPTIONAL) : Only run the test stages on the specified GPU types. Examples: "A30, H100_PCIe". Note: Does NOT update GitHub check status.

--test-backend "pytorch, cpp" (OPTIONAL) : Skip test stages which don't match the specified backends. Only support [pytorch, cpp, tensorrt, triton]. Examples: "pytorch, cpp" (does not run test stages with tensorrt or triton backend). Note: Does NOT update GitHub pipeline status.

--only-multi-gpu-test (OPTIONAL) : Only run the multi-GPU tests. Note: Does NOT update GitHub check status.

--disable-multi-gpu-test (OPTIONAL) : Disable the multi-GPU tests. Note: Does NOT update GitHub check status.

--add-multi-gpu-test (OPTIONAL) : Force run the multi-GPU tests in addition to running L0 pre-merge pipeline.

--post-merge (OPTIONAL) : Run the L0 post-merge pipeline instead of the ordinary L0 pre-merge pipeline.

--extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx" (OPTIONAL) : Run the ordinary L0 pre-merge pipeline and specified test stages. Supports wildcard * for pattern matching. Examples: --extra-stage "H100_PCIe-TensorRT-Post-Merge-1, xxx", --extra-stage "Post-Merge".

--detailed-log (OPTIONAL) : Enable flushing out all logs to the Jenkins console. This will significantly increase the log volume and may slow down the job.

--debug (OPTIONAL) : Experimental feature. Enable access to the CI container for debugging purpose. Note: Specify exactly one stage in the stage-list parameter to access the appropriate container environment. Note: Does NOT update GitHub check status.

--high-priority (OPTIONAL) : Run the pipeline with high priority. This option is restricted to authorized users only and will route the job to a high-priority queue.

kill

kill

Kill all running builds associated with pull request.

skip

skip --comment COMMENT

Skip testing for latest commit on pull request. --comment "Reason for skipping build/test" is required. IMPORTANT NOTE: This is dangerous since lack of user care and validation can cause top of tree to break.

reuse-pipeline

reuse-pipeline

Reuse a previous pipeline to validate current commit. This action will also kill all currently running builds associated with the pull request. IMPORTANT NOTE: This is dangerous since lack of user care and validation can cause top of tree to break.

@brnguyen2

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57878 [ run ] triggered by Bot. Commit: ed774dc Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57878 [ run ] completed with state SUCCESS. Commit: ed774dc
/LLM/main/L0_MergeRequest_PR pipeline #46574 completed with status: 'SUCCESS'
Pipeline passed with automatic retried tests. Check the rerun report for details.

CI Report

Link to invocation

@brnguyen2 brnguyen2 requested a review from tburt-nv July 7, 2026 17:53

@tburt-nv tburt-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was concerned the stamp files would end up in the wheel, but since they begin with . they should be excluded by the glob here:

"include/**/*",

@brnguyen2 brnguyen2 merged commit c9228d8 into NVIDIA:main Jul 7, 2026
6 of 7 checks passed
crazydemo pushed a commit to crazydemo/TensorRT-LLM that referenced this pull request Jul 8, 2026
…_symlink (NVIDIA#16020)

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
BrianLi23 pushed a commit to BrianLi23/TensorRT-LLM that referenced this pull request Jul 9, 2026
…_symlink (NVIDIA#16020)

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants