diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g new file mode 100644 index 00000000000..0396ccf4169 --- /dev/null +++ b/benchmark/matobj/bench-matelm-access.g @@ -0,0 +1,152 @@ +ReadGapRoot("benchmark/matobj/bench.g"); + + +TestReadingMatrix := function(m) + local f; + + PrintHeadline("m[i][j]"); + MyBench(function() + local u, i, j, rows, cols, x; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + x:=m[i][j]; + od; + od; + od; + end); + + PrintHeadline("m[i,j]"); + MyBench(function() + local u, i, j, rows, cols, x; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + x:=m[i,j]; + od; + od; + od; + end); + + PrintHeadline("MatElm(m,i,j)"); + MyBench(function() + local u, i, j, rows, cols, x; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + x:=MatElm(m,i,j); + od; + od; + od; + end); + + PrintHeadline("MatElm(m,i,j) with prefetched method"); + f:=ApplicableMethod(MatElm, [m,1,1]);; + MyBench(function() + local u, i, j, rows, cols, x; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + x:=f(m,i,j); + od; + od; + od; + end); + +end; + +TestWritingMatrix := function(m) + local f; + + PrintHeadline("m[i][j]:=elm"); + MyBench(function() + local u, i, j, rows, cols, x; + x:=m[1][1]; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + m[i][j]:=x; + od; + od; + od; + end); + + PrintHeadline("m[i,j]:=elm"); + MyBench(function() + local u, i, j, rows, cols, x; + x:=m[1][1]; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + m[i,j]:=x; + od; + od; + od; + end); + + PrintHeadline("SetMatElm(m,i,j,elm)"); + MyBench(function() + local u, i, j, rows, cols, x; + x:=m[1][1]; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + SetMatElm(m,i,j,x); + od; + od; + od; + end); + + PrintHeadline("SetMatElm(m,i,j,elm) with prefetched method"); + f:=ApplicableMethod(SetMatElm, [m,1,1,m[1][1]]);; + MyBench(function() + local u, i, j, rows, cols, x; + x:=m[1][1]; + rows := [1..Length(m)]; + cols := [1..Length(m[1])]; + for u in [1..QuoInt(100000,Length(m)*Length(m[1]))] do + for i in rows do + for j in cols do + f(m,i,j,x); + od; + od; + od; + end); +end; + +RunMatTest := function(desc, m) + Print("\n"); + PrintBoxed(Concatenation("Testing ", desc)); + TestReadingMatrix(m); + Print(TextAttr.2, "...now testing write access...\n", TextAttr.reset); + TestWritingMatrix(m); +end; + +m:=IdentityMat(10);; +RunMatTest("integer matrix", m); + +m:=IdentityMat(10,GF(2));; +RunMatTest("GF(2) rowlist", m); + +m:=IdentityMat(10,GF(2));; ConvertToMatrixRep(m);; +RunMatTest("GF(2) compressed matrix", m); + +m:=IdentityMat(10,GF(7));; +RunMatTest("GF(7) rowlist", m); + +m:=IdentityMat(10,GF(7));; ConvertToMatrixRep(m);; +RunMatTest("GF(7) compressed matrix", m); diff --git a/benchmark/matobj/bench-matobj-creation.g b/benchmark/matobj/bench-matobj-creation.g new file mode 100644 index 00000000000..375de10f560 --- /dev/null +++ b/benchmark/matobj/bench-matobj-creation.g @@ -0,0 +1,113 @@ +ReadGapRoot("benchmark/matobj/bench.g"); + + +TestCreatingVector := function(v) + Error("TODO"); +end; + +# test for old-style matrix constructors, as reference +TestCreatingMatrix := function(ring) + PrintHeadline("NullMat"); + MyBench(function() + local m, n, mat; + for m in [1..10] do + for n in [1..10] do + mat := NullMat(m, n, ring); + od; + od; + end); + + PrintHeadline("IdentityMat"); + MyBench(function() + local n, mat; + for n in [1..100] do + mat := IdentityMat(n, ring); + od; + end); +end; + +# test for matriobj constructors +TestCreatingMatrixObj := function(filter, ring) + local example_mat; + + example_mat := NewZeroMatrix(filter, ring, 1, 1); + + PrintHeadline("NewZeroMatrix"); + MyBench(function() + local m, n, mat; + for m in [1..10] do + for n in [1..10] do + mat := NewZeroMatrix(filter, ring, m, n); + od; + od; + end); + + PrintHeadline("ZeroMatrix( filt, R, m, n )"); + MyBench(function() + local m, n, mat; + for m in [1..10] do + for n in [1..10] do + mat := ZeroMatrix(filter, ring, m, n); + od; + od; + end); + + PrintHeadline("ZeroMatrix( m, n, M )"); + MyBench(function() + local m, n, mat; + for m in [1..10] do + for n in [1..10] do + mat := ZeroMatrix(m, n, example_mat); + od; + od; + end); + + PrintHeadline("NewIdentityMatrix"); + MyBench(function() + local n, mat; + for n in [1..100] do + mat := NewIdentityMatrix(filter, ring, n); + od; + end); + + PrintHeadline("IdentityMatrix( filt, R, n )"); + MyBench(function() + local n, mat; + for n in [1..100] do + mat := IdentityMatrix(filter, ring, n); + od; + end); + + PrintHeadline("IdentityMatrix( n, M )"); + MyBench(function() + local n, mat; + for n in [1..100] do + mat := IdentityMatrix(n, example_mat); + od; + end); + + # TODO: NewMatrix + # TODO: Matrix +end; + +RunMatTest := function(desc, ring) + Print("\n"); + PrintBoxed(Concatenation("Testing ", desc)); + TestCreatingMatrix(ring); +end; + +RunMatTest("GF(2)", GF(2)); +RunMatTest("Rationals", Rationals); + +RunMatObjTest := function(desc, filter, ring) + Print("\n"); + PrintBoxed(Concatenation("Testing ", desc)); + TestCreatingMatrixObj(filter, ring); +end; + +RunMatObjTest("GF(2) IsPlistMatrixRep", IsPlistMatrixRep, GF(2)); +RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers); +RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals); + +# TODO: other reps +# TODO: other compare with creating plist-of-plist diff --git a/benchmark/matobj/bench.g b/benchmark/matobj/bench.g new file mode 100644 index 00000000000..effcabeffd0 --- /dev/null +++ b/benchmark/matobj/bench.g @@ -0,0 +1,185 @@ +# Benchmark( func[, optrec] ) +# +# func - a function taking no arguments +# optrec - an optional record with various options +# +# Measures how long executing the given function "func" takes. +# In order to improve accuracy, it invokes the function repeatedly. +# Before each repetition, the garbage collector is run, and +# (unless turned off by an option) the random number generators +# are reset. +# At the end, it outputs the average, median, and std deviation. +# +# Example: +# gap> Benchmark(function() Factors(x^293-1); end); +# ................................................. +# Performed 49 iterations, taking 201 milliseconds. +# average: 4.1 +/- 0.11 (+/- 3%) +# median: 4.06396484375 +# rec( avg := 4.09581, counter := 49, median := 4.06396, std := 0.109638, total := 200.695, var := 0.0120205 ) +# +# +# The following options are currently implemented: +# +# minreps: the minimal number of repetitions; +# the function will be executed at least that often, +# unless some other condition (maxreps exceeded, maxtime exceeded) +# aborts the benchmark early. +# mintime: the minimal number of milliseconds that has to pass before +# benchmarking ends; +# benchmarking will not stop before this time has passed, +# unless some other condition (maxreps exceeded, maxtime exceeded) +# aborts the benchmark early. +# maxreps: the maximal number of repetitions; +# once this is reached, benchmarking stops immediately. +# maxtime: the maximal number of milliseconds before benchmarking ends; +# once this is reached, benchmarking stops immediately. +# showSummary: +# showProgress: +# resetRandom: whether to reset the random number generators before each repetition (default: true) +# +# +# TODO: allow passing a function that is executed before every test run. +# That function can reset other state, flush caches etc. +# +Benchmark := function(func, arg...) + local opt, getTime, timings, total, t, i, res; + + opt := rec( + minreps := 5, + maxreps := 1000, + silent := false, + resetRandom := true, + mintime := 200, + maxtime := infinity, + showProgress := true, + showSummary := true, + ); + + if Length(arg) = 1 and IsRecord(arg[1]) then + for i in RecNames(arg[1]) do + opt.(i) := arg[1].(i); + od; + elif Length(arg) <> 0 then + Error("Usage: Benchmark( func[, optrec] )"); + fi; + + # force mintime and maxtime to be floats + opt.mintime := Float(opt.mintime); + opt.maxtime := Float(opt.maxtime); + + # if available, use NanosecondsSinceEpoch + if IsBound(NanosecondsSinceEpoch) then + getTime := function() return NanosecondsSinceEpoch()/1000000.; end; + else + getTime := Runtime; + fi; + + timings := []; + total := 0.0; + i := 0; + # repeat at most opt.maxreps times, and at least opt.minreps + # times, resp. at least till opt.mintime milliseconds passed + # + # TODO: what we really should do is repeat until the variance + # is low enough (or until it stagnates) + while i < opt.maxreps and (opt.maxtime = infinity or total < opt.maxtime) and + (i < opt.minreps or total < opt.mintime) do + i := i + 1; + + if opt.resetRandom then + Reset(GlobalMersenneTwister); + Reset(GlobalRandomSource); + fi; + GASMAN("collect"); + + t := getTime(); + func(); + t := getTime() - t; + + total := total + t; + Add(timings, t); + if opt.showProgress then + #Print(".\c"); + Print(['\r', "|/-\\"[1+(i mod 4)],'\c']); + fi; + od; + if opt.showProgress then + #Print("\n"); + Print("\r \c\r"); + fi; + + Sort(timings); + + res := rec(); + #res.timings := timings; + res.total := total; + res.counter := i; + res.avg := Sum(timings) * 1.0 / res.counter; + res.var := Sum(timings, t -> (t-res.avg)^2) / res.counter; + res.std := Sqrt(res.var); + if IsOddInt(res.counter) then + res.median := timings[(res.counter+1)/2]; + else + res.median := (timings[(res.counter)/2] + timings[(res.counter+2)/2]) / 2.; + fi; + # TODO: discard outliers? + + if opt.showSummary then + Print("Performed ", res.counter, " iterations, taking ", Round(res.total), " milliseconds.\n"); + #Print("timings: ", timings, "\n"); + Print("average: ", Round(100*res.avg)/100, + " +/- ", Round(100*res.std)/100, + " (+/- ", Round(100*res.std/res.avg), "%)", + "\n"); + Print("median: ", res.median, "\n"); + fi; + + return res; +end; + +if false then +x:=X(Integers); +Benchmark(function() Factors(x^293-1); end); +Benchmark(function() Factors(x^293-1); end, rec(maxreps:=10)); +fi; + + +PrintBoxed := function(str) + local n, line; + n := Length(str) + 2; + line := Concatenation("+", ListWithIdenticalEntries(n,'-'), "+\n"); + Print(line); + Print("| ", str, " |\n"); + Print(line); +end; + +PrintHeadline := function(what); + Print(TextAttr.5, "Testing ", what, ":\n",TextAttr.reset); +end; + +MyBench := function(func) + local opt, res; + + opt := rec( + mintime:=300, + #maxtime:=2000, + maxreps:=200, + showSummary := false + ); + res := Benchmark(func, opt); + + Print(" ", + Int(Round(res.total / res.counter * 1000.0)), " µs per iteration; ", + Int(Round(res.counter * 1000.0 / res.total )), " iterations per second; ", + "(", res.counter, " iterations)", + "\n"); + +# Print(" Performed ", res.counter, " iterations, taking ", Round(res.total), " milliseconds; "); +# #Print("timings: ", timings, "\n"); +# # Print("average: ", Round(100*res.avg)/100, +# # " +/- ", Round(100*res.std)/100, +# # " (+/- ", Round(100*res.std/res.avg), "%)", +# # "\n"); +# Print(" median: ", res.median, "\n"); +end;