Skip to content

Commit 0239ceb

Browse files
authored
feat: make tensors resizeable + release v0.2.0 (#1)
* feat: add support for resizing tensors * feat: add diagonal and trace functions for matrices * feat: weaken trait requirements for tensor read/init/writes * feat: update to wgpu 27 * chore: add CI workflow * feat: update to slang-hal/minislang v0.2 * fead: fix svd3 for near-identity matrices * Release v0.2.0 * chore: cargo fmt * fix clippy & docs * fix tests * fix CI
1 parent 0beda86 commit 0239ceb

File tree

19 files changed

+683
-84
lines changed

19 files changed

+683
-84
lines changed

.github/workflows/ci.yaml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
RUSTFLAGS: --deny warnings
12+
RUSTDOCFLAGS: --deny warnings
13+
SLANG_TAG: 2025.18.2
14+
15+
jobs:
16+
# Check formatting.
17+
format:
18+
name: Format
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 30
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Install Rust toolchain
26+
uses: dtolnay/rust-toolchain@stable
27+
with:
28+
components: rustfmt
29+
30+
- name: Run cargo fmt
31+
run: cargo fmt --all -- --check
32+
setup-slang:
33+
strategy:
34+
matrix:
35+
os: [ubuntu-latest]
36+
runs-on: ${{ matrix.os }}
37+
outputs:
38+
slang-dir: ${{ steps.setup.outputs.slang-dir }} # Pass SLANG_DIR to dependent jobs
39+
slang-cache-key: ${{ steps.setup.outputs.slang-cache-key }} # Pass SLANG_DIR to dependent jobs
40+
steps:
41+
- name: Checkout code
42+
uses: actions/checkout@v4
43+
44+
- name: Cache Slang
45+
id: cache-slang
46+
uses: actions/cache/restore@v4 # Restore first
47+
with:
48+
path: |
49+
~/.cache/slang # Matches script's default OUTPUT_DIR
50+
key: slang-v$SLANG_TAG-${{ runner.os }}-${{ runner.arch }}
51+
52+
- name: Setup Slang
53+
id: setup
54+
run: |
55+
echo "version=$SLANG_TAG" >> $GITHUB_OUTPUT # Output for cache key
56+
SLANG_DIR=$(./.github/workflows/download_slang.sh --version $SLANG_TAG | grep '^SLANG_DIR=' | cut -d'=' -f2-)
57+
echo "slang-dir=$SLANG_DIR" >> $GITHUB_OUTPUT # Output for dependents
58+
echo "slang-cache-key=slang-v$SLANG_TAG-${{ runner.os }}-${{ runner.arch }}" >> $GITHUB_OUTPUT
59+
echo "SLANG_DIR=$SLANG_DIR" >> $GITHUB_ENV # For this job if needed
60+
61+
- name: Save Slang Cache
62+
if: steps.cache-slang.outputs.cache-hit != 'true' # Only save on miss
63+
uses: actions/cache/save@v4
64+
with:
65+
path: ~/.cache/slang
66+
key: ${{ steps.setup.outputs.slang-cache-key }}
67+
# Run clippy lints.
68+
clippy:
69+
needs: setup-slang # Depends on setup-slang
70+
name: Clippy
71+
runs-on: ubuntu-latest
72+
env:
73+
SLANG_DIR: ${{ needs.setup-slang.outputs.slang-dir }}
74+
timeout-minutes: 30
75+
steps:
76+
- name: Checkout repository
77+
uses: actions/checkout@v4
78+
79+
- name: Install Rust toolchain
80+
uses: dtolnay/rust-toolchain@stable
81+
with:
82+
components: clippy
83+
84+
- name: Install dependencies
85+
run: sudo apt-get update; sudo apt-get install --no-install-recommends build-essential curl wget file libssl-dev
86+
87+
- name: Retrieve Cache for Slang
88+
uses: actions/cache/restore@v4
89+
with:
90+
path: ~/.cache/slang
91+
key: ${{ needs.setup-slang.outputs.slang-cache-key }}
92+
93+
- name: Populate target directory from cache
94+
uses: Leafwing-Studios/cargo-cache@v2
95+
with:
96+
sweep-cache: true
97+
98+
- name: Run clippy lints
99+
run: SLANG_DIR=$SLANG_DIR cargo clippy --locked --workspace --all-targets -- --deny warnings
100+
101+
# Check documentation.
102+
doc:
103+
needs: setup-slang # Depends on setup-slang
104+
name: Docs
105+
runs-on: ubuntu-latest
106+
timeout-minutes: 30
107+
env:
108+
SLANG_DIR: ${{ needs.setup-slang.outputs.slang-dir }}
109+
steps:
110+
- name: Checkout repository
111+
uses: actions/checkout@v4
112+
113+
- name: Install Rust toolchain
114+
uses: dtolnay/rust-toolchain@stable
115+
116+
- name: Install dependencies
117+
run: sudo apt-get update; sudo apt-get install --no-install-recommends build-essential curl wget file libssl-dev
118+
119+
- name: Retrieve Cache for Slang
120+
uses: actions/cache/restore@v4
121+
with:
122+
path: ~/.cache/slang
123+
key: ${{ needs.setup-slang.outputs.slang-cache-key }}
124+
125+
- name: Populate target directory from cache
126+
uses: Leafwing-Studios/cargo-cache@v2
127+
with:
128+
sweep-cache: true
129+
130+
- name: Check documentation
131+
run: SLANG_DIR=$SLANG_DIR cargo doc --locked --workspace --document-private-items --no-deps
132+
# Testing.
133+
test:
134+
needs: setup-slang # Depends on setup-slang
135+
name: Tests
136+
runs-on: ubuntu-latest
137+
timeout-minutes: 30
138+
env:
139+
SLANG_DIR: ${{ needs.setup-slang.outputs.slang-dir }}
140+
steps:
141+
- name: Checkout repository
142+
uses: actions/checkout@v4
143+
144+
- name: Install Rust toolchain
145+
uses: dtolnay/rust-toolchain@stable
146+
147+
- name: Install dependencies
148+
run: |
149+
sudo apt-get update
150+
sudo apt-get install --no-install-recommends -y \
151+
build-essential curl wget file libssl-dev \
152+
libegl1-mesa-dev libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
153+
154+
- name: Retrieve Cache for Slang
155+
uses: actions/cache/restore@v4
156+
with:
157+
path: ~/.cache/slang
158+
key: ${{ needs.setup-slang.outputs.slang-cache-key }}
159+
160+
- name: Populate target directory from cache
161+
uses: Leafwing-Studios/cargo-cache@v2
162+
with:
163+
sweep-cache: true
164+
- name: Run Cargo Tests
165+
run: |
166+
SLANG_DIR=$SLANG_DIR LIBGL_ALWAYS_SOFTWARE=1 cargo test --verbose
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/bin/bash
2+
3+
# Default values
4+
OS=""
5+
OUTPUT_DIR="$HOME/.cache/slang"
6+
SLANG_VERSION=""
7+
SLANG_TAG=""
8+
ASSET_SUFFIX=""
9+
SLANG_URL_BASE="https://github.com/shader-slang/slang/releases/download"
10+
11+
# Help message
12+
usage() {
13+
echo "Usage: $0 [--os <linux|macos|macos-arm64|windows>] [--output-dir <path>] [--version <version>]"
14+
echo " --os: Target OS (default: auto-detect from current platform)"
15+
echo " --output-dir: Directory to extract Slang (default: ~/.cache/slang)"
16+
echo " --version: Slang version (e.g., 2025.18.2, default: latest)"
17+
echo "Example: $0 --os linux --output-dir /tmp/slang"
18+
}
19+
20+
# Parse arguments
21+
while [[ "$#" -gt 0 ]]; do
22+
case $1 in
23+
--os) OS="$2"; shift ;;
24+
--output-dir) export OUTPUT_DIR="$2"; shift ;;
25+
--version) export SLANG_VERSION="$2"; shift ;;
26+
*) usage ; exit 1 ;;
27+
esac
28+
shift
29+
done
30+
31+
# Detect OS if not specified
32+
if [[ -z "$OS" ]]; then
33+
case "$(uname -s)" in
34+
Linux*) OS="linux" ;;
35+
Darwin*)
36+
if [[ "$(uname -m)" == "arm64" ]]; then
37+
OS="macos-aarch64"
38+
else
39+
OS="macos"
40+
fi
41+
;;
42+
CYGWIN*|MINGW*|MSYS*) OS="windows" ;;
43+
*) echo "Error: Unable to detect OS. Specify --os (linux, macos, macos-arm64, windows)"; exit 1 ;;
44+
esac
45+
fi
46+
47+
# Determine asset suffix based on OS
48+
case "$OS" in
49+
linux) ASSET_SUFFIX="linux-x86_64.zip" ;;
50+
macos) ASSET_SUFFIX="macos-x86_64.zip" ;;
51+
macos-aarch64) ASSET_SUFFIX="macos-aarch64.zip" ;;
52+
windows) ASSET_SUFFIX="windows-x86_64.zip" ;;
53+
*) echo "Error: Unsupported OS: $OS"; exit 1 ;;
54+
esac
55+
56+
# Get Slang version if not specified
57+
if [[ -z "$SLANG_VERSION" ]]; then
58+
export SLANG_TAG=$(curl -s https://api.github.com/repos/shader-slang/slang/releases/latest | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
59+
export SLANG_VERSION=$(echo "$SLANG_TAG" | sed 's/v//') # e.g., v2025.18.2 -> 2025.18.2
60+
else
61+
export SLANG_TAG="v$SLANG_VERSION"
62+
fi
63+
64+
if [[ -z "$SLANG_VERSION" ]]; then
65+
echo "Error: Could not determine Slang version"
66+
exit 1
67+
fi
68+
69+
# Set up paths
70+
SLANG_DIR="$OUTPUT_DIR/slang-v$SLANG_VERSION-$OS"
71+
ZIP_URL="$SLANG_URL_BASE/$SLANG_TAG/slang-$SLANG_VERSION-$ASSET_SUFFIX"
72+
TEMP_ZIP="/tmp/slang-$SLANG_VERSION.zip"
73+
74+
# Check if Slang is already extracted
75+
if [[ -d "$SLANG_DIR" ]] && [[ -f "$SLANG_DIR/bin/slangc" || -f "$SLANG_DIR/bin/slangc.exe" ]]; then
76+
echo "Using existing Slang at $SLANG_DIR"
77+
echo "SLANG_DIR=$SLANG_DIR"
78+
exit 0
79+
fi
80+
81+
# Download Slang release
82+
echo "Downloading Slang v$SLANG_VERSION for $OS from $ZIP_URL..."
83+
mkdir -p "$OUTPUT_DIR"
84+
curl -L -o "$TEMP_ZIP" "$ZIP_URL" || { echo "Error: Download failed for $ZIP_URL"; exit 1; }
85+
86+
# Extract based on OS
87+
echo "Extracting to $SLANG_DIR..."
88+
if [[ "$OS" == "windows" ]]; then
89+
# Windows: Assume 7z is available (or adjust for PowerShell/Expand-Archive)
90+
7z x "$TEMP_ZIP" -o"$SLANG_DIR" -y > /dev/null || { echo "Error: Extraction failed"; rm -f "$TEMP_ZIP"; exit 1; }
91+
else
92+
# Linux/macOS: Use unzip
93+
unzip -q "$TEMP_ZIP" -d "$SLANG_DIR" || { echo "Error: Extraction failed"; rm -f "$TEMP_ZIP"; exit 1; }
94+
fi
95+
96+
# Clean up
97+
rm -f "$TEMP_ZIP"
98+
99+
# Verify extraction
100+
if [[ ! -f "$SLANG_DIR/bin/slangc" && ! -f "$SLANG_DIR/bin/slangc.exe" ]]; then
101+
echo "Error: Extraction incomplete, slangc not found in $SLANG_DIR/bin"
102+
exit 1
103+
fi
104+
105+
echo "Slang v$SLANG_VERSION extracted to $SLANG_DIR"
106+
echo "SLANG_DIR=$SLANG_DIR"
107+
108+
# For use in calling script
109+
export SLANG_DIR

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# v0.2.0 (27 Oct. 2025)
2+
- Update to slang-hal 0.2.
3+
- Make rank-1 tensors resizeable.
4+
- Fix svd3.slang retuning incorrect results for near-identity matrices.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "stensor"
33
authors = ["Sébastien Crozet <[email protected]>"]
44
description = "Cross-platform GPU tensor library with Slang and Rust."
55
repository = "https://github.com/dimforge/stensor"
6-
version = "0.1.1"
6+
version = "0.2.0"
77
edition = "2024"
88
license = "Apache-2.0"
99

@@ -12,15 +12,15 @@ cuda = [ "cudarc", "slang-hal/cuda" ]
1212
cublas = [ "slang-hal/cublas" ]
1313

1414
[dependencies]
15-
wgpu = "26"
15+
wgpu = "27"
1616
encase = "0.12"
1717
bytemuck = "1"
1818
nalgebra = { version = "0.34", features = ["encase"] }
1919

2020
cudarc = { version = "0.16", optional = true }
2121

22-
minislang = "0.1"
23-
slang-hal = { version = "0.1", features = ["derive"] }
22+
minislang = "0.2"
23+
slang-hal = { version = "0.2", features = ["derive"] }
2424
include_dir = "0.7"
2525

2626
[dev-dependencies]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ gpu". It aims (but it isn’t there yet) to expose linear algebra operations (in
55
operations) as well as geometric types (quaternions, similarities, etc.) as Slang shaders and kernels.
66

77
> **Warning**
8-
**stensor** is still very incomplete and under heavy development and is lacking many features.
8+
> **stensor** is still very incomplete and under heavy development and is lacking many features.
99
1010
See also the README of [slang-hal](https://github.com/dimforge/slang-hal/blob/main/README.md) for information on
1111
supported platforms.
1212

1313
### Using Slang
1414

1515
In order to compile and run any slang project, be sure to define the `SLANG_DIR` environment variable:
16-
1. Download the Slang compiler libraries for your platform: https://github.com/shader-slang/slang/releases/tag/v2025.16
16+
1. Download the Slang compiler libraries for your platform: <https://github.com/shader-slang/slang/releases/tag/v2025.16>
1717
2. Unzip the downloaded directory, and use its path as value to the `SLANG_DIR` environment variable: `SLANG_DIR=/path/to/slang`.
1818
Note that the variable must point to the root of the slang installation (i.e. the directory that contains `bin` and `lib`).
1919
We recommend adding that as a system-wide environment variables so that it also becomes available to your IDE.

build.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ pub fn main() {
1515
slang.compile_all(target, "../shaders", "./src/autogen", &[]);
1616
}
1717
}
18-

examples/gemm_bench.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use approx::assert_relative_eq;
21
use indexmap::IndexMap;
32
use minislang::SlangCompiler;
43
use nalgebra::DMatrix;
54
use slang_hal::Shader;
65
use slang_hal::backend::WebGpu;
76
use slang_hal::backend::{Backend, Encoder};
8-
use slang_hal::shapes::ViewShapeBuffers;
9-
use slang_hal::tensor::{GpuTensor, TensorBuilder};
107
use stensor::linalg::{Gemm, GemmVariant};
8+
use stensor::shapes::ViewShapeBuffers;
9+
use stensor::tensor::GpuTensor;
1110
use wgpu::{BufferUsages, Features, Limits};
1211

1312
#[async_std::main]
@@ -105,7 +104,7 @@ async fn run_gemm<B: Backend>(
105104
drop(pass); // Ensure the pass is ended before the encoder is borrowed again.
106105

107106
backend.submit(encoder)?;
108-
backend.synchronize();
107+
backend.synchronize()?;
109108
timing[i] = t0.elapsed().as_secs_f32();
110109
backend
111110
.slow_read_buffer(result.buffer(), gpu_result.as_mut_slice())

shaders/stensor/geometry/svd3.slang

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ public struct Svd3 {
4949

5050
// Constants used for calculation of givens quaternions
5151
static const float GAMMA = 5.828427124; // sqrt(8)+3;
52-
static const float CSTAR = 0.923879532; // cos(pi/8)
53-
static const float SSTAR = 0.3826834323; // sin(p/8)
52+
static const float CSTAR = 1.0; // TODO: using no-identity values (below) breaks the SVD for near-identity matrices.
53+
static const float SSTAR = 0.0; // TODO: using no-identity values (below) breaks the SVD for near-identity matrices.
54+
//static const float CSTAR = 0.923879532; // cos(pi/8)
55+
//static const float SSTAR = 0.3826834323; // sin(p/8)
5456
// Threshold value
5557
static const float SVD_EPSILON = 1e-6;
5658
// Iteration counts for Jacobi Eigenanalysis and reciprocal square root functions, influence precision

shaders/stensor/linalg/gemm.slang

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ void gemm_fast(
2626
) {
2727
let local_id = local_id.y;
2828

29-
out[0] = 1.0;
30-
3129
for (var k = 0u; k < shape_m2.ncols; k += 4u) {
3230
var sum = float4x4(0.0);
3331

0 commit comments

Comments
 (0)