torchref-kernels 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- torchref_kernels-0.1.0/Cargo.lock +223 -0
- torchref_kernels-0.1.0/Cargo.toml +35 -0
- torchref_kernels-0.1.0/PKG-INFO +33 -0
- torchref_kernels-0.1.0/README.md +21 -0
- torchref_kernels-0.1.0/build.rs +61 -0
- torchref_kernels-0.1.0/pyproject.toml +34 -0
- torchref_kernels-0.1.0/python/torchref_kernels/__init__.py +19 -0
- torchref_kernels-0.1.0/src/ffi.rs +83 -0
- torchref_kernels-0.1.0/src/frf/legendre_shell.rs +370 -0
- torchref_kernels-0.1.0/src/frf/mod.rs +3 -0
- torchref_kernels-0.1.0/src/lib.rs +47 -0
- torchref_kernels-0.1.0/src/pool.rs +35 -0
- torchref_kernels-0.1.0/src/real.rs +174 -0
- torchref_kernels-0.1.0/src/simd.rs +66 -0
- torchref_kernels-0.1.0/src/sphere_splat/aniso.rs +165 -0
- torchref_kernels-0.1.0/src/sphere_splat/common.rs +224 -0
- torchref_kernels-0.1.0/src/sphere_splat/iso.rs +119 -0
- torchref_kernels-0.1.0/src/sphere_splat/mod.rs +199 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "crossbeam-deque"
|
|
7
|
+
version = "0.8.8"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"crossbeam-epoch",
|
|
12
|
+
"crossbeam-utils",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[[package]]
|
|
16
|
+
name = "crossbeam-epoch"
|
|
17
|
+
version = "0.9.21"
|
|
18
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
19
|
+
checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
|
|
20
|
+
dependencies = [
|
|
21
|
+
"crossbeam-utils",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[[package]]
|
|
25
|
+
name = "crossbeam-utils"
|
|
26
|
+
version = "0.8.23"
|
|
27
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
28
|
+
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
|
|
29
|
+
|
|
30
|
+
[[package]]
|
|
31
|
+
name = "either"
|
|
32
|
+
version = "1.19.0"
|
|
33
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
34
|
+
checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "heck"
|
|
38
|
+
version = "0.5.0"
|
|
39
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
40
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "libc"
|
|
44
|
+
version = "0.2.190"
|
|
45
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
46
|
+
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
|
47
|
+
|
|
48
|
+
[[package]]
|
|
49
|
+
name = "multiversion"
|
|
50
|
+
version = "0.9.0"
|
|
51
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
52
|
+
checksum = "b4ca4bea16ffc3f443cf7d866912118196bfef4c6a1556ca00f9f9b00bb43f7c"
|
|
53
|
+
dependencies = [
|
|
54
|
+
"multiversion-macros",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[[package]]
|
|
58
|
+
name = "multiversion-macros"
|
|
59
|
+
version = "0.9.0"
|
|
60
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
61
|
+
checksum = "0d416831a7317ef4b08bee00b69cbbb9c8763da7959a7026244d6266869f9c83"
|
|
62
|
+
dependencies = [
|
|
63
|
+
"proc-macro2",
|
|
64
|
+
"quote",
|
|
65
|
+
"rustversion",
|
|
66
|
+
"syn 3.0.7",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
[[package]]
|
|
70
|
+
name = "once_cell"
|
|
71
|
+
version = "1.21.4"
|
|
72
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
73
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
74
|
+
|
|
75
|
+
[[package]]
|
|
76
|
+
name = "portable-atomic"
|
|
77
|
+
version = "1.15.0"
|
|
78
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
79
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
80
|
+
|
|
81
|
+
[[package]]
|
|
82
|
+
name = "proc-macro2"
|
|
83
|
+
version = "1.0.107"
|
|
84
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
85
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
86
|
+
dependencies = [
|
|
87
|
+
"unicode-ident",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[[package]]
|
|
91
|
+
name = "pyo3"
|
|
92
|
+
version = "0.29.3"
|
|
93
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
94
|
+
checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
|
|
95
|
+
dependencies = [
|
|
96
|
+
"libc",
|
|
97
|
+
"once_cell",
|
|
98
|
+
"portable-atomic",
|
|
99
|
+
"pyo3-build-config",
|
|
100
|
+
"pyo3-ffi",
|
|
101
|
+
"pyo3-macros",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[[package]]
|
|
105
|
+
name = "pyo3-build-config"
|
|
106
|
+
version = "0.29.3"
|
|
107
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
+
checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
|
|
109
|
+
dependencies = [
|
|
110
|
+
"target-lexicon",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[[package]]
|
|
114
|
+
name = "pyo3-ffi"
|
|
115
|
+
version = "0.29.3"
|
|
116
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
117
|
+
checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
|
|
118
|
+
dependencies = [
|
|
119
|
+
"libc",
|
|
120
|
+
"pyo3-build-config",
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
[[package]]
|
|
124
|
+
name = "pyo3-macros"
|
|
125
|
+
version = "0.29.3"
|
|
126
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
127
|
+
checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
|
|
128
|
+
dependencies = [
|
|
129
|
+
"proc-macro2",
|
|
130
|
+
"pyo3-macros-backend",
|
|
131
|
+
"quote",
|
|
132
|
+
"syn 2.0.119",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
[[package]]
|
|
136
|
+
name = "pyo3-macros-backend"
|
|
137
|
+
version = "0.29.3"
|
|
138
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
139
|
+
checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
|
|
140
|
+
dependencies = [
|
|
141
|
+
"heck",
|
|
142
|
+
"proc-macro2",
|
|
143
|
+
"quote",
|
|
144
|
+
"syn 2.0.119",
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
[[package]]
|
|
148
|
+
name = "quote"
|
|
149
|
+
version = "1.0.47"
|
|
150
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
151
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
152
|
+
dependencies = [
|
|
153
|
+
"proc-macro2",
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
[[package]]
|
|
157
|
+
name = "rayon"
|
|
158
|
+
version = "1.12.0"
|
|
159
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
160
|
+
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
|
161
|
+
dependencies = [
|
|
162
|
+
"either",
|
|
163
|
+
"rayon-core",
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
[[package]]
|
|
167
|
+
name = "rayon-core"
|
|
168
|
+
version = "1.13.0"
|
|
169
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
170
|
+
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
|
171
|
+
dependencies = [
|
|
172
|
+
"crossbeam-deque",
|
|
173
|
+
"crossbeam-utils",
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
[[package]]
|
|
177
|
+
name = "rustversion"
|
|
178
|
+
version = "1.0.23"
|
|
179
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
180
|
+
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
|
181
|
+
|
|
182
|
+
[[package]]
|
|
183
|
+
name = "syn"
|
|
184
|
+
version = "2.0.119"
|
|
185
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
|
+
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
|
187
|
+
dependencies = [
|
|
188
|
+
"proc-macro2",
|
|
189
|
+
"quote",
|
|
190
|
+
"unicode-ident",
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
[[package]]
|
|
194
|
+
name = "syn"
|
|
195
|
+
version = "3.0.7"
|
|
196
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
197
|
+
checksum = "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc"
|
|
198
|
+
dependencies = [
|
|
199
|
+
"proc-macro2",
|
|
200
|
+
"quote",
|
|
201
|
+
"unicode-ident",
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
[[package]]
|
|
205
|
+
name = "target-lexicon"
|
|
206
|
+
version = "0.13.5"
|
|
207
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
208
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
209
|
+
|
|
210
|
+
[[package]]
|
|
211
|
+
name = "torchref_kernels"
|
|
212
|
+
version = "0.1.0"
|
|
213
|
+
dependencies = [
|
|
214
|
+
"multiversion",
|
|
215
|
+
"pyo3",
|
|
216
|
+
"rayon",
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
[[package]]
|
|
220
|
+
name = "unicode-ident"
|
|
221
|
+
version = "1.0.26"
|
|
222
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
223
|
+
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "torchref_kernels"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
# `slice::as_chunks`.
|
|
6
|
+
rust-version = "1.88"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
description = "Prebuilt CPU kernels for TorchRef"
|
|
9
|
+
repository = "https://github.com/HatPdotS/TorchRef"
|
|
10
|
+
build = "build.rs"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
|
|
13
|
+
[lib]
|
|
14
|
+
name = "torchref_kernels"
|
|
15
|
+
# cdylib is the Python extension; rlib lets `cargo test` link the kernels.
|
|
16
|
+
crate-type = ["cdylib", "rlib"]
|
|
17
|
+
|
|
18
|
+
[dependencies]
|
|
19
|
+
multiversion = "0.9.0"
|
|
20
|
+
pyo3 = { version = "0.29.3", features = ["abi3-py310"] }
|
|
21
|
+
rayon = "1.12.0"
|
|
22
|
+
|
|
23
|
+
[features]
|
|
24
|
+
# Enabled by maturin (pyproject.toml). Off for `cargo test`, which must link libpython.
|
|
25
|
+
extension-module = ["pyo3/extension-module"]
|
|
26
|
+
|
|
27
|
+
[profile.release]
|
|
28
|
+
lto = "fat"
|
|
29
|
+
codegen-units = 1
|
|
30
|
+
opt-level = 3
|
|
31
|
+
|
|
32
|
+
# A forgotten `--release` on `maturin develop` must not produce a kernel that is
|
|
33
|
+
# silently 10-100x slower; debug assertions stay on so dev builds still check bounds.
|
|
34
|
+
[profile.dev]
|
|
35
|
+
opt-level = 3
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: torchref-kernels
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Summary: Prebuilt CPU kernels for TorchRef
|
|
7
|
+
Author: HansPeterSeidel
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
11
|
+
|
|
12
|
+
# torchref-kernels
|
|
13
|
+
|
|
14
|
+
Prebuilt CPU kernels for [TorchRef](https://github.com/HatPdotS/TorchRef), written in Rust.
|
|
15
|
+
|
|
16
|
+
The wheels link neither libtorch nor a specific CPython version (abi3), so one wheel per
|
|
17
|
+
platform works with every torch and Python version TorchRef supports, and nothing is
|
|
18
|
+
compiled when TorchRef is imported. On x86-64 each kernel is built for several
|
|
19
|
+
microarchitecture levels and the best one for the running CPU is chosen on first use.
|
|
20
|
+
|
|
21
|
+
This package is an implementation detail of TorchRef and is installed with it; its entry
|
|
22
|
+
points take raw tensor pointers and are not a public API.
|
|
23
|
+
|
|
24
|
+
## Development
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install -e ./kernels # or: maturin develop --release -m kernels/Cargo.toml
|
|
28
|
+
cargo test --manifest-path kernels/Cargo.toml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Rust changes are picked up only after rebuilding. `torchref_kernels.build_info()` reports
|
|
32
|
+
the build profile, the selected CPU variant and a hash of the sources it was built from.
|
|
33
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# torchref-kernels
|
|
2
|
+
|
|
3
|
+
Prebuilt CPU kernels for [TorchRef](https://github.com/HatPdotS/TorchRef), written in Rust.
|
|
4
|
+
|
|
5
|
+
The wheels link neither libtorch nor a specific CPython version (abi3), so one wheel per
|
|
6
|
+
platform works with every torch and Python version TorchRef supports, and nothing is
|
|
7
|
+
compiled when TorchRef is imported. On x86-64 each kernel is built for several
|
|
8
|
+
microarchitecture levels and the best one for the running CPU is chosen on first use.
|
|
9
|
+
|
|
10
|
+
This package is an implementation detail of TorchRef and is installed with it; its entry
|
|
11
|
+
points take raw tensor pointers and are not a public API.
|
|
12
|
+
|
|
13
|
+
## Development
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install -e ./kernels # or: maturin develop --release -m kernels/Cargo.toml
|
|
17
|
+
cargo test --manifest-path kernels/Cargo.toml
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Rust changes are picked up only after rebuilding. `torchref_kernels.build_info()` reports
|
|
21
|
+
the build profile, the selected CPU variant and a hash of the sources it was built from.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//! Embed the build profile, optimisation level and a hash of the kernel sources, so the
|
|
2
|
+
//! Python side can refuse a debug build and detect a stale one.
|
|
3
|
+
|
|
4
|
+
use std::fs;
|
|
5
|
+
use std::path::{Path, PathBuf};
|
|
6
|
+
|
|
7
|
+
/// FNV-1a 64; `torchref.utils.native.source_hash` computes the same digest in Python.
|
|
8
|
+
fn fnv1a(hash: &mut u64, bytes: &[u8]) {
|
|
9
|
+
for b in bytes {
|
|
10
|
+
*hash ^= u64::from(*b);
|
|
11
|
+
*hash = hash.wrapping_mul(0x100_0000_01b3);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fn collect(dir: &Path, out: &mut Vec<PathBuf>) {
|
|
16
|
+
for entry in fs::read_dir(dir).expect("readable source dir") {
|
|
17
|
+
let path = entry.expect("dir entry").path();
|
|
18
|
+
if path.is_dir() {
|
|
19
|
+
collect(&path, out);
|
|
20
|
+
} else if path.extension().is_some_and(|e| e == "rs") {
|
|
21
|
+
out.push(path);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fn main() {
|
|
27
|
+
let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
28
|
+
let mut files = Vec::new();
|
|
29
|
+
collect(&root.join("src"), &mut files);
|
|
30
|
+
// Relative, '/'-separated and sorted, so the digest is the same on every OS.
|
|
31
|
+
let mut rel: Vec<(String, PathBuf)> = files
|
|
32
|
+
.into_iter()
|
|
33
|
+
.map(|p| {
|
|
34
|
+
let r = p
|
|
35
|
+
.strip_prefix(&root)
|
|
36
|
+
.unwrap()
|
|
37
|
+
.to_string_lossy()
|
|
38
|
+
.replace('\\', "/");
|
|
39
|
+
(r, p)
|
|
40
|
+
})
|
|
41
|
+
.collect();
|
|
42
|
+
rel.sort();
|
|
43
|
+
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
|
|
44
|
+
for (name, path) in &rel {
|
|
45
|
+
fnv1a(&mut hash, name.as_bytes());
|
|
46
|
+
fnv1a(&mut hash, &[0]);
|
|
47
|
+
fnv1a(&mut hash, &fs::read(path).expect("readable source"));
|
|
48
|
+
fnv1a(&mut hash, &[0]);
|
|
49
|
+
println!("cargo:rerun-if-changed={}", path.display());
|
|
50
|
+
}
|
|
51
|
+
println!("cargo:rerun-if-changed=src");
|
|
52
|
+
println!("cargo:rustc-env=TORCHREF_KERNELS_SOURCE_HASH={hash:016x}");
|
|
53
|
+
println!(
|
|
54
|
+
"cargo:rustc-env=TORCHREF_KERNELS_PROFILE={}",
|
|
55
|
+
std::env::var("PROFILE").unwrap()
|
|
56
|
+
);
|
|
57
|
+
println!(
|
|
58
|
+
"cargo:rustc-env=TORCHREF_KERNELS_OPT_LEVEL={}",
|
|
59
|
+
std::env::var("OPT_LEVEL").unwrap()
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["maturin>=1.7,<2"]
|
|
3
|
+
build-backend = "maturin"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "torchref-kernels"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Prebuilt CPU kernels for TorchRef"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{name = "HansPeterSeidel"}]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Rust",
|
|
15
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[tool.maturin]
|
|
19
|
+
python-source = "python"
|
|
20
|
+
module-name = "torchref_kernels._native"
|
|
21
|
+
features = ["extension-module"]
|
|
22
|
+
# `pip install ./kernels` and the wheels build in release; `maturin develop` uses the dev
|
|
23
|
+
# profile, which Cargo.toml also optimises, so neither path yields a slow kernel.
|
|
24
|
+
profile = "release"
|
|
25
|
+
|
|
26
|
+
[tool.uv]
|
|
27
|
+
# uv only rebuilds a local package when these change; without them a Rust edit is ignored.
|
|
28
|
+
cache-keys = [
|
|
29
|
+
{file = "pyproject.toml"},
|
|
30
|
+
{file = "Cargo.toml"},
|
|
31
|
+
{file = "Cargo.lock"},
|
|
32
|
+
{file = "build.rs"},
|
|
33
|
+
{file = "src/**/*.rs"},
|
|
34
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Prebuilt CPU kernels for TorchRef.
|
|
2
|
+
|
|
3
|
+
Low-level entry points taking ``(data_ptr, numel)`` pairs of CPU tensors. They are not
|
|
4
|
+
meant to be called directly: TorchRef's wrappers (``torchref.utils.native``) validate
|
|
5
|
+
device, dtype, contiguity and shapes, own the autograd, and choose the thread count.
|
|
6
|
+
Nothing here imports torch.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from torchref_kernels._native import ABI_VERSION, build_info
|
|
10
|
+
from torchref_kernels import _native
|
|
11
|
+
|
|
12
|
+
__version__ = build_info()["version"]
|
|
13
|
+
|
|
14
|
+
__all__ = ["ABI_VERSION", "build_info", "native", "__version__"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def native():
|
|
18
|
+
"""The compiled extension module holding the kernel entry points."""
|
|
19
|
+
return _native
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//! The one unsafe boundary: raw `(address, length)` pairs from Python become slices.
|
|
2
|
+
//!
|
|
3
|
+
//! Python passes `tensor.data_ptr()` and `tensor.numel()` for CPU, contiguous tensors of the
|
|
4
|
+
//! kernel's dtype (`torchref.utils.native.buf` checks all three). Everything past this
|
|
5
|
+
//! module works on safe slices, and every kernel checks slice lengths against each other
|
|
6
|
+
//! before touching memory, so a wrong shape is a `ValueError`, not a segfault.
|
|
7
|
+
|
|
8
|
+
use pyo3::PyResult;
|
|
9
|
+
use pyo3::exceptions::PyValueError;
|
|
10
|
+
use std::ptr::NonNull;
|
|
11
|
+
|
|
12
|
+
/// `(data_ptr, numel)` of a CPU tensor, as passed from Python.
|
|
13
|
+
pub type Buf = (usize, usize);
|
|
14
|
+
|
|
15
|
+
fn checked<T>(buf: Buf, what: &str) -> PyResult<*mut T> {
|
|
16
|
+
let (addr, len) = buf;
|
|
17
|
+
if len == 0 {
|
|
18
|
+
// An empty tensor may report address 0, which is not a valid slice pointer.
|
|
19
|
+
return Ok(NonNull::<T>::dangling().as_ptr());
|
|
20
|
+
}
|
|
21
|
+
if addr == 0 {
|
|
22
|
+
return Err(PyValueError::new_err(format!("{what}: null data pointer")));
|
|
23
|
+
}
|
|
24
|
+
if addr % std::mem::align_of::<T>() != 0 {
|
|
25
|
+
return Err(PyValueError::new_err(format!(
|
|
26
|
+
"{what}: data pointer is not aligned for its dtype"
|
|
27
|
+
)));
|
|
28
|
+
}
|
|
29
|
+
Ok(addr as *mut T)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Borrow an input tensor's storage.
|
|
33
|
+
///
|
|
34
|
+
/// # Safety
|
|
35
|
+
/// `buf` must describe `buf.1` initialised elements of `T` that stay alive and are not
|
|
36
|
+
/// written by anything else while the returned slice is in use.
|
|
37
|
+
pub unsafe fn input<'a, T>(buf: Buf, what: &str) -> PyResult<&'a [T]> {
|
|
38
|
+
let ptr = checked::<T>(buf, what)?;
|
|
39
|
+
Ok(unsafe { std::slice::from_raw_parts(ptr, buf.1) })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Borrow an output tensor's storage for writing.
|
|
43
|
+
///
|
|
44
|
+
/// # Safety
|
|
45
|
+
/// As [`input`], and additionally no other slice (input or output) may overlap it.
|
|
46
|
+
pub unsafe fn output<'a, T>(buf: Buf, what: &str) -> PyResult<&'a mut [T]> {
|
|
47
|
+
let ptr = checked::<T>(buf, what)?;
|
|
48
|
+
Ok(unsafe { std::slice::from_raw_parts_mut(ptr, buf.1) })
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Fail with a `ValueError` unless `len == expected`.
|
|
52
|
+
pub fn expect_len(len: usize, expected: usize, what: &str) -> PyResult<()> {
|
|
53
|
+
if len != expected {
|
|
54
|
+
return Err(PyValueError::new_err(format!(
|
|
55
|
+
"{what}: expected {expected} elements, got {len}"
|
|
56
|
+
)));
|
|
57
|
+
}
|
|
58
|
+
Ok(())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Address ranges of two buffers overlap (empty buffers never do).
|
|
62
|
+
fn overlaps(a: Buf, b: Buf, elem: usize) -> bool {
|
|
63
|
+
a.1 != 0 && b.1 != 0 && a.0 < b.0 + b.1 * elem && b.0 < a.0 + a.1 * elem
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Refuse outputs that alias each other or any input; the kernels assume exclusive access.
|
|
67
|
+
pub fn no_aliasing(outputs: &[(Buf, &str)], inputs: &[Buf], elem: usize) -> PyResult<()> {
|
|
68
|
+
for (i, (o, name)) in outputs.iter().enumerate() {
|
|
69
|
+
for (p, _) in &outputs[i + 1..] {
|
|
70
|
+
if overlaps(*o, *p, elem) {
|
|
71
|
+
return Err(PyValueError::new_err(format!(
|
|
72
|
+
"{name} aliases another output"
|
|
73
|
+
)));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for p in inputs {
|
|
77
|
+
if overlaps(*o, *p, elem) {
|
|
78
|
+
return Err(PyValueError::new_err(format!("{name} aliases an input")));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
Ok(())
|
|
83
|
+
}
|