first whole bench

This commit is contained in:
antonl 2026-03-16 19:08:31 +01:00
parent d7c10045ba
commit a30a500564
5 changed files with 298 additions and 28 deletions

View File

@ -1,6 +1,6 @@
[
{"label":"FEM_3D_thermal2","rows":147900,"cols":147900,"nnz":3489300,"spmv_runs":32,"spmv_total_ns":3866100,"spmv_avg_ns":120815,"dense_rows":2048,"dense_cols":2048,"dense_runs":32,"dense_total_ns":957945100,"dense_avg_ns":29935784},
{"label":"ldoor","rows":952203,"cols":952203,"nnz":46522475,"spmv_runs":32,"spmv_total_ns":286909100,"spmv_avg_ns":8965909,"dense_rows":4096,"dense_cols":4096,"dense_runs":32,"dense_total_ns":7653100100,"dense_avg_ns":239159378},
{"label":"Cube_Coup_dt0","rows":2164760,"cols":2164760,"nnz":127206144,"spmv_runs":32,"spmv_total_ns":864947600,"spmv_avg_ns":27029612,"dense_rows":8192,"dense_cols":8192,"dense_runs":32,"dense_total_ns":59799139700,"dense_avg_ns":1868723115},
{"label":"nlpkkt200","rows":16240000,"cols":16240000,"nnz":448225632,"spmv_runs":32,"spmv_total_ns":2383754600,"spmv_avg_ns":74492331,"dense_rows":16384,"dense_cols":16384,"dense_runs":32,"dense_total_ns":471942950199,"dense_avg_ns":14748217193}
{"label":"FEM_3D_thermal2","rows":147900,"cols":147900,"nnz":3489300,"spmv_runs":32,"spmv_total_ns":9411500,"spmv_avg_ns":294109,"dense_rows":1024,"dense_cols":1024,"dense_runs":32,"dense_total_ns":129353000,"dense_avg_ns":4042281},
{"label":"ldoor","rows":952203,"cols":952203,"nnz":46522475,"spmv_runs":32,"spmv_total_ns":284244500,"spmv_avg_ns":8882640,"dense_rows":2048,"dense_cols":2048,"dense_runs":32,"dense_total_ns":1979492200,"dense_avg_ns":61859131},
{"label":"Cube_Coup_dt0","rows":2164760,"cols":2164760,"nnz":127206144,"spmv_runs":32,"spmv_total_ns":894006900,"spmv_avg_ns":27937715,"dense_rows":4096,"dense_cols":4096,"dense_runs":32,"dense_total_ns":8725314200,"dense_avg_ns":272666068},
{"label":"nlpkkt200","rows":16240000,"cols":16240000,"nnz":448225632,"spmv_runs":32,"spmv_total_ns":2437591700,"spmv_avg_ns":76174740,"dense_rows":8192,"dense_cols":8192,"dense_runs":32,"dense_total_ns":63669801300,"dense_avg_ns":1989681290}
]

58
goSparseResults.json Normal file
View File

@ -0,0 +1,58 @@
[
{
"label": "FEM_3D_thermal2",
"rows": 147900,
"cols": 147900,
"nnz": 3489300,
"dense_rows": 1024,
"dense_cols": 1024,
"dense_runs": 32,
"dense_total_ns": 678975700,
"dense_avg_ns": 21217990,
"spmv_runs": 32,
"spmv_total_ns": 44127200,
"spmv_avg_ns": 1378975
},
{
"label": "ldoor",
"rows": 952203,
"cols": 952203,
"nnz": 46522475,
"dense_rows": 2048,
"dense_cols": 2048,
"dense_runs": 32,
"dense_total_ns": 5421343500,
"dense_avg_ns": 169416984,
"spmv_runs": 32,
"spmv_total_ns": 515245900,
"spmv_avg_ns": 16101434
},
{
"label": "Cube_Coup_dt0",
"rows": 2164760,
"cols": 2164760,
"nnz": 127206144,
"dense_rows": 4096,
"dense_cols": 4096,
"dense_runs": 32,
"dense_total_ns": 43612138700,
"dense_avg_ns": 1362879334,
"spmv_runs": 32,
"spmv_total_ns": 1300820500,
"spmv_avg_ns": 40650640
},
{
"label": "nlpkkt200",
"rows": 16240000,
"cols": 16240000,
"nnz": 448225632,
"dense_rows": 8192,
"dense_cols": 8192,
"dense_runs": 32,
"dense_total_ns": 350072230900,
"dense_avg_ns": 10939757215,
"spmv_runs": 32,
"spmv_total_ns": 6186462100,
"spmv_avg_ns": 193326940
}
]

111
plot.py Normal file
View File

@ -0,0 +1,111 @@
import json
import numpy as np
import matplotlib.pyplot as plt
#font sizes
plt.rcParams.update({
"font.size": 18,
"axes.titlesize": 22,
"axes.labelsize": 20,
"xtick.labelsize": 16,
"ytick.labelsize": 16,
"legend.fontsize": 16,
})
def getResults(filename):
with open(filename) as f:
data = json.load(f)
# Prepare lists
spmv_sizes = []
spmv_times = []
dense_sizes = []
dense_times = []
labels = []
for d in data:
spmv_sizes.append(d["nnz"])
spmv_times.append(d["spmv_avg_ns"])
dense_sizes.append(d["dense_rows"])
dense_times.append(d["dense_avg_ns"])
labels.append(d["label"])
return spmv_sizes, spmv_times, dense_sizes, dense_times, labels
c_spmv_sizes, c_spmv_times, c_dense_sizes, c_dense_times, c_labels = getResults("cSparseResults.json")
go_spmv_sizes, go_spmv_times, go_dense_sizes, go_dense_times, go_labels = getResults("goSparseResults.json")
# make sure data aligns on x axis
for i in range(len(go_spmv_sizes)):
assert(c_spmv_sizes[i] == go_spmv_sizes[i])
assert(go_dense_sizes[i] == c_dense_sizes[i])
#spmv plot
x_spmv = c_spmv_sizes
x_spmv = np.float64(x_spmv)/1e6
go_spmv_float = np.float64(go_spmv_times)
c_spmv_float = np.float64(c_spmv_times)
ratio_spmv = go_spmv_float/c_spmv_float
plt.figure("spmv")
plt.plot(x_spmv, ratio_spmv, 'kd-')
plt.title("Sparse Matrix-Vector multiplication ratio Go native / C MKL")
plt.xlabel("SuiteSparse matrix millions of number of non-zeros")
plt.ylabel("Average time ratio Go/C for SpMV-kernel")
xtick_string = [f"{x:.1f}\n{label}" for x, label in zip(x_spmv, c_labels)]
plt.xticks(x_spmv, xtick_string)
plt.grid()
# dense plot
x_dense = c_dense_sizes
go_dense_float = np.float64(go_dense_times)
c_dense_float = np.float64(c_dense_times)
ratio_dense = go_dense_float/c_dense_float
plt.figure("dense")
plt.plot(x_dense, ratio_dense, 'kd-')
plt.title("Dense Matrix-Matrix multiplication ratio Go native / C MKL")
plt.xlabel("Dense matrix size")
plt.ylabel("Average time ratio Go/C for matmul kernel")
xtick_string = [f"{x}^2" for x in x_dense]
plt.xticks(x_dense, xtick_string)
plt.grid()
plt.show()
## ---- SpMV Plot ----
#plt.figure()
#plt.plot(spmv_sizes, spmv_times, marker='o')
#
#for i, label in enumerate(labels):
# plt.annotate(label, (spmv_sizes[i], spmv_times[i]))
#
#plt.xlabel("Number of Nonzeros (nnz)")
#plt.ylabel("Average Time (ns)")
#plt.title("SpMV: Avg Time vs Size")
#plt.xscale("log")
#plt.yscale("log")
#plt.grid(True)
#
## ---- Dense Plot ----
#plt.figure()
#plt.plot(dense_sizes, dense_times, marker='o')
#
#for i, label in enumerate(labels):
# plt.annotate(label, (dense_sizes[i], dense_times[i]))
#
#plt.xlabel("Matrix Size (rows × cols)")
#plt.ylabel("Average Time (ns)")
#plt.title("Dense: Avg Time vs Size")
#plt.xscale("log")
#plt.yscale("log")
#plt.grid(True)
#
#plt.show()

View File

@ -629,7 +629,7 @@ Timing doSpMVTimings(const char *path) {
int main() {
S32 numPaths = 4;
int denseRows[] = {2048, 4096, 4096*2, 4096*4};
int denseRows[] = {1024, 2048, 4096, 4096*2};
const char *paths[] = {
"E:\\dev\\go_matmul_perf\\suitesparse_test_matrices\\FEM_3D_thermal2.mtx",

View File

@ -14,6 +14,7 @@ import (
"time"
"github.com/james-bowman/sparse"
"gonum.org/v1/gonum/blas/blas64"
"gonum.org/v1/gonum/mat"
)
@ -57,8 +58,6 @@ func writeTimingJSON(all []Timing, outPath string) {
}
}
// 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 {
f, err := os.Open(path)
if err != nil {
@ -68,44 +67,142 @@ func matrixLoadMarket(path string) *sparse.CSR {
scanner := bufio.NewScanner(f)
// skip header
scanner.Scan()
// Read header
if !scanner.Scan() {
panic("failed to read Matrix Market header")
}
header := strings.Fields(scanner.Text())
if len(header) < 5 {
panic("invalid Matrix Market header")
}
// skip comments
field := header[3]
symmetry := header[4]
isPattern := field == "pattern"
isInteger := field == "integer"
isReal := field == "real"
isSymmetric := symmetry == "symmetric"
if !isPattern && !isInteger && !isReal {
panic("unsupported Matrix Market field type")
}
if symmetry != "general" && symmetry != "symmetric" {
panic("unsupported Matrix Market symmetry")
}
// Skip comments, then read size line
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "%") {
if !strings.HasPrefix(strings.TrimSpace(line), "%") {
break
}
}
fields := strings.Fields(scanner.Text())
if len(fields) != 3 {
panic("invalid Matrix Market size line")
}
rows, _ := strconv.Atoi(fields[0])
cols, _ := strconv.Atoi(fields[1])
nnz, _ := strconv.Atoi(fields[2])
rows, err := strconv.Atoi(fields[0])
if err != nil {
panic(err)
}
cols, err := strconv.Atoi(fields[1])
if err != nil {
panic(err)
}
nnzInFile, err := strconv.Atoi(fields[2])
if err != nil {
panic(err)
}
r := make([]int, nnz)
c := make([]int, nnz)
v := make([]float64, nnz)
capacity := nnzInFile
if isSymmetric {
capacity = 2 * nnzInFile
}
i := 0
r := make([]int, 0, capacity)
c := make([]int, 0, capacity)
v := make([]float64, 0, capacity)
for scanner.Scan() {
f := strings.Fields(scanner.Text())
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "%") {
continue
}
ri, _ := strconv.Atoi(f[0])
ci, _ := strconv.Atoi(f[1])
val, _ := strconv.ParseFloat(f[2], 64)
flds := strings.Fields(line)
r[i] = ri - 1
c[i] = ci - 1
v[i] = val
i++
var ri, ci int
var val float64 = 1.0
if isPattern {
if len(flds) != 2 {
panic("bad pattern entry")
}
ri, err = strconv.Atoi(flds[0])
if err != nil {
panic(err)
}
ci, err = strconv.Atoi(flds[1])
if err != nil {
panic(err)
}
} else if isInteger {
if len(flds) != 3 {
panic("bad integer entry")
}
ri, err = strconv.Atoi(flds[0])
if err != nil {
panic(err)
}
ci, err = strconv.Atoi(flds[1])
if err != nil {
panic(err)
}
ival, err := strconv.Atoi(flds[2])
if err != nil {
panic(err)
}
val = float64(ival)
} else {
if len(flds) != 3 {
panic("bad real entry")
}
ri, err = strconv.Atoi(flds[0])
if err != nil {
panic(err)
}
ci, err = strconv.Atoi(flds[1])
if err != nil {
panic(err)
}
val, err = strconv.ParseFloat(flds[2], 64)
if err != nil {
panic(err)
}
}
ri--
ci--
r = append(r, ri)
c = append(c, ci)
v = append(v, val)
if isSymmetric && ri != ci {
r = append(r, ci)
c = append(c, ri)
v = append(v, val)
}
}
if err := scanner.Err(); err != nil {
panic(err)
}
coo := sparse.NewCOO(rows, cols, r, c, v)
return coo.ToCSR()
}
@ -255,6 +352,10 @@ func doTimings(path string, denseRows int) Timing {
func main() {
mainBegin := time.Now()
fmt.Printf("BLAS backend: %T\n", blas64.Implementation())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
paths := []string{
"suitesparse_test_matrices/FEM_3D_thermal2.mtx",
"suitesparse_test_matrices/ldoor.mtx",
@ -263,7 +364,7 @@ func main() {
}
denseRows := []int{
2048, 4096, 4096 * 2, 4096 * 4,
1024, 2048, 4096, 4096 * 2,
}
numPaths := len(paths)