Skip to content
Open
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
64 changes: 51 additions & 13 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,37 @@ jobs:
if exist wheelpkg rd /s /q wheelpkg
if exist therock-dist rd /s /q therock-dist

# Persistent GPU assets (model/, amdgpu-oga-models/, l2-test-models/) live
# outside the checkout and survive across runs. After the onnx-hipdnn-ep ->
# hip-ep rename, runner.workspace moved but the staged dirs did not; probe
# legacy paths before failing. Override anytime via GPU_TEST_ASSET_ROOT.
- name: Resolve GPU test asset root
shell: pwsh
run: |
$explicit = "${{ vars.GPU_TEST_ASSET_ROOT }}".Trim()
$candidates = [System.Collections.Generic.List[string]]::new()
if ($explicit) { $candidates.Add($explicit) }
$candidates.Add("${{ runner.workspace }}")
$parent = Split-Path "${{ runner.workspace }}" -Parent
$candidates.Add((Join-Path $parent "onnx-hipdnn-ep"))
$candidates.Add((Join-Path $parent "hip-ep"))

$root = $null
foreach ($c in ($candidates | Select-Object -Unique)) {
if ((Test-Path (Join-Path $c "model")) -or
(Test-Path (Join-Path $c "amdgpu-oga-models")) -or
(Test-Path (Join-Path $c "l2-test-models"))) {
$root = $c
Write-Host "Using GPU test asset root: $root"
break
}
}
if (-not $root) {
$root = if ($explicit) { $explicit } else { "${{ runner.workspace }}" }
Write-Host "WARNING: no GPU asset dirs found; defaulting to: $root"
}
"GPU_TEST_ASSET_ROOT=$root" >> $env:GITHUB_ENV

- name: Download GPU test package
uses: actions/download-artifact@v4
with:
Expand Down Expand Up @@ -733,17 +764,14 @@ jobs:
# Output is tee'd to results/ for QPS extraction. Non-zero exit code
# sets FAILED but continues so all models are tested.
#
# GPU-test asset dirs (model/, amdgpu-oga-models/, l2-test-models/) resolve
# under ${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}: set the repo/org
# Actions variable GPU_TEST_ASSET_ROOT to a stable path (and stage the dirs
# there) so persistent assets need not live under the repo-name-derived
# _work/<repo>/, which strands them on a repo rename. Unset => runner.workspace
# (unchanged from today).
# GPU-test asset dirs resolve under $env:GPU_TEST_ASSET_ROOT (see
# "Resolve GPU test asset root" above). Set the repo/org Actions variable
# GPU_TEST_ASSET_ROOT to override the auto-detected path.
- name: Run onnxruntime_perf_test (GPU)
shell: cmd
run: |
set PATH=%CD%\therock-dist\bin;%CD%\gpu-test-package\bin;%PATH%
set MODEL_DIR=${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\model
set MODEL_DIR=%GPU_TEST_ASSET_ROOT%\model
if not exist "%MODEL_DIR%" (
echo [ERROR] MODEL_DIR not found: %MODEL_DIR%
exit /b 1
Expand Down Expand Up @@ -787,7 +815,7 @@ jobs:
set THEROCK_DIST=%CD%\therock-dist
set PATH=%CD%\therock-dist\bin;%CD%\gpu-test-package\bin;%PATH%
set LIB=%CD%\gpu-test-package\lib;%CD%\therock-dist\lib
set MODEL_DIR=${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\model
set MODEL_DIR=%GPU_TEST_ASSET_ROOT%\model
if not exist "%MODEL_DIR%" (
echo [SKIP] MODEL_DIR not found: %MODEL_DIR%
exit /b 0
Expand Down Expand Up @@ -833,7 +861,7 @@ jobs:
set THEROCK_DIST=%CD%\therock-dist
set PATH=%CD%\therock-dist\bin;%CD%\gpu-test-package\bin;%PATH%
set LIB=%CD%\gpu-test-package\lib;%CD%\therock-dist\lib
set MODEL_DIR=${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\model
set MODEL_DIR=%GPU_TEST_ASSET_ROOT%\model
if not exist "%MODEL_DIR%" (
echo [SKIP] MODEL_DIR not found: %MODEL_DIR%
exit /b 0
Expand Down Expand Up @@ -875,7 +903,7 @@ jobs:
$pkgBin = Join-Path $PWD "gpu-test-package\bin"
$env:PATH = "$PWD\therock-dist\bin;$pkgBin;$env:PATH"

$modelDir = "${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\model"
$modelDir = "$env:GPU_TEST_ASSET_ROOT\model"
if (-not (Test-Path $modelDir)) {
Write-Host "[SKIP] MODEL_DIR not found: $modelDir"
exit 0
Expand Down Expand Up @@ -955,7 +983,7 @@ jobs:
# generated once on the GPU runner and persists across runs, so just
# consume it here (no re-copy / no config rewrite). It must be present
# -- treat its absence as an error, not a skip.
$ogaModelRoot = "${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\amdgpu-oga-models"
$ogaModelRoot = "$env:GPU_TEST_ASSET_ROOT\amdgpu-oga-models"
if (-not (Test-Path $ogaModelRoot)) {
Write-Host "[ERROR] AMDGPU OGA model directory not found: $ogaModelRoot"
exit 1
Expand Down Expand Up @@ -1049,7 +1077,7 @@ jobs:
$ErrorActionPreference = 'Continue'
$PSNativeCommandUseErrorActionPreference = $false

$model = "${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\amdgpu-oga-models\Llama-3.1-8B-awq-g128-int4-asym-fp16-onnx-dml"
$model = "$env:GPU_TEST_ASSET_ROOT\amdgpu-oga-models\Llama-3.1-8B-awq-g128-int4-asym-fp16-onnx-dml"
if (-not (Test-Path $model)) { Write-Host "[SKIP] model not found: $model"; exit 0 }

# The morphizen wheel now bundles the whole AMD GPU umbrella chain
Expand Down Expand Up @@ -1098,7 +1126,7 @@ jobs:
rem The EP DLL is now hipgpu.dll; hip-onnx-runner's legacy default name
rem is onnxruntime_morphizen_ep.dll, so point it at the new DLL.
set MORPHIZEN_EP_LIB=%CD%\gpu-test-package\bin\hipgpu.dll
set L2_MODEL_DIR=${{ vars.GPU_TEST_ASSET_ROOT || runner.workspace }}\l2-test-models
set L2_MODEL_DIR=%GPU_TEST_ASSET_ROOT%\l2-test-models
if not exist "%L2_MODEL_DIR%" (
echo [SKIP] L2 model directory not found: %L2_MODEL_DIR%
exit /b 0
Expand Down Expand Up @@ -1144,6 +1172,8 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
$ErrorActionPreference = 'Continue'
$PSNativeCommandUseErrorActionPreference = $false
$l2Dir = "l2-results"
if (-not (Test-Path $l2Dir)) {
Write-Host "No L2 results to publish (directory not found)"
Expand Down Expand Up @@ -1218,6 +1248,9 @@ jobs:
}
}

# Step summary is the source of truth; fork PRs may lack comment perms.
exit 0

# Parse QPS from result files and publish:
# - PR trigger → post/update a PR comment via gh CLI (github-actions[bot])
# - other trigger → write to GITHUB_STEP_SUMMARY only
Expand All @@ -1227,6 +1260,8 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
$ErrorActionPreference = 'Continue'
$PSNativeCommandUseErrorActionPreference = $false
$resultsDir = "gpu-test-package/results"
$runUrl = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
$rawSha = if ("${{ github.event_name }}" -eq "pull_request") { "${{ github.event.pull_request.head.sha }}" } else { "${{ github.sha }}" }
Expand Down Expand Up @@ -1373,3 +1408,6 @@ jobs:
Write-Host "WARNING: gh api unreachable, skipping PR comment"
}
}

# Step summary is the source of truth; fork PRs may lack comment perms.
exit 0
1 change: 1 addition & 0 deletions lib/Conversion/OnnxToHip/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ add_library(OnnxToHip STATIC
GatherShapeFold.cpp
ReshapeShapeFold.cpp
PadShapeFold.cpp
SliceShapeFold.cpp
ShapeConversion.cpp
ReshapeConversion.cpp
CausalConvWithStateConversion.cpp
Expand Down
1 change: 1 addition & 0 deletions lib/Conversion/OnnxToHip/OnnxToHip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ void ConvertOnnxToHipPass::runOnOperation() {
populateGatherBlockQuantizedPreparePatterns(preLoweringPatterns, ctx);
populateReshapeShapeFoldPatterns(preLoweringPatterns, ctx);
populatePadShapeFoldPatterns(preLoweringPatterns, ctx);
populateSliceShapeFoldPatterns(preLoweringPatterns, ctx);
populateFastGeluFusionPatterns(preLoweringPatterns, ctx);
populateErfGeluFusionPatterns(preLoweringPatterns, ctx);
populateProjectorOpsRewritePatterns(preLoweringPatterns, ctx);
Expand Down
8 changes: 8 additions & 0 deletions lib/Conversion/OnnxToHip/OnnxToHipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,14 @@ void populateReshapeShapeFoldPatterns(RewritePatternSet &patterns,
void populatePadShapeFoldPatterns(RewritePatternSet &patterns,
MLIRContext *ctx);

/// Pre-lowering pattern set: stamp compile-time `onnx.Slice` starts/ends/axes/
/// steps onto the op as `hipdnn.slice_*` attributes so SliceDecompose can
/// rewrite to `tensor.extract_slice` after `lowerOnnxConstants` externalizes
/// the operand constants. Sibling of PadShapeFold; must run BEFORE
/// lowerOnnxConstants. See SliceShapeFold.cpp.
void populateSliceShapeFoldPatterns(RewritePatternSet &patterns,
MLIRContext *ctx);

/// Pre-lowering pattern set: collapse ORT's inlined `FastGelu` primitive
/// chain (Pow / Mul / Sum / Tanh) back into a single
/// `onnx.Gelu(approximate="tanh")`. ORT inlines the Gelu function body
Expand Down
50 changes: 40 additions & 10 deletions lib/Conversion/OnnxToHip/SliceConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,10 @@ static mlir::DenseElementsAttr getCompileTimeConstantTensor(mlir::Value value) {
return nullptr;
}

/// Extract a 1-D integer tensor constant into a SmallVector<int64_t>.
/// Returns failure if the tensor is missing, not 1-D, or not int32/int64.
/// Populate \p out from a dense 1-D integer tensor attribute.
static mlir::LogicalResult
extractIntVector(mlir::Value v, llvm::SmallVectorImpl<int64_t> &out) {
if (!v)
return mlir::failure();
auto dense = getCompileTimeConstantTensor(v);
denseIntVectorToSmallVector(mlir::DenseElementsAttr dense,
llvm::SmallVectorImpl<int64_t> &out) {
if (!dense)
return mlir::failure();
auto tensorType = mlir::dyn_cast<mlir::RankedTensorType>(dense.getType());
Expand All @@ -83,11 +80,34 @@ extractIntVector(mlir::Value v, llvm::SmallVectorImpl<int64_t> &out) {
auto elemTy = tensorType.getElementType();
if (!elemTy.isInteger(64) && !elemTy.isInteger(32))
return mlir::failure();
out.clear();
for (mlir::APInt entry : dense.getValues<mlir::APInt>())
out.push_back(entry.getSExtValue());
return mlir::success();
}

/// Extract a 1-D integer tensor constant into a SmallVector<int64_t>.
/// Returns failure if the tensor is missing, not 1-D, or not int32/int64.
static mlir::LogicalResult
extractIntVector(mlir::Value v, llvm::SmallVectorImpl<int64_t> &out) {
if (!v)
return mlir::failure();
return denseIntVectorToSmallVector(getCompileTimeConstantTensor(v), out);
}

/// Prefer compile-time slice params stamped by SliceShapeFold (captured
/// before constant externalization); fall back to reading inline operands.
static mlir::LogicalResult
extractSliceParamVector(mlir::Operation *op, llvm::StringRef attrName,
mlir::Value operand,
llvm::SmallVectorImpl<int64_t> &out) {
if (auto attr = op->getAttrOfType<mlir::DenseI64ArrayAttr>(attrName)) {
out.assign(attr.asArrayRef().begin(), attr.asArrayRef().end());
return mlir::success();
}
return extractIntVector(operand, out);
}

/// Normalise an ONNX Slice operand reference (`v`): if it is an `onnx.NoValue`
/// placeholder (used for absent optional inputs), returns null Value.
static mlir::Value normaliseOptional(mlir::Value v) {
Expand Down Expand Up @@ -120,18 +140,24 @@ struct SliceDecompose : public mlir::RewritePattern {
int64_t rank = dataType.getRank();

llvm::SmallVector<int64_t> startsVec, endsVec;
if (mlir::failed(extractIntVector(op->getOperand(1), startsVec)) ||
mlir::failed(extractIntVector(op->getOperand(2), endsVec)))
if (mlir::failed(extractSliceParamVector(op, "hipdnn.slice_starts",
op->getOperand(1), startsVec)) ||
mlir::failed(extractSliceParamVector(op, "hipdnn.slice_ends",
op->getOperand(2), endsVec)))
return rewriter.notifyMatchFailure(
op, "starts/ends are not compile-time constants");

llvm::SmallVector<int64_t> axesVec;
if (op->getNumOperands() >= 4) {
mlir::Value axes = normaliseOptional(op->getOperand(3));
if (axes) {
if (mlir::failed(extractIntVector(axes, axesVec)))
if (mlir::failed(extractSliceParamVector(op, "hipdnn.slice_axes", axes,
axesVec)))
return rewriter.notifyMatchFailure(
op, "axes is not a compile-time constant");
} else if (auto attr = op->getAttrOfType<mlir::DenseI64ArrayAttr>(
"hipdnn.slice_axes")) {
axesVec.assign(attr.asArrayRef().begin(), attr.asArrayRef().end());
}
}
if (axesVec.empty())
Expand All @@ -142,9 +168,13 @@ struct SliceDecompose : public mlir::RewritePattern {
if (op->getNumOperands() == 5) {
mlir::Value steps = normaliseOptional(op->getOperand(4));
if (steps) {
if (mlir::failed(extractIntVector(steps, stepsVec)))
if (mlir::failed(extractSliceParamVector(op, "hipdnn.slice_steps",
steps, stepsVec)))
return rewriter.notifyMatchFailure(
op, "steps is not a compile-time constant");
} else if (auto attr = op->getAttrOfType<mlir::DenseI64ArrayAttr>(
"hipdnn.slice_steps")) {
stepsVec.assign(attr.asArrayRef().begin(), attr.asArrayRef().end());
}
}
if (stepsVec.empty())
Expand Down
Loading
Loading