Skip to content
Merged
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

## [Unreleased]

## [0.62.3] - 2026-10-25

Headline: **opening a tokenizer GGUF and building its tokenizer is several times cheaper, and the dense FP32 `A · B`
product uses AVX2/FMA on x86-64** (#1446, #1447, #1445, see *Changed*). `StreamingGGUFReader` read the metadata one
value at a time (one `readAt` per primitive, one `FileChannel` read each on a file source); it now decodes from 64 KB
blocks, with `fields` unchanged. `TextFrontEnds.fromGguf` copied the ~262k-entry token, token-type and score lists
three to four times per build; it now takes each once, with token ids identical on 26,803 texts. Gemma-3 tokenizer
GGUF on a 32-bit ARM Android device (debuggable app): file-source parse 23.3 → 1.2 s, read + build on the first load
in a process 8.4–11.2 → 6.0–6.4 s; JVM file-source parse 1,002 → 21–45 ms. The native `skainet_fp32_matmul` gets a
6 × 16 register-tiled AVX2/FMA lane selected at runtime (63 × 1024 × 1024: 21 → 281 GFLOP/s on a six-core laptop),
and its heap face no longer zeroes the rest of a sub-block caller's output buffer.

### Changed

- **Dense FP32 SGEMM uses AVX2/FMA on x86-64** (`skainet-backend-native-cpu`): `skainet_fp32_matmul`, the kernel behind every `A · B` product the JVM hands to the native lane (a weight stored `[in, out]`, attention scores and values, training), had register-tiled bodies for wasm SIMD128 only; the x86-64 library is built for baseline x86-64, so the kernel ran a scalar/SSE2 outer-product loop without FMA that loaded and stored a row of C for every row of A. Hosts with AVX2 and FMA now select, through the cached `cpuid` probe the `x · Wᵀ` kernel introduced, a lane compiled per function for that target: a 6 × 16 tile of C in twelve eight-lane FMA accumulators over a 256-deep k-block, each sixteen-column panel of B packed once so a power-of-two `n` no longer maps every row of the panel to one L1 set, 2 × 16 and 1 × 16 tiles for the rows left over and a lane-masked stripe for the columns left over. Every output takes one fused multiply-add per `p` in ascending `p` whichever tile holds it, so sliced, threaded and whole calls stay bit-identical to each other; against the previous x86 numbers an output moves within rounding, as the NEON and wasm lanes already do. Machines without AVX2, and every other architecture, run the previous code. Measured single call on a six-core laptop, develop → this change: 63 × 1024 × 1024 21 → 281 GFLOP/s, 1024³ 48 → 311, 512³ 59 → 358, 192 × 192 × 64 (one thread) 18 → 99.
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ authors:
orcid: https://orcid.org/0009-0006-7981-4075
- name: SKaiNET-developers contributors
website: https://github.com/SKaiNET-developers
version: "0.62.2"
version: "0.62.3"
date-released: "2026-10-21"
license: MIT
repository-code: https://github.com/SKaiNET-developers/SKaiNET
Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Add the core dependencies (Gradle Kotlin DSL):
```kotlin
dependencies {
// Recommended: import the umbrella BOM and drop versions on the engine modules.
implementation(platform("sk.ainet:skainet-bom:0.62.2"))
implementation(platform("sk.ainet:skainet-bom:0.62.3"))

implementation("sk.ainet.core:skainet-lang-core")
implementation("sk.ainet.core:skainet-backend-cpu")
Expand Down Expand Up @@ -308,7 +308,17 @@ val withoutLabel = dataPipeline<RawDataset>()

---

## What's New in 0.62.2
## What's New in 0.62.3

A load-time and kernel release. `StreamingGGUFReader` decodes the GGUF metadata from 64 KB blocks instead of one
source read per value, and `TextFrontEnds.fromGguf` builds a SentencePiece tokenizer in one pass over the vocabulary
instead of three to four copies of it; `fields`, the public API and the token ids stay the same. On a Gemma-3
tokenizer GGUF a file-source parse drops from 1.0 s to 21–45 ms on the JVM and from 23.3 s to 1.2 s on a 32-bit ARM
Android device, where read + build on the first load in a process goes from 8.4–11.2 s to 6.0–6.4 s. The native
dense FP32 `A · B` kernel gets an AVX2/FMA register-tiled lane on x86-64 (63 × 1024 × 1024: 21 → 281 GFLOP/s), and
no longer overwrites the parts of a sub-block caller's output buffer outside the block.

### Carried from 0.62.2

A performance release for the JVM native lane. The dense FP32 `x · Wᵀ` kernel — what every resident dense
weight resolves to once `skainet-backend-native-cpu` is on the classpath — now splits its work across the
Expand Down Expand Up @@ -381,6 +391,11 @@ We love contributions! Whether it's a new operator, documentation, or a bug fix:

Browse the full codebase documentation on [DeepWiki](https://deepwiki.com/SKaiNET-developers/SKaiNET).

### Contributors (0.62.3)

- **Michal Harakal** ([@michalharakal](https://github.com/michalharakal)) — the buffered GGUF metadata reader, the
one-pass tokenizer build, the AVX2/FMA dense FP32 SGEMM lane with their tests and measurements, and the release

### Contributors (0.62.2)

- **Michal Harakal** ([@michalharakal](https://github.com/michalharakal)) — the schedule-driven and AVX2/FMA
Expand Down Expand Up @@ -512,7 +527,7 @@ from it). Ready-to-paste BibTeX:
author = {Harakal, Michal and {SKaiNET-developers contributors}},
title = {{SKaiNET}: A {Kotlin} Multiplatform {AI} Framework},
year = {2026},
note = {Version 0.62.2. MIT License},
note = {Version 0.62.3. MIT License},
howpublished = {\url{https://github.com/SKaiNET-developers/SKaiNET}}
}
```
Expand Down
2 changes: 1 addition & 1 deletion docs/antora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ asciidoc:
framework_name: SKaiNET
# Current SKaiNET release — bump once per release; referenced as
# {skainet_version} in dependency snippets (blocks need subs="attributes+").
skainet_version: 0.62.2
skainet_version: 0.62.3
ksp_version: 2.2.21-2.0.5
dokka_version: 2.1.0
asciidoctorj_version: 3.0.0
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
= Kernel × platform support matrix
:description: Which compute-kernel provider serves each weight format on each KMP target.

Generated from `kernel-support.json` (version `0.62.2`) by `KernelSupportMatrixTest` — registry introspection of the registered `KernelProvider` implementations. Do not edit by hand; run `./gradlew generateKernelMatrix` to refresh.
Generated from `kernel-support.json` (version `0.62.3`) by `KernelSupportMatrixTest` — registry introspection of the registered `KernelProvider` implementations. Do not edit by hand; run `./gradlew generateKernelMatrix` to refresh.

Each cell is the best (highest-priority) provider that serves `Float32 × format` `matmul` on that platform: *native-ffm* / *native-jni* / *native-cinterop* (100) → *panama-vector* / *wasm-simd128* (50) → *scalar* (0). An empty cell (`—`) means no provider carries a kernel there (the format is dequant-to-FP32 only). The JS/WASM column assumes `WasmSimd.install()` has run; without the sidecar it is the scalar floor.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
= AI-NET Operators Reference

Generated from version `0.62.2` on 2026-10-24
Generated from version `0.62.3` on 2026-10-25

== Operators by Modality

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/reference/ops-status-matrix.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
= Operator Coverage Matrix
:description: Cross-backend status for every operator function in SKaiNET.

Generated from `operators.json` version `0.62.2` on 2026-10-24.
Generated from `operators.json` version `0.62.3` on 2026-10-25.

Rows are `Operator.function` pairs. A gap is marked in source with `@NotImplemented(reason = …, issue = …)` (or `@InProgress`) and shows up here as ❌ (or 🚧) linked to its tracking issue; the PR that closes the gap removes the annotation. See xref:contributing/issue-taxonomy.adoc[Issue taxonomy] to pick one up.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ An Android project with Kotlin. Add the SKaiNET modules:
[source,kotlin]
----
dependencies {
implementation("sk.ainet.core:skainet-lang-core:0.62.2") // tensors, DSL, training
implementation("sk.ainet.core:skainet-backend-cpu:0.62.2") // CPU ops
implementation("sk.ainet.core:skainet-compile-dag:0.62.2") // autograd (training context)
implementation("sk.ainet.core:skainet-data-api:0.62.2") // Dataset / DataBatch
implementation("sk.ainet.core:skainet-data-simple:0.62.2") // embedded Iris
runtimeOnly("sk.ainet.core:skainet-backend-jni-cpu:0.62.2") // NEON kernels (see below)
implementation("sk.ainet.core:skainet-lang-core:0.62.3") // tensors, DSL, training
implementation("sk.ainet.core:skainet-backend-cpu:0.62.3") // CPU ops
implementation("sk.ainet.core:skainet-compile-dag:0.62.3") // autograd (training context)
implementation("sk.ainet.core:skainet-data-api:0.62.3") // Dataset / DataBatch
implementation("sk.ainet.core:skainet-data-simple:0.62.3") // embedded Iris
runtimeOnly("sk.ainet.core:skainet-backend-jni-cpu:0.62.3") // NEON kernels (see below)
}
----

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
GROUP=sk.ainet.core
VERSION_NAME=0.62.2
VERSION_NAME=0.62.3
POM_DESCRIPTION=SKaiNET

POM_URL=https://github.com/SKaiNET-developers/skainet/
Expand Down
Loading