From 9d7e6ff62dba858071f5a0faf30cd98a42e0855b Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 10 Jun 2026 10:56:24 -0400 Subject: [PATCH 1/3] [cdac pipeline] Add shared CdacBuild stage for dump+stress tests Adds a per-platform CdacBuild stage that builds coreclr (Checked) + libs + tools.cdac + the cDAC dump+stress test subsets, then publishes artifacts/bin as a CdacBuildArtifacts_ tar. Subsequent commits will switch CdacDumpTests, CdacStressTests, and the CdacXPlat stages to consume this artifact instead of each running their own full build. The matrix uses cdacDumpPlatforms (the broader 8-platform set); CdacStressTests' 4-platform subset is still satisfied since per-platform artifacts are independent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/pipelines/runtime-diagnostics.yml | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/eng/pipelines/runtime-diagnostics.yml b/eng/pipelines/runtime-diagnostics.yml index f13e62a096b366..8f8dc544f2cac2 100644 --- a/eng/pipelines/runtime-diagnostics.yml +++ b/eng/pipelines/runtime-diagnostics.yml @@ -278,6 +278,39 @@ extends: continueOnError: true condition: failed() + # + # cDAC Shared Build — One coreclr+libs build per platform, consumed by + # both CdacDumpTests and CdacStressTests (and the X-plat dump stages) + # so we don't rebuild coreclr per test leg. Runtime is built Checked; + # cDAC native shim ships in the Release testhost (used by stress tests + # in-process); dump tests will rebuild the cDAC managed assemblies at + # /p:Configuration=Debug during payload prep. + # + - ${{ if ne(variables['Build.Reason'], 'Schedule') }}: + - stage: CdacBuild + dependsOn: [] + jobs: + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: release + platforms: ${{ parameters.cdacDumpPlatforms }} + jobParameters: + nameSuffix: CdacBuild + buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests+tools.cdacstresstests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 + isOfficialBuild: ${{ variables.isOfficialBuild }} + timeoutInMinutes: 180 + postBuildSteps: + - template: /eng/pipelines/common/upload-artifact-step.yml + parameters: + rootFolder: $(Build.SourcesDirectory)/artifacts/bin + includeRootFolder: false + archiveType: $(archiveType) + archiveExtension: $(archiveExtension) + tarCompression: $(tarCompression) + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + displayName: cDAC Shared Build Artifacts + # # cDAC Dump Tests — Build, generate dumps, and run tests on Helix (single-leg mode) # From 7806205bb5fe83d5d45ea9afaa24dba04907cc98 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 10 Jun 2026 11:00:02 -0400 Subject: [PATCH 2/3] [cdac pipeline] Consume shared CdacBuild artifact in dump+stress stages CdacDumpTests, CdacStressTests, CdacXPlatDumpGen, and CdacXPlatDumpTests now download the per-platform CdacBuildArtifacts_ tar published by CdacBuild instead of each running their own full clr+libs+tools.cdac+... build. Each test leg still calls ./build.sh with a minimal subset (tools.cdactests) so .dotnet is initialized and MSBuild can re-link the test csproj against the downloaded artifact -- no coreclr or libs work is repeated. Adds a cdacTestConfig parameter to prepare-cdac-helix-steps.yml (default $(_BuildConfig) for back-compat); dump-test stages pass cdacTestConfig: Debug so the dotnet build invocations that build the debuggees and prepare the Helix payload pull in the Debug-configured managed cDAC assemblies that the DumpTests project loads directly. The stress stage keeps the Release native cDAC shim that ships in the shared testhost. Cross-platform job-name expansion uses dependsOnGlobalBuilds rather than a hand-rolled build___CdacBuild string. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../cdac/prepare-cdac-helix-steps.yml | 9 ++- eng/pipelines/runtime-diagnostics.yml | 67 +++++++++++++++++-- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/eng/pipelines/cdac/prepare-cdac-helix-steps.yml b/eng/pipelines/cdac/prepare-cdac-helix-steps.yml index c3b61807915e56..d06fbb3e8d8461 100644 --- a/eng/pipelines/cdac/prepare-cdac-helix-steps.yml +++ b/eng/pipelines/cdac/prepare-cdac-helix-steps.yml @@ -7,13 +7,18 @@ parameters: buildDebuggees: true skipDebuggeeCopy: false runtimeConfiguration: 'Checked' + # Configuration used to rebuild the cDAC managed assemblies + DumpTests + # csproj during payload prep. The dump tests load the managed cDAC + # directly, so we ship Debug binaries here even when the rest of the + # build is Release. Defaults to $(_BuildConfig) for backward compatibility. + cdacTestConfig: '$(_BuildConfig)' steps: - ${{ if parameters.buildDebuggees }}: - script: $(Build.SourcesDirectory)$(dir).dotnet$(dir)dotnet$(exeExt) msbuild $(Build.SourcesDirectory)/src/native/managed/cdac/tests/DumpTests/Microsoft.Diagnostics.DataContractReader.DumpTests.csproj /t:BuildDebuggeesOnly - /p:Configuration=$(_BuildConfig) + /p:Configuration=${{ parameters.cdacTestConfig }} /p:TargetArchitecture=$(archType) /p:RuntimeConfiguration=${{ parameters.runtimeConfiguration }} -bl:$(Build.SourcesDirectory)/artifacts/log/BuildDebuggees.binlog @@ -23,7 +28,7 @@ steps: $(Build.SourcesDirectory)/src/native/managed/cdac/tests/DumpTests/Microsoft.Diagnostics.DataContractReader.DumpTests.csproj /p:PrepareHelixPayload=true /p:SkipDebuggeeCopy=${{ parameters.skipDebuggeeCopy }} - /p:Configuration=$(_BuildConfig) + /p:Configuration=${{ parameters.cdacTestConfig }} /p:HelixPayloadDir=$(Build.SourcesDirectory)/artifacts/helixPayload/cdac /p:SkipDumpVersions=net10.0 -bl:$(Build.SourcesDirectory)/artifacts/log/DumpTestPayload.binlog diff --git a/eng/pipelines/runtime-diagnostics.yml b/eng/pipelines/runtime-diagnostics.yml index 8f8dc544f2cac2..58560d661c0bec 100644 --- a/eng/pipelines/runtime-diagnostics.yml +++ b/eng/pipelines/runtime-diagnostics.yml @@ -316,7 +316,8 @@ extends: # - ${{ if and(eq(parameters.cdacDumpTestMode, 'single-leg'), ne(variables['Build.Reason'], 'Schedule')) }}: - stage: CdacDumpTests - dependsOn: [] + dependsOn: + - CdacBuild jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -326,10 +327,24 @@ extends: shouldContinueOnError: true jobParameters: nameSuffix: CdacDumpTest - buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 + # Tiny rebuild that triggers .dotnet init; coreclr+libs+tools.cdac + # come from CdacBuildArtifacts. prepare-cdac-helix-steps below + # rebuilds the cDAC managed assemblies at Debug for the dump tests. + buildArgs: -s tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 timeoutInMinutes: 180 + dependsOnGlobalBuilds: + - nameSuffix: CdacBuild + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + artifactFileName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + displayName: 'cDAC Shared Build Artifacts' postBuildSteps: - template: /eng/pipelines/cdac/prepare-cdac-helix-steps.yml + parameters: + cdacTestConfig: Debug - template: /eng/pipelines/common/templates/runtimes/send-to-helix-inner-step.yml parameters: displayName: 'Send cDAC Dump Tests to Helix' @@ -360,7 +375,8 @@ extends: # - ${{ if ne(variables['Build.Reason'], 'Schedule') }}: - stage: CdacStressTests - dependsOn: [] + dependsOn: + - CdacBuild jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -370,8 +386,19 @@ extends: shouldContinueOnError: true jobParameters: nameSuffix: CdacStressTest - buildArgs: -s clr+libs+tools.cdac+tools.cdacstresstests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) + # Tiny rebuild that triggers .dotnet init; coreclr+libs+tools.cdac + # come from CdacBuildArtifacts and aren't rebuilt. + buildArgs: -s tools.cdacstresstests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) timeoutInMinutes: 180 + dependsOnGlobalBuilds: + - nameSuffix: CdacBuild + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + artifactFileName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + displayName: 'cDAC Shared Build Artifacts' postBuildSteps: - template: /eng/pipelines/cdac/prepare-cdac-stress-helix-steps.yml - template: /eng/pipelines/common/templates/runtimes/send-to-helix-inner-step.yml @@ -408,7 +435,8 @@ extends: # - ${{ if or(eq(parameters.cdacDumpTestMode, 'xplat'), eq(variables['Build.Reason'], 'Schedule')) }}: - stage: CdacXPlatDumpGen - dependsOn: [] + dependsOn: + - CdacBuild jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -418,10 +446,21 @@ extends: shouldContinueOnError: true jobParameters: nameSuffix: CdacXPlatDumpGen - buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 + buildArgs: -s tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 timeoutInMinutes: 180 + dependsOnGlobalBuilds: + - nameSuffix: CdacBuild + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + artifactFileName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + displayName: 'cDAC Shared Build Artifacts' postBuildSteps: - template: /eng/pipelines/cdac/prepare-cdac-helix-steps.yml + parameters: + cdacTestConfig: Debug - template: /eng/pipelines/common/templates/runtimes/send-to-helix-inner-step.yml parameters: displayName: 'Send cDAC Dump Gen to Helix' @@ -455,6 +494,7 @@ extends: - stage: CdacXPlatDumpTests dependsOn: + - CdacBuild - CdacXPlatDumpGen jobs: - template: /eng/pipelines/common/platform-matrix.yml @@ -465,10 +505,23 @@ extends: shouldContinueOnError: true jobParameters: nameSuffix: CdacXPlatDumpTest - buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 + buildArgs: -s tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 timeoutInMinutes: 180 + dependsOnGlobalBuilds: + - nameSuffix: CdacBuild + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + artifactFileName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + displayName: 'cDAC Shared Build Artifacts' postBuildSteps: - template: /eng/pipelines/cdac/prepare-cdac-helix-steps.yml + parameters: + buildDebuggees: false + skipDebuggeeCopy: true + cdacTestConfig: Debug parameters: buildDebuggees: false skipDebuggeeCopy: true From 6d9496d8fcd98532687cbccbf171a2e0a3e60d14 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 10 Jun 2026 11:05:06 -0400 Subject: [PATCH 3/3] [cdac pipeline] Collapse to single Cdac stage for per-platform parallelism Moves CdacBuild + CdacDumpTests + CdacStressTests + CdacXPlatDumpGen into a single `Cdac` stage. Within that stage, every test job uses job-level `dependsOnGlobalBuilds: - nameSuffix: CdacBuild` which the global-build-job template expands to a per-platform `build___CdacBuild` dep. This is the canonical dotnet/runtime pattern (runtime.yml:1591,1622,1653) and means `linux_x64` test legs start as soon as `linux_x64`'s build finishes -- no waiting on slower platforms' builds. Previously each test stage had a stage-level `dependsOn: CdacBuild` which is all-or-nothing in AzDO -- every platform's tests had to wait for the slowest platform's build to finish before starting. The single-leg / xplat / stress / schedule selection moves from stage-level `${{ if }}` to job-level `${{ if }}` inside the Cdac stage. CdacXPlatDumpTests stays as a separate stage with stage-level `dependsOn: Cdac` because its cross-platform synchronization (every target platform's test needs every source platform's dumps) is intrinsic. Its previous job-level `dependsOnGlobalBuilds: CdacBuild` is dropped -- AzDO doesn't support cross-stage job-level deps, and the stage-level dep already gates everything correctly. Also fixes a duplicate `parameters:` block in CdacXPlatDumpTests that was a merge artifact from the previous commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/pipelines/runtime-diagnostics.yml | 118 ++++++++++++-------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/eng/pipelines/runtime-diagnostics.yml b/eng/pipelines/runtime-diagnostics.yml index 58560d661c0bec..ba09a9ba7ae0c4 100644 --- a/eng/pipelines/runtime-diagnostics.yml +++ b/eng/pipelines/runtime-diagnostics.yml @@ -279,46 +279,45 @@ extends: condition: failed() # - # cDAC Shared Build — One coreclr+libs build per platform, consumed by - # both CdacDumpTests and CdacStressTests (and the X-plat dump stages) - # so we don't rebuild coreclr per test leg. Runtime is built Checked; - # cDAC native shim ships in the Release testhost (used by stress tests - # in-process); dump tests will rebuild the cDAC managed assemblies at - # /p:Configuration=Debug during payload prep. + # cDAC Stage — single stage containing the shared build + all per-platform + # test legs (dump tests, stress tests, x-plat dump generation). Putting + # them in one stage lets each test job depend on its OWN platform's + # CdacBuild job via job-level `dependsOnGlobalBuilds`, so linux_x64 dump + # tests start as soon as linux_x64 build is done -- no waiting for the + # slowest platform's build. # - - ${{ if ne(variables['Build.Reason'], 'Schedule') }}: - - stage: CdacBuild - dependsOn: [] - jobs: - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - platforms: ${{ parameters.cdacDumpPlatforms }} - jobParameters: - nameSuffix: CdacBuild - buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests+tools.cdacstresstests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 - isOfficialBuild: ${{ variables.isOfficialBuild }} - timeoutInMinutes: 180 - postBuildSteps: - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/artifacts/bin - includeRootFolder: false - archiveType: $(archiveType) - archiveExtension: $(archiveExtension) - tarCompression: $(tarCompression) - artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) - displayName: cDAC Shared Build Artifacts - - # - # cDAC Dump Tests — Build, generate dumps, and run tests on Helix (single-leg mode) + # Runtime is built Checked; the cDAC native shim ships in the Release + # testhost (used by stress tests in-process); dump tests rebuild the + # cDAC managed assemblies at /p:Configuration=Debug during payload prep. # - - ${{ if and(eq(parameters.cdacDumpTestMode, 'single-leg'), ne(variables['Build.Reason'], 'Schedule')) }}: - - stage: CdacDumpTests - dependsOn: - - CdacBuild - jobs: + - stage: Cdac + dependsOn: [] + jobs: + # ---- Shared per-platform build (always runs; downstream jobs depend on + # this via job-level dependsOnGlobalBuilds: - nameSuffix: CdacBuild) ---- + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: release + platforms: ${{ parameters.cdacDumpPlatforms }} + jobParameters: + nameSuffix: CdacBuild + buildArgs: -s clr+libs+tools.cdac+tools.cdacdumptests+tools.cdacstresstests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 + isOfficialBuild: ${{ variables.isOfficialBuild }} + timeoutInMinutes: 180 + postBuildSteps: + - template: /eng/pipelines/common/upload-artifact-step.yml + parameters: + rootFolder: $(Build.SourcesDirectory)/artifacts/bin + includeRootFolder: false + archiveType: $(archiveType) + archiveExtension: $(archiveExtension) + tarCompression: $(tarCompression) + artifactName: CdacBuildArtifacts_$(osGroup)$(osSubgroup)_$(archType) + displayName: cDAC Shared Build Artifacts + + # ---- cDAC Dump Tests (single-leg mode, not on schedule) ---- + - ${{ if and(eq(parameters.cdacDumpTestMode, 'single-leg'), ne(variables['Build.Reason'], 'Schedule')) }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml @@ -368,16 +367,8 @@ extends: displayName: 'Fail on test errors' condition: always() - # - # cDAC GC Stress Tests — runs in-process cDAC vs runtime stack-ref - # verification at GC stress points. Independent stage with its own build - # so its status/failures don't get conflated with the dump tests. - # - - ${{ if ne(variables['Build.Reason'], 'Schedule') }}: - - stage: CdacStressTests - dependsOn: - - CdacBuild - jobs: + # ---- cDAC GC Stress Tests (not on schedule) ---- + - ${{ if ne(variables['Build.Reason'], 'Schedule') }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml @@ -428,16 +419,8 @@ extends: continueOnError: true condition: failed() - # - # cDAC X-Plat Dump Generation and Testing — Two-stage flow: - # 1. Generate dumps on each platform via Helix, download and publish as artifacts - # 2. Download all platforms' dumps and run tests on each target platform - # - - ${{ if or(eq(parameters.cdacDumpTestMode, 'xplat'), eq(variables['Build.Reason'], 'Schedule')) }}: - - stage: CdacXPlatDumpGen - dependsOn: - - CdacBuild - jobs: + # ---- cDAC X-Plat Dump Generation (xplat mode or schedule) ---- + - ${{ if or(eq(parameters.cdacDumpTestMode, 'xplat'), eq(variables['Build.Reason'], 'Schedule')) }}: - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml @@ -492,10 +475,16 @@ extends: displayName: 'Fail on dump generation errors' condition: always() + # + # cDAC X-Plat Dump Tests — runs after all source platforms have generated + # their dumps. This stage IS cross-platform-synchronizing (every target + # platform's test needs every source platform's dumps), so it remains a + # separate stage depending on Cdac. + # + - ${{ if or(eq(parameters.cdacDumpTestMode, 'xplat'), eq(variables['Build.Reason'], 'Schedule')) }}: - stage: CdacXPlatDumpTests dependsOn: - - CdacBuild - - CdacXPlatDumpGen + - Cdac jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -507,8 +496,10 @@ extends: nameSuffix: CdacXPlatDumpTest buildArgs: -s tools.cdacdumptests -c $(_BuildConfig) -rc checked -lc $(_BuildConfig) /p:SkipDumpVersions=net10.0 timeoutInMinutes: 180 - dependsOnGlobalBuilds: - - nameSuffix: CdacBuild + # No dependsOnGlobalBuilds: this stage depends on the entire Cdac + # stage (which already has the per-platform CdacBuild jobs), and + # AzDO does not support cross-stage job-level deps. The stage-level + # dependsOn: Cdac above is sufficient. preBuildSteps: - template: /eng/pipelines/common/download-artifact-step.yml parameters: @@ -522,9 +513,6 @@ extends: buildDebuggees: false skipDebuggeeCopy: true cdacTestConfig: Debug - parameters: - buildDebuggees: false - skipDebuggeeCopy: true # Download dump artifacts from all source platforms - ${{ each platform in parameters.cdacXPlatDumpPlatforms }}: - task: DownloadPipelineArtifact@2