Compare commits

..

2 Commits

Author SHA1 Message Date
e7e9a7389c some results but includes too big matrix for my RAM, start of C 2026-03-15 13:02:55 +01:00
8b24f2dcfd checking spmv also 2026-03-15 12:16:22 +01:00
4 changed files with 174 additions and 50 deletions

54
goSparseResults.json Normal file
View File

@ -0,0 +1,54 @@
[
{
"label": "FEM_3D_thermal2",
"rows": 147900,
"cols": 147900,
"nnz": 3489300,
"matmul_runs": 16,
"matmul_total_ns": 1413419300,
"matmul_avg_ns": 88338706,
"matmul_output_nnz": 14335500,
"spmv_runs": 16,
"spmv_total_ns": 21010700,
"spmv_avg_ns": 1313168
},
{
"label": "ldoor",
"rows": 952203,
"cols": 952203,
"nnz": 23737339,
"matmul_runs": 16,
"matmul_total_ns": 6835373200,
"matmul_avg_ns": 427210825,
"matmul_output_nnz": 43783061,
"spmv_runs": 16,
"spmv_total_ns": 156246400,
"spmv_avg_ns": 9765400
},
{
"label": "Cube_Coup_dt0",
"rows": 2164760,
"cols": 2164760,
"nnz": 64685452,
"matmul_runs": 16,
"matmul_total_ns": 32192429900,
"matmul_avg_ns": 2012026868,
"matmul_output_nnz": 234465452,
"spmv_runs": 16,
"spmv_total_ns": 392950200,
"spmv_avg_ns": 24559387
},
{
"label": "nlpkkt240",
"rows": 27993600,
"cols": 27993600,
"nnz": 401232976,
"matmul_runs": 16,
"matmul_total_ns": 38319352500,
"matmul_avg_ns": 2394959531,
"matmul_output_nnz": 401232976,
"spmv_runs": 16,
"spmv_total_ns": 3164097400,
"spmv_avg_ns": 197756087
}
]

23
src/main.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
typedef int32_t S32;
typedef uint32_t U32;
typedef float F32;
typedef double F64;
typedef int32_t B32;
int main() {
printf(" ******* \n HELLO WARRUDU \n ****);
return 0;
}

View File

@ -2,6 +2,7 @@ package main
import (
"bufio"
"encoding/json"
"fmt"
"os"
"path/filepath"
@ -13,10 +14,7 @@ import (
"gonum.org/v1/gonum/mat"
)
var (
gNumMatmuls = 10
gNumSolves = 10
)
var gNumTestIterations = 16
type SparseMatrixTiming struct {
Label string `json:"label"`
@ -27,10 +25,11 @@ type SparseMatrixTiming struct {
MatMulRuns int `json:"matmul_runs"`
MatMulTotalNs int64 `json:"matmul_total_ns"`
MatMulAvgNs int64 `json:"matmul_avg_ns"`
MatMulOutputNNZ int `json:"matmul_output_nnz"`
SolveRuns int `json:"solve_runs"`
SolveTotalNs int64 `json:"solve_total_ns"`
SolveAvgNs int64 `json:"solve_avg_ns"`
SpMVRuns int `json:"spmv_runs"`
SpMVTotalNs int64 `json:"spmv_total_ns"`
SpMVAvgNs int64 `json:"spmv_avg_ns"`
}
type SparseBenchmarkCase struct {
@ -38,6 +37,21 @@ type SparseBenchmarkCase struct {
Matrix *sparse.CSR
}
func writeTimingJSON(all []SparseMatrixTiming, outPath string) {
f, err := os.Create(outPath)
if err != nil {
panic(err)
}
defer f.Close()
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
if err := enc.Encode(all); err != nil {
panic(err)
}
}
// The "SuiteSparse" collection of matrices come in a format called
// "market matrix" and so we parse and load them to a sparse.COO format here.
func matrixLoadMarket(path string) *sparse.CSR {
@ -131,7 +145,7 @@ func timeSparseMatmuls(bcase *SparseBenchmarkCase) {
// The CSR x CSR matrix multiplication is supposed to have a specific optimised
// path for matmuls
var out sparse.CSR
numberOfMults := gNumMatmuls
numberOfMults := gNumTestIterations
fmt.Printf("NNZ before matmuls: %d\n", mCSR.NNZ())
@ -147,6 +161,7 @@ func timeSparseMatmuls(bcase *SparseBenchmarkCase) {
panic("Sparsity pattern changed unexpectedly after matmul!")
}
bcase.Timing.MatMulOutputNNZ = out.NNZ()
bcase.Timing.MatMulRuns = numberOfMults
bcase.Timing.MatMulTotalNs = timeElapsed.Nanoseconds()
@ -154,45 +169,48 @@ func timeSparseMatmuls(bcase *SparseBenchmarkCase) {
bcase.Timing.MatMulAvgNs = timeAvgNS
}
func timeSparseSolve(bcase *SparseBenchmarkCase) {
matrix := bcase.Matrix
rows, _ := matrix.Dims()
rhsData := make([]float64, rows) // We have checked square matrix already
for i := range rhsData {
rhsData[i] = 1.0
}
b := mat.NewVecDense(rows, rhsData)
x := mat.NewVecDense(rows, nil)
func timeSparseMatVec(bcase *SparseBenchmarkCase) {
A := bcase.Matrix
rows, cols := A.Dims()
var chol sparse.Cholesky
x := mat.NewVecDense(cols, nil)
y := mat.NewVecDense(rows, nil)
for i := 0; i < cols; i++ {
x.SetVec(i, 1.0)
}
// warmup
err := chol.SolveVecTo(x, b)
if err != nil {
panic(err)
A.MulVecTo(y.RawVector().Data, false, x.RawVector().Data)
norm := y.Norm(2)
if norm < 1e-12 {
panic("Norm of resulting SpMV is zero. Something went wrong.\n")
}
numberOfSolves := gNumSolves
for i := 0; i < 3; i += 1 {
numberOfRuns := gNumTestIterations
timeBegin := time.Now()
chol.Factorize(matrix)
err = chol.SolveVecTo(x, b)
if err != nil {
panic(err)
}
timeElapsed := time.Since(timeBegin)
for i := 0; i < numberOfRuns; i++ {
// fmt.Printf("spmv iteration %d\n", i)
A.MulVecTo(y.RawVector().Data, false, x.RawVector().Data)
}
bcase.Timing.SolveRuns = numberOfSolves
bcase.Timing.SolveTotalNs = timeElapsed.Nanoseconds()
bcase.Timing.SolveAvgNs = timeElapsed.Nanoseconds() / int64(numberOfSolves)
timeElapsed := time.Since(timeBegin)
total := timeElapsed.Nanoseconds()
avg := total / int64(numberOfRuns)
bcase.Timing.SpMVTotalNs = total
bcase.Timing.SpMVAvgNs = avg
bcase.Timing.SpMVRuns = numberOfRuns
}
func timeNanoToMS(timeNS int64) float64 {
return float64(timeNS) / float64(1e6)
}
func doTimings(path string) {
func doTimings(path string) SparseMatrixTiming {
bcase := getSparseBenchmarkCase(path)
rows := bcase.Timing.Rows
cols := bcase.Timing.Cols
@ -201,23 +219,43 @@ func doTimings(path string) {
panic("Sparse benchmark assumes square matrix")
}
doMatMul := true
if doMatMul {
fmt.Printf("Timing sparse matrix %s with size: %d x %d \n", bcase.Timing.Label, rows, cols)
fmt.Printf("Matmul:\n")
timeSparseMatmuls(&bcase)
avgMatMulTimeMS := timeNanoToMS(bcase.Timing.MatMulAvgNs)
fmt.Printf("Avg matmul time for %s: %.4f ms \n", bcase.Timing.Label, avgMatMulTimeMS)
}
fmt.Printf("Cholesky solve:\n")
timeSparseSolve(&bcase)
avgSolveTimeMS := timeNanoToMS(bcase.Timing.SolveAvgNs)
fmt.Printf("Avg Cholesky solve time for %s: %.4f ms \n", bcase.Timing.Label, avgSolveTimeMS)
doSpMV := true
if doSpMV {
fmt.Printf("SpMV:\n")
timeSparseMatVec(&bcase)
avgSpMVTimeMS := timeNanoToMS(bcase.Timing.SpMVAvgNs)
fmt.Printf("Avg SpMV time for %s: %.4f ms\n", bcase.Timing.Label, avgSpMVTimeMS)
}
return bcase.Timing
}
func main() {
mainBegin := time.Now()
thermal2Path := "suitesparse_test_matrices/thermal2.mtx"
doTimings(thermal2Path)
paths := []string{
"suitesparse_test_matrices/FEM_3D_thermal2.mtx",
"suitesparse_test_matrices/ldoor.mtx",
"suitesparse_test_matrices/Cube_Coup_dt0.mtx",
"suitesparse_test_matrices/nlpkkt240.mtx",
}
results := make([]SparseMatrixTiming, 0, len(paths))
for _, path := range paths {
results = append(results, doTimings(path))
}
writeTimingJSON(results, "goSparseResults.json")
mainElapsed := time.Since(mainBegin)

View File

@ -1,6 +1,15 @@
# This is just a small matrix for debugging / validating code
https://suitesparse-collection-website.herokuapp.com/MM/HB/1138_bus.tar.gz
# 3.5M NNZ 3d thermal problem
https://suitesparse-collection-website.herokuapp.com/MM/Botonakis/FEM_3D_thermal2.tar.gz
# This is a real large (not really, but ok) sparse matrix with 8.5 million non-zero elements
https://suitesparse-collection-website.herokuapp.com/MM/Schmid/thermal2.tar.gz
# Almost 43M NNZ, structural problem
https://suitesparse-collection-website.herokuapp.com/MM/GHS_psdef/ldoor.tar.gz
# Almost 125M non-zero elements from a structural problem, 420mb compressed, 1.1GB uncompressed .mtx
https://suitesparse-collection-website.herokuapp.com/MM/Janna/Cube_Coup_dt0.tar.gz
# 760M NNZ, optimization problem 1.23GB compressed, 8.4 GB uncompressed
# This was too large for my 32 GB memory and I went into swap... probably should exclude
https://suitesparse-collection-website.herokuapp.com/MM/Schenk/nlpkkt240.tar.gz