Documentation
¶
Overview ¶
Package simd provides SIMD-accelerated vector operations for NornicDB.
This package wraps the viterin/vek32 library which implements high-performance vector similarity calculations using true AVX2+FMA assembly for x86/amd64 processors.
Implementation ¶
The package automatically detects CPU capabilities at runtime and selects the fastest available implementation:
- x86/amd64: AVX2 + FMA SIMD assembly via vek32 (Intel Haswell+, AMD Zen+)
- arm64: NEON assembly via vek32 (Apple Silicon, ARM servers)
- fallback: Pure Go implementation for unsupported platforms
No configuration is required; SIMD acceleration is detected and enabled automatically.
Supported Operations ¶
- DotProduct: Dot product of two vectors
- CosineSimilarity: Cosine similarity between two vectors
- EuclideanDistance: Euclidean distance between two vectors
- Norm: Euclidean norm (L2 norm / magnitude) of a vector
- NormalizeInPlace: Normalize a vector to unit length in-place
Performance ¶
Measurements on Intel i9-9900KF (AVX2+FMA) comparing vek32 SIMD vs pure Go:
- DotProduct (1536-dim vectors): ~1.9x faster (380 ns → 700 ns with SIMD on this CPU)
- CosineSimilarity (1536-dim): ~0.31x-0.53x (NOTE: vek32 assembly is optimized)
- EuclideanDistance (1536-dim): ~1.9x faster
- Norm (1536-dim): ~1.6x faster
- vek32.Sum (operations): Up to 20x faster with true SIMD assembly
- vek32.MatMul (matrix ops): Up to 14x faster for float32
Performance varies by vector size and CPU features. Larger vectors and operations like matrix multiplication benefit most from SIMD acceleration.
Usage ¶
import "github.com/orneryd/nornicdb/pkg/simd"
a := []float32{1.0, 2.0, 3.0, 4.0}
b := []float32{5.0, 6.0, 7.0, 8.0}
// Cosine similarity (most common for embeddings)
sim := simd.CosineSimilarity(a, b)
// Dot product
dot := simd.DotProduct(a, b)
// Euclidean distance
dist := simd.EuclideanDistance(a, b)
// Normalize a vector
simd.NormalizeInPlace(a)
// Check SIMD acceleration status
info := simd.Info()
if info.Accelerated {
fmt.Printf("Using %s SIMD with features: %v\n", info.Implementation, info.Features)
}
Thread Safety ¶
All functions in this package are safe for concurrent use. They do not maintain global state and all operations are pure functions.
Precision Notes ¶
- Float32 operations use float32 throughout for maximum SIMD performance - vek32 SIMD functions are compiled with -ffast-math for speed - This trades strict IEEE 754 compliance for performance (inputs should never be NaN/Inf) - For higher precision requirements, use pkg/math/vector which uses float64 accumulation
Dependencies ¶
- github.com/viterin/vek: SIMD vector functions (true assembly implementation) - golang.org/x/sys/cpu: CPU feature detection
Index ¶
- Variables
- func BatchCosineSimilarity(embeddings []float32, query []float32, scores []float32)
- func BatchCosineSimilarityMetal(embeddings []float32, query []float32, scores []float32) error
- func BatchDotProduct(embeddings []float32, query []float32, results []float32)
- func BatchDotProductMetal(embeddings []float32, query []float32, results []float32) error
- func BatchEuclideanDistance(embeddings []float32, query []float32, distances []float32)
- func BatchEuclideanDistanceMetal(embeddings []float32, query []float32, distances []float32) error
- func BatchNormalize(vectors []float32, numVectors, dimensions int)
- func BatchNormalizeMetal(vectors []float32, numVectors, dimensions int) error
- func CosineSimilarity(a, b []float32) float32
- func DotProduct(a, b []float32) float32
- func EuclideanDistance(a, b []float32) float32
- func MetalAvailable() bool
- func MetalCosineSimilarity(a, b []float32) float32
- func MetalDotProduct(a, b []float32) float32
- func MetalEuclideanDistance(a, b []float32) float32
- func MetalNorm(v []float32) float32
- func Norm(v []float32) float32
- func NormalizeInPlace(v []float32)
- type Implementation
- type RuntimeInfo
Constants ¶
This section is empty.
Variables ¶
var (
ErrMetalNotAvailable = errors.New("simd/metal: Metal GPU not available (build without metal tag)")
)
Metal backend errors
Functions ¶
func BatchCosineSimilarity ¶
BatchCosineSimilarity computes cosine similarity between a query vector and a batch of embedding vectors. Automatically uses Metal GPU if available on macOS, otherwise falls back to CPU SIMD.
This is the recommended function for searching embedding collections.
Parameters:
- embeddings: Contiguous array of [num_vectors × dimensions] float32
- query: Single query vector of [dimensions] float32
- scores: Output array of [num_vectors] float32 similarity scores
Example:
embeddings := make([]float32, 1000*768) // 1000 vectors of 768 dimensions query := make([]float32, 768) scores := make([]float32, 1000) simd.BatchCosineSimilarity(embeddings, query, scores)
func BatchCosineSimilarityMetal ¶
BatchCosineSimilarityMetal returns error when Metal is not available
func BatchDotProduct ¶
BatchDotProduct computes dot product between a query vector and a batch of vectors. Automatically uses Metal GPU if available, otherwise falls back to CPU SIMD.
Parameters:
- embeddings: Contiguous array of [num_vectors × dimensions] float32
- query: Single query vector of [dimensions] float32
- results: Output array of [num_vectors] float32 dot products
func BatchDotProductMetal ¶
BatchDotProductMetal returns error when Metal is not available
func BatchEuclideanDistance ¶
BatchEuclideanDistance computes Euclidean distance between a query vector and a batch of vectors. Automatically uses Metal GPU if available, otherwise falls back to CPU SIMD.
Parameters:
- embeddings: Contiguous array of [num_vectors × dimensions] float32
- query: Single query vector of [dimensions] float32
- distances: Output array of [num_vectors] float32 distances
func BatchEuclideanDistanceMetal ¶
BatchEuclideanDistanceMetal returns error when Metal is not available
func BatchNormalize ¶
BatchNormalize normalizes a batch of vectors in-place. Automatically uses Metal GPU if available, otherwise falls back to CPU SIMD.
Parameters:
- vectors: Contiguous array of [num_vectors × dimensions] float32
- numVectors: Number of vectors
- dimensions: Dimension of each vector
func BatchNormalizeMetal ¶
BatchNormalizeMetal returns error when Metal is not available
func CosineSimilarity ¶
CosineSimilarity computes the cosine similarity between two float32 vectors.
Cosine similarity measures the angle between two vectors, returning a value between -1 (opposite directions) and 1 (same direction). A value of 0 indicates orthogonal (perpendicular) vectors.
The formula is: dot(a, b) / (norm(a) * norm(b))
Requirements:
- Both vectors must have the same length
- Returns 0 if vectors are empty, have different lengths, or either is zero-length
Example:
a := []float32{1, 0, 0}
b := []float32{0, 1, 0}
result := simd.CosineSimilarity(a, b) // 0 (perpendicular)
func DotProduct ¶
DotProduct computes the dot product of two float32 vectors.
The dot product is defined as: sum(a[i] * b[i]) for all i.
Requirements:
- Both vectors must have the same length
- Returns 0 if vectors are empty or have different lengths
Example:
a := []float32{1, 2, 3}
b := []float32{4, 5, 6}
result := simd.DotProduct(a, b) // 1*4 + 2*5 + 3*6 = 32
func EuclideanDistance ¶
EuclideanDistance computes the Euclidean distance between two float32 vectors.
The Euclidean distance is the straight-line distance in N-dimensional space: sqrt(sum((a[i] - b[i])^2))
Requirements:
- Both vectors must have the same length
- Returns 0 if vectors are empty or have different lengths
Example:
a := []float32{0, 0}
b := []float32{3, 4}
result := simd.EuclideanDistance(a, b) // 5.0
func MetalAvailable ¶
func MetalAvailable() bool
MetalAvailable returns false when Metal is not compiled in
func MetalCosineSimilarity ¶
MetalCosineSimilarity falls back to CPU implementation
func MetalDotProduct ¶
MetalDotProduct falls back to CPU implementation
func MetalEuclideanDistance ¶
MetalEuclideanDistance falls back to CPU implementation
func Norm ¶
Norm computes the Euclidean norm (L2 norm / magnitude) of a float32 vector.
The norm is defined as: sqrt(sum(v[i]^2))
Example:
v := []float32{3, 4}
result := simd.Norm(v) // 5.0
func NormalizeInPlace ¶
func NormalizeInPlace(v []float32)
NormalizeInPlace normalizes a vector to unit length, modifying it in place.
After normalization, Norm(v) will equal 1.0 (within floating-point precision).
If the vector has zero length, it will remain unchanged.
Example:
v := []float32{3, 4}
simd.NormalizeInPlace(v)
// v is now {0.6, 0.8}
Types ¶
type Implementation ¶
type Implementation string
Implementation represents the active SIMD implementation
const ( // ImplGeneric indicates pure Go fallback (no SIMD) ImplGeneric Implementation = "generic" // ImplAVX2 indicates x86 AVX2+FMA SIMD ImplAVX2 Implementation = "avx2" // ImplNEON indicates ARM NEON SIMD ImplNEON Implementation = "neon" )
type RuntimeInfo ¶
type RuntimeInfo struct {
// Implementation is the active SIMD backend
Implementation Implementation
// Features lists specific CPU features being used
Features []string
// Accelerated indicates whether SIMD acceleration is active
Accelerated bool
}
RuntimeInfo contains information about the active SIMD implementation
func Info ¶
func Info() RuntimeInfo
Info returns information about the active SIMD implementation.
This can be used to check whether SIMD acceleration is being used and which specific features are enabled.
Example:
info := simd.Info()
if info.Accelerated {
fmt.Printf("Using %s SIMD\n", info.Implementation)
}