diff --git a/AGENTS.md b/AGENTS.md index 58df6d2..75da653 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -156,6 +156,12 @@ julia --project=. -e 'using Pkg; Pkg.instantiate()' # benchmarks (separate environment, needs CUDSS.jl for the cuDSS baseline) julia --project=bench bench/cudss_baseline.jl + +# cuDSS vs SparseDirectSolver.jl comparison, run by hand (one solver per process), +# then render bench/comparison/comparison.{md,png} +julia --project=bench bench/compare.jl --solver=cudss +julia --project=bench bench/compare.jl --solver=sds --backend=cuda +julia --project=bench/report bench/compare_report.jl ``` `SDS_TEST_GPU` and `SDS_TEST_ONLY` are implemented in `test/runtests.jl` (T01), diff --git a/README.md b/README.md index dacab36..bbdd8ac 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,19 @@ silently. * [`TASKS.md`](TASKS.md) — implementation tasks and their reports. * [`RESEARCH.md`](RESEARCH.md) — background and state of the art. * [`bench/README.md`](bench/README.md) — benchmark harness and cuDSS baselines. +* [`bench/comparison/comparison.md`](bench/comparison/comparison.md) — per-feature performance comparison with cuDSS. + +## Performance against cuDSS + +Time of SparseDirectSolver.jl divided by the time of cuDSS per planned +feature and phase, geometric mean over the benchmark matrices (below 1 is +faster). Features whose task is not done yet are marked pending and stay +empty. Per-matrix numbers are in +[`bench/comparison/comparison.md`](bench/comparison/comparison.md); the plot +is regenerated by hand with `bench/compare.jl` and `bench/compare_report.jl` +(see [`bench/README.md`](bench/README.md)). + +![SparseDirectSolver.jl vs cuDSS time ratio per feature](bench/comparison/comparison.png) ## Installation diff --git a/bench/Project.toml b/bench/Project.toml index e2cf862..921478f 100644 --- a/bench/Project.toml +++ b/bench/Project.toml @@ -1,16 +1,24 @@ [deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MatrixDepot = "b51810bb-c9f3-55da-ae3c-350fc1fbce05" +Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SparseDirectSolver = "dc8e0fd9-41f1-440b-9624-22817132f700" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +[sources] +SparseDirectSolver = {path = ".."} + [compat] +BenchmarkTools = "1" CUDA = "6" CUDSS = "0.8" DelimitedFiles = "1" MatrixDepot = "1" +Metis = "1" julia = "1.13" diff --git a/bench/README.md b/bench/README.md index 146c1be..0b4a47d 100644 --- a/bench/README.md +++ b/bench/README.md @@ -13,6 +13,9 @@ Baselines every later milestone is measured against (PLAN.md §5 M0, §7). The | `regimes.jl` | `factorize!` time on the generated matrices with regimes A+B+C (default), B+C (`subtree_budgets = []`) and C only (`factorization_alg = "algo2"`), with fronts per regime and launch counts; package environment: `julia --project=. bench/regimes.jl [--backend=cuda] [--T=Float64] [--only=lap2d_300,lap3d_40]` | | `report.jl` | prints the CSV files as Markdown tables | | `dump_madnlp_kkt.jl` | dumps MadNLP K2 and condensed KKT matrices of pglib-opf cases | +| `features.jl` | module `BenchFeatures`: the comparison features, one per planned capability in TASKS.md order (`cholesky_f64` … `mixed_precision`), with structure, element type, matrix selector and parameters; `task_status` reads the task's marker in TASKS.md | +| `compare.jl` | cuDSS vs SparseDirectSolver.jl per feature × matrix with BenchmarkTools; one solver per run (`--solver=cudss` or `--solver=sds`), results merged into `bench/comparison/.csv` | +| `compare_report.jl` | renders `bench/comparison/comparison.md` (overview + one table per feature) and `comparison.png` (SDS/cuDSS ratio per feature and phase); environment `bench/report/` (CairoMakie) | | `pivot_pairs.jl` | 2×2 pivot pairs of the `S` analysis (issue #66): `pivot_pairs` = `none`/`default`/`all` on the K2 dumps and the KKT generators, with nnz(L), zero/perturbed/2×2 pivots, max abs L and factor error of the CPU reference LDLᵀ; package environment: `julia --project=. bench/pivot_pairs.jl [--only=case118,...] [--generators=false]` | ## Commands @@ -38,6 +41,60 @@ julia --project=bench/kkt -e 'using Pkg; Pkg.add(["MadNLP", "ExaModels", "ExaMod julia --project=bench/kkt bench/dump_madnlp_kkt.jl pglib_opf_case118_ieee pglib_opf_case1354_pegase --iters=1,10,20 ``` +## cuDSS vs SparseDirectSolver.jl comparison + +`bench/comparison/` is committed (unlike `bench/results/`): the two CSVs, the +Markdown table and the plot are the record of where the package stands against +cuDSS. Rerun it by hand after a task lands: + +```bash +julia --project=bench -e 'using Pkg; Pkg.instantiate()' # once +julia --project=bench/report -e 'using Pkg; Pkg.instantiate()' # once + +julia --project=bench bench/compare.jl --solver=cudss # cuDSS side, all features +julia --project=bench bench/compare.jl --solver=sds --backend=cuda # SparseDirectSolver.jl side +julia --project=bench/report bench/compare_report.jl # comparison.md + comparison.png + +# rerun one feature after its task lands (other rows of the CSV are kept) +julia --project=bench bench/compare.jl --solver=sds --features=ldlt +``` + +* **Features.** Every capability planned in TASKS.md is a row of the overview + from the start. The SDS run skips a feature until its task is marked done + (`[x]`/`[!]`) in TASKS.md, so its cells stay blank; `--force` runs it anyway + and records the error. The gate is the task marker, not an error, because + some parameters (`hybrid_memory_mode`, `ir_n_steps`) are accepted and + ignored before their task. The cuDSS side runs every feature with a cuDSS + counterpart, so its column is filled before the SDS one. +* **Two processes.** CUDSS.jl and the package's CUDA extension define the same + `cholesky(::CuSparseMatrixCSR)` methods, so one run loads one solver. The SDS + run uses only the handle layer (`DirectSolver`, `setparam!`, `execute!`, + `getparam`) and loads Metis for the default AMD/ND ordering choice. The bench + environment gets SparseDirectSolver from `..` through `[sources]`. +* **Timing.** BenchmarkTools, `evals = 1`, 5 samples per phase (`--samples`). + The `setup` of each sample builds a fresh solver, runs the phases the timed + one depends on and, on a GPU, keeps the device busy for 0.2 s: otherwise the + GPU drops to a low-clock power state during the host-side setup and the timed + phase starts slow (lap2d_300 factorization varied between 6 and 19 ms; with + the spin it is a stable 5.9 ms, against 6.05 ms in the T04 baseline). The + report shows medians; the CSV also keeps the minima. Before the trials, one + run compiles and gives `info`, nnz(L) and the residual, and a second run is + timed; if its factorization takes longer than `--single-run-above` (5 s), + its times are recorded instead of a trial (`samples` = 1 in the CSV, listed + under the feature's table). This keeps slow rows, such as the T15 LDLᵀ on + the larger matrices, from costing twenty factorizations each. The CSV is + rewritten after every row, so an interrupted run keeps what it measured. +* **Synthetic inputs.** `ubatch8` builds 8 value sets on one pattern by scaling + the diagonal of member k by 1 + 0.01(k−1). `schur` takes the last + min(64, n/10) rows as the Schur block and times `solve_fwd_schur` as the + solve (no residual). `nubatch` batches all selected condensed dumps into one + row. The SDS calls for uniform batches assume `(n, nbatch)` right-hand sides + and the non-uniform batch assumes `BatchedDirectSolver` (PLAN §3); adjust + `compare.jl` when T17/T22 fix the API. +* **Adding a feature.** One `Feature(...)` entry in `features.jl` (task id, + structure, matrix selector, parameters); `compare.jl` handles the kinds + `:single`, `:ubatch`, `:nubatch` and `:schur`. + ## What is measured For each matrix and structure, after one warm-up run, five runs each of diff --git a/bench/compare.jl b/bench/compare.jl new file mode 100644 index 0000000..57e40a7 --- /dev/null +++ b/bench/compare.jl @@ -0,0 +1,362 @@ +# cuDSS vs SparseDirectSolver.jl: per-phase timings for every feature of +# `features.jl` on the harness matrices, measured with BenchmarkTools. One solver +# per process (CUDSS.jl and the CUDA extension define the same `cholesky` +# methods), each run merged into `bench/comparison/.csv`; +# `compare_report.jl` renders the side-by-side table and plot. +# +# julia --project=bench bench/compare.jl --solver=cudss [options] +# julia --project=bench bench/compare.jl --solver=sds [--backend=cuda|cpu] [options] +# +# Options: +# --features=a,b feature ids (default: all; see bench/features.jl) +# --only=m1,m2 matrix names (default: all harness matrices) +# --samples=5 BenchmarkTools samples per phase (after its warm-up sample) +# --seconds=60 time budget per phase; sampling stops at whichever limit comes first +# --single-run-above=5 if one factorization takes longer (seconds), record the +# times of a single run instead of a BenchmarkTools trial +# --no-suitesparse skip the MatrixDepot matrices +# --no-dumps skip the KKT dumps under bench/data/ +# --force run SDS features whose task is not done in TASKS.md (rows record the error) +# +# Each phase is timed on a fresh solver: the `setup` of the benchmark creates the +# solver and runs the phases it depends on, the timed expression runs the phase +# and synchronizes the device. On a GPU the setup ends by keeping the device busy +# for 0.2 s so that it is at full clock (see `spin_device`). A first run of all +# phases compiles and gives `info`, the statistics and the residual; when the +# factorization of a second run exceeds --single-run-above, the times of that +# run are recorded instead of a trial. + +using LinearAlgebra +using SparseArrays +using Random +using Dates +using BenchmarkTools +using DelimitedFiles + +include(joinpath(@__DIR__, "matrices.jl")) +include(joinpath(@__DIR__, "features.jl")) +using .BenchMatrices +using .BenchFeatures + +function parse_args(args) + o = Dict{String, String}("solver" => "", "backend" => "cuda", "features" => "", "only" => "", + "samples" => "5", "seconds" => "60", "single-run-above" => "5", "suitesparse" => "true", "dumps" => "true", + "force" => "false") + for a in args + if a in ("--no-suitesparse", "--no-dumps", "--force") + o[a == "--force" ? "force" : a[6:end]] = a == "--force" ? "true" : "false" + elseif (m = match(r"^--(solver|backend|features|only|samples|seconds|single-run-above)=(.*)$", a)) !== nothing + o[m[1]] = m[2] + else + error("unknown argument \"$a\"; see the header of bench/compare.jl") + end + end + o["solver"] in ("cudss", "sds") || error("--solver=cudss or --solver=sds is required") + o["backend"] in ("cuda", "cpu") || error("--backend must be cuda or cpu") + return o +end + +const OPTS = parse_args(ARGS) +const SOLVER = OPTS["solver"] +const ON_GPU = SOLVER == "cudss" || OPTS["backend"] == "cuda" + +if SOLVER == "cudss" + using CUDA, CUDA.cuSPARSE, CUDSS +else + using SparseDirectSolver, Metis # Metis: nested dissection in the default ordering + ON_GPU && using CUDA, CUDA.cuSPARSE +end + +dev(x) = ON_GPU ? CUDA.CuArray(x) : x +dev_csr(A) = ON_GPU ? CUDA.cuSPARSE.CuSparseMatrixCSR(A) : A +sync() = ON_GPU ? CUDA.synchronize() : nothing + +# The GPU drops to a low-clock power state while the host runs the (untimed) +# setup, and the timed phase then starts slow: on the RTX 4080, lap2d_300 +# factorization varied between 6 and 19 ms. Keeping the device busy for 0.2 s +# right before each timed phase gives a stable 5.9 ms (T04 baseline: 6.05 ms). +const SPIN_SECONDS = 0.2 +const SPIN_BUFFER = Ref{Any}(nothing) +function spin_device() + ON_GPU || return + SPIN_BUFFER[] === nothing && (SPIN_BUFFER[] = CUDA.zeros(Float32, 2^24)) + buf, t0 = SPIN_BUFFER[], time() + while time() - t0 < SPIN_SECONDS + buf .= sin.(buf) .+ 1f0 + CUDA.synchronize() + end +end + +# --- the two solvers behind one set of names (the parameter strings mirror cuDSS) --- + +# CUDSS.jl has no getter for CUDSS_DATA_FLOPS (an Int64 in cuDSS 0.8, see cudss_baseline.jl) +function cudss_flops(s) + ref, nw = Ref{Int64}(0), Ref{Csize_t}(0) + CUDSS.cudssDataGet(s.data.handle, s.data, CUDSS.CUDSS_DATA_FLOPS, ref, 8, nw) + return nw[] == 8 && ref[] > 0 ? ref[] : missing +end + +const API = if SOLVER == "cudss" + (solver = CUDSS.CudssSolver, batched = CUDSS.CudssBatchedSolver, set = CUDSS.cudss_set, + get = CUDSS.cudss_get, exec = CUDSS.cudss, flops = cudss_flops, + # a uniform batch passes x and b as descriptors with nbatch columns + ubatch_rhs = (X, nb) -> (D = CUDSS.CudssMatrix(eltype(X), size(X, 1); nbatch = nb); CUDSS.cudss_update(D, X); D), + version = string(CUDSS.version())) +else + (solver = SparseDirectSolver.DirectSolver, + batched = (a...) -> getproperty(SparseDirectSolver, :BatchedDirectSolver)(a...), # T22 + set = SparseDirectSolver.setparam!, get = SparseDirectSolver.getparam, + exec = (p, s, x, b) -> SparseDirectSolver.execute!(p, s, x, b; asynchronous = false), + flops = s -> SparseDirectSolver.getparam(s, "flops"), + ubatch_rhs = (X, nb) -> X, # assumed (n, nbatch) arrays; revisit when T17 lands + version = string(pkgversion(SparseDirectSolver))) +end + +side_params(f) = merge(f.params, SOLVER == "cudss" ? f.cudss_params : f.sds_params) + +relres(A, x, b) = norm(b - A * x) / norm(b) +colmax_relres(A, X, B) = maximum(relres(A, X[:, j], B[:, j]) for j in axes(B, 2)) + +# --- systems: `fresh()` builds a configured solver with its x and b, untimed --- + +""" + build_system(f, Ms) -> (; fresh, solve_phase, check) + +`fresh()` returns `(s, x, b)`: a new solver for feature `f` on the matrices `Ms` +(one matrix, or the batch members for `:nubatch`) with its device right-hand +side and solution. `check(x)` returns the relative residual on the host +(`missing` for the Schur feature). +""" +function build_system(f::Feature, Ms) + T, view = f.T, f.structure == "G" ? 'F' : 'L' + stored(A) = f.structure == "G" ? A : tril(A) + Random.seed!(666) + if f.kind == :nubatch + As = [SparseMatrixCSC{T, Int}(M.A) for M in Ms] + Ads = [dev_csr(stored(A)) for A in As] + bs = [rand(T, size(A, 1)) for A in As] + bds = dev.(bs) + fresh = () -> (s = API.batched(Ads, f.structure, view); configure!(s, f); (s, similar.(bds), bds)) + check = xs -> maximum(relres(As[k], Array(xs[k]), bs[k]) for k in eachindex(As)) + return (; fresh, solve_phase = "solve", check) + end + A = SparseMatrixCSC{T, Int}(only(Ms).A) + n = size(A, 1) + if f.kind == :ubatch + # nbatch value sets on one pattern: member k scales the diagonal by 1 + 0.01(k-1) (stays SPD) + Lt = sparse(transpose(stored(A))) # CSC of the transpose = CSR arrays of the stored triangle + ondiag = [Lt.rowval[p] == j for j in 1:n for p in nzrange(Lt, j)] + scale(k) = 1 .+ T(0.01) * (k - 1) .* ondiag + nzval = reduce(hcat, Lt.nzval .* scale(k) for k in 1:f.nbatch) + rowptr, colval, nzd = dev(Cint.(Lt.colptr)), dev(Cint.(Lt.rowval)), dev(nzval) + B = rand(T, n, f.nbatch) + Bd = dev(B) + fresh = () -> begin + s = API.solver(rowptr, colval, nzd, f.structure, view) + API.set(s, "ubatch_size", f.nbatch) + configure!(s, f) + Xd = similar(Bd) + (s, API.ubatch_rhs(Xd, f.nbatch), API.ubatch_rhs(Bd, f.nbatch), Xd) + end + Ak(k) = A + Diagonal(T(0.01) * (k - 1) .* diag(A)) + check = X -> maximum(relres(Ak(k), Array(X)[:, k], B[:, k]) for k in 1:f.nbatch) + return (; fresh, solve_phase = "solve", check) + end + Ad = dev_csr(stored(A)) + B = f.nrhs == 1 ? rand(T, n) : rand(T, n, f.nrhs) + Bd = dev(B) + fresh = () -> begin + s = API.solver(Ad, f.structure, view) + if f.kind == :schur # Schur block: the last min(64, n ÷ 10) rows and columns + API.set(s, "user_schur_indices", Cint[i > n - min(64, n ÷ 10) for i in 1:n]) + end + configure!(s, f) + (s, similar(Bd), Bd) + end + check = f.kind == :schur ? (X -> missing) : (X -> colmax_relres(A, reshape(Array(X), n, :), reshape(B, n, :))) + return (; fresh, solve_phase = f.kind == :schur ? "solve_fwd_schur" : "solve", check) +end + +configure!(s, f) = foreach(((k, v),) -> API.set(s, k, v), side_params(f)) + +# the solution array `check` reads: the plain device array (index 4) for a uniform batch +solution(st) = length(st) == 4 ? st[4] : st[2] + +# --- timing ------------------------------------------------------------------ + +const PHASES = ("analysis", "factorization", "refactorization", "solve") +const BEFORE = Dict("analysis" => (), "factorization" => ("analysis",), + "refactorization" => ("analysis", "factorization"), "solve" => ("analysis", "factorization")) + +phase_name(sys, p) = p == "solve" ? sys.solve_phase : p +run_phase(sys, st, p) = API.exec(phase_name(sys, p), st[1], st[2], st[3]) + +""" + time_phase(sys, phase; samples, seconds) -> (median_s, min_s) + +BenchmarkTools trial of one phase; the setup builds a fresh solver and runs the +phases `phase` depends on. +""" +function time_phase(sys, phase; samples, seconds) + prep = () -> (st = sys.fresh(); foreach(p -> run_phase(sys, st, p), BEFORE[phase]); sync(); spin_device(); st) + core = st -> (run_phase(sys, st, phase); sync()) + b = @benchmarkable $core(st) setup = (st = $prep()) evals = 1 + t = run(b; samples, seconds, gcsample = true) + return median(t).time / 1e9, minimum(t).time / 1e9 +end + +function stat(f, s) + try + f(s) + catch + missing + end +end + +""" + measure(sys; samples, seconds, single_run_above) -> NamedTuple + +A first run of all four phases compiles and gives `info`, the statistics and +the residual. A second run is timed phase by phase; if its factorization took +longer than `single_run_above` seconds, its times are recorded (`samples = 1`), +otherwise each phase gets a BenchmarkTools trial (median and minimum). +""" +function measure(sys; samples, seconds, single_run_above) + st = sys.fresh() + foreach(p -> run_phase(sys, st, p), PHASES) + sync() + info = API.get(st[1], "info") + info == 0 || error("info = $info after the factorization") + stats = (relres = sys.check(solution(st)), lu_nnz = stat(s -> API.get(s, "lu_nnz"), st[1]), + flops = stat(API.flops, st[1]), nsuperpanels = stat(s -> API.get(s, "nsuperpanels"), st[1])) + st = sys.fresh() + once = Dict{String, Float64}() + for p in PHASES + p == "analysis" || spin_device() + t0 = time_ns() + run_phase(sys, st, p) + sync() + once[p] = (time_ns() - t0) / 1e9 + end + single = once["factorization"] > single_run_above + times = single ? Dict(p => (once[p], once[p]) for p in PHASES) : + Dict(p => time_phase(sys, p; samples, seconds) for p in PHASES) + return (; times, samples = single ? 1 : samples, stats...) +end + +# --- CSV --------------------------------------------------------------------- + +const COLUMNS = ["solver", "feature", "task", "matrix", "structure", "n", "nnz", "T", "nrhs", "nbatch", + "analysis_s", "factorization_s", "refactorization_s", "solve_s", + "analysis_min_s", "factorization_min_s", "refactorization_min_s", "solve_min_s", + "lu_nnz", "flops", "nsuperpanels", "relres", "samples", "status", "device", "version", "git_sha", "date"] + +cell(x) = x === missing || x === nothing ? "" : x isa AbstractFloat ? repr(Float64(x)) : string(x) +clean(msg) = first(strip(replace(msg, r"[,\"\s]+" => " ")), 200) + +function device_name() + ON_GPU && return replace(CUDA.name(CUDA.device()), "," => " ") + return "CPU (KernelAbstractions, $(Threads.nthreads()) threads)" +end + +function git_sha() + try + sha = readchomp(`git -C $(@__DIR__) rev-parse --short HEAD`) + dirty = !isempty(readchomp(`git -C $(@__DIR__) status --porcelain --untracked-files=no`)) + return dirty ? sha * "+dirty" : sha + catch + return "" + end +end + +function csv_row(f, name, Ms, result, meta) + n, nz = sum(M -> size(M.A, 1), Ms), sum(M -> nnz(M.A), Ms) + head = [SOLVER, f.id, f.task, name, f.structure, string(n), string(nz), string(f.T), string(f.nrhs), + string(f.kind == :nubatch ? length(Ms) : f.nbatch)] + if result isa Exception + body = vcat(fill("", 13), clean(sprint(showerror, result))) + else + body = vcat([cell(result.times[p][1]) for p in PHASES], [cell(result.times[p][2]) for p in PHASES], + [cell(x) for x in (result.lu_nnz, result.flops, result.nsuperpanels, result.relres, result.samples)], "ok") + end + return vcat(head, body, meta) +end + +""" + merge_csv(path, rows) + +Writes `rows` to `path`, keeping the rows of an existing file whose +(feature, matrix) is not among `rows`; sorted by feature order, then matrix. +""" +function merge_csv(path, rows) + old = Vector{Vector{String}}() + if isfile(path) + data, header = readdlm(path, ',', String; header = true, quotes = false) + if vec(header) == COLUMNS + rerun = Set((r[2], r[4]) for r in rows) + old = [data[i, :] for i in axes(data, 1) if (data[i, 2], data[i, 4]) ∉ rerun] + else + @warn "$path has other columns; replacing it" + end + end + order = Dict(f.id => i for (i, f) in enumerate(COMPARE_FEATURES)) + all_rows = sort!(vcat(old, rows); by = r -> (get(order, r[2], typemax(Int)), r[4])) + mkpath(dirname(path)) + open(path, "w") do io + writedlm(io, [permutedims(COLUMNS); permutedims(reduce(hcat, all_rows))], ',') + end +end + +# --- driver ------------------------------------------------------------------ + +function main() + ON_GPU && !CUDA.functional() && error("CUDA is not functional on this machine") + samples, seconds = parse(Int, OPTS["samples"]), parse(Float64, OPTS["seconds"]) + single_run_above = parse(Float64, OPTS["single-run-above"]) + ids = filter(!isempty, split(OPTS["features"], ',')) + features = isempty(ids) ? COMPARE_FEATURES : feature.(ids) + mats = bench_matrices(; suitesparse = OPTS["suitesparse"] == "true", dumps = OPTS["dumps"] == "true") + only_names = filter(!isempty, split(OPTS["only"], ',')) + isempty(only_names) || filter!(M -> M.name in only_names, mats) + meta = [device_name(), API.version, git_sha(), string(today())] + out = joinpath(@__DIR__, "comparison", "$SOLVER.csv") + println(SOLVER, " ", API.version, " on ", meta[1], ", samples = ", samples) + + rows = Vector{Vector{String}}() + for f in features + if SOLVER == "cudss" && !f.cudss_supported + println(rpad(f.id, 18), "no cuDSS counterpart, skipped") + continue + elseif SOLVER == "sds" && !feature_implemented(f) && OPTS["force"] != "true" + println(rpad(f.id, 18), "pending ", f.task, ", skipped") + continue + end + selected = filter(M -> f.structure in M.structures && f.matrices(M), mats) + groups = f.kind == :nubatch ? (isempty(selected) ? [] : ["batch_of_$(length(selected))" => selected]) : + [M.name => [M] for M in selected] + for (name, Ms) in groups + print(rpad(f.id, 18), rpad(name, 42)) + flush(stdout) + result = try + Base.invokelatest(measure, build_system(f, Ms); samples, seconds, single_run_above) + catch err + err isa InterruptException && rethrow() + err + end + if result isa Exception + println("FAILED: ", first(sprint(showerror, result), 160)) + else + println(join(("$p $(round(result.times[p][1] * 1e3; sigdigits = 3)) ms" for p in PHASES), ", "), + ", relres ", result.relres === missing ? "-" : round(result.relres; sigdigits = 2), + result.samples == 1 ? " (single run)" : "") + end + push!(rows, csv_row(f, name, Ms, result, meta)) + merge_csv(out, rows) # after every row, so an interrupted run keeps what it measured + end + end + println(isempty(rows) ? "nothing to run" : "wrote $out") +end + +if abspath(PROGRAM_FILE) == @__FILE__ + main() +end diff --git a/bench/compare_report.jl b/bench/compare_report.jl new file mode 100644 index 0000000..aee1fd8 --- /dev/null +++ b/bench/compare_report.jl @@ -0,0 +1,190 @@ +# Renders the cuDSS vs SparseDirectSolver.jl comparison from the CSVs written by +# `compare.jl`: `bench/comparison/comparison.md` (overview of every planned +# feature, then one table per feature) and `bench/comparison/comparison.png` +# (geometric-mean time ratio SDS/cuDSS per feature and phase). +# +# julia --project=bench/report bench/compare_report.jl [--no-plot] +# +# Features whose task is not done in TASKS.md are listed with blank SDS cells. + +module BenchCompareReport + +using DelimitedFiles +using Printf + +include(joinpath(@__DIR__, "features.jl")) +using .BenchFeatures + +export read_rows, ratio_summary, render_markdown, PHASES + +const PHASES = ("analysis", "factorization", "refactorization", "solve") +const DIR = joinpath(@__DIR__, "comparison") + +""" + read_rows(path) -> Vector{Dict{String,String}} + +Rows of a CSV written by `compare.jl`, keyed by column name; empty if the file does not exist. +""" +function read_rows(path::AbstractString) + isfile(path) || return Dict{String, String}[] + data, header = readdlm(path, ',', String; header = true, quotes = false) + return [Dict(zip(vec(header), data[i, :])) for i in axes(data, 1)] +end + +ok(r) = r !== nothing && r["status"] == "ok" +seconds(r, p) = parse(Float64, r["$(p)_s"]) +find_row(rows, f, m) = (i = findfirst(r -> r["feature"] == f.id && r["matrix"] == m, rows); i === nothing ? nothing : rows[i]) + +""" + matrices_of(f, cudss_rows, sds_rows) -> Vector{String} + +Matrix names with a row for feature `f` on either side, cuDSS order first. +""" +matrices_of(f, cudss_rows, sds_rows) = + unique!([r["matrix"] for r in vcat(cudss_rows, sds_rows) if r["feature"] == f.id]) + +""" + ratio_summary(f, cudss_rows, sds_rows) -> (ratios, count) + +Geometric mean of the SDS/cuDSS time ratio per phase over the matrices where +both rows are `ok` (`nothing` per phase when there is none), and their number. +""" +function ratio_summary(f, cudss_rows, sds_rows) + pairs = [(find_row(cudss_rows, f, m), find_row(sds_rows, f, m)) for m in matrices_of(f, cudss_rows, sds_rows)] + filter!(((c, s),) -> ok(c) && ok(s), pairs) + isempty(pairs) && return Dict{String, Union{Nothing, Float64}}(p => nothing for p in PHASES), 0 + gm(p) = exp(sum(log(seconds(s, p) / seconds(c, p)) for (c, s) in pairs) / length(pairs)) + return Dict{String, Union{Nothing, Float64}}(p => gm(p) for p in PHASES), length(pairs) +end + +fmt_ms(r, p) = ok(r) ? @sprintf("%.3g", seconds(r, p) * 1e3) : r === nothing ? "" : "fail" +fmt_ratio(x) = x === nothing ? "" : @sprintf("%.2f×", x) +fmt_ratio(c, s, p) = ok(c) && ok(s) ? fmt_ratio(seconds(s, p) / seconds(c, p)) : "" +fmt_field(r, k) = ok(r) && !isempty(r[k]) ? @sprintf("%.3g", parse(Float64, r[k])) : "" + +state(f, implemented) = implemented ? "done" : "pending" + +""" + render_markdown(io, cudss_rows, sds_rows; features = COMPARE_FEATURES, implemented = feature_implemented) + +Writes the comparison as Markdown: an overview with one line per feature, then +per feature a table with cuDSS ms, SDS ms and the ratio for each phase, nnz(L) +and the relative residual of both solvers. Cells without a row stay blank, a +failed row shows `fail` and its message below the table. +""" +function render_markdown(io::IO, cudss_rows, sds_rows; features = COMPARE_FEATURES, + implemented = feature_implemented, plot = true) + println(io, "# cuDSS vs SparseDirectSolver.jl\n") + println(io, "Generated by `bench/compare_report.jl` from `bench/comparison/{cudss,sds}.csv` ", + "(`bench/compare.jl`). Times are BenchmarkTools medians per phase on a fresh solver; ", + "the ratio is SDS time / cuDSS time, so below 1 means SparseDirectSolver.jl is faster. ", + "Features whose task is not done in TASKS.md have blank SDS cells.\n") + plot && println(io, "![SDS/cuDSS time ratio per feature](comparison.png)\n") + println(io, "## Overview\n") + println(io, "Geometric mean of the SDS/cuDSS ratio over the matrices both solvers ran.\n") + println(io, "| feature | task | status | matrices | analysis | factorization | refactorization | solve |") + println(io, "| --- | --- | --- | --- | --- | --- | --- | --- |") + for f in features + ratios, count = ratio_summary(f, cudss_rows, sds_rows) + println(io, "| ", f.title, " | ", f.task, " | ", state(f, implemented(f)), " | ", count == 0 ? "" : count, + " | ", join((fmt_ratio(ratios[p]) for p in PHASES), " | "), " |") + end + println(io) + for f in features + println(io, "## ", f.title, "\n") + println(io, "`", f.id, "`, ", f.task, " (", state(f, implemented(f)), "), structure `", f.structure, "`, ", + f.T, ", nrhs = ", f.nrhs, f.kind == :ubatch ? ", uniform batch of $(f.nbatch)" : "", + f.cudss_supported ? "" : ", no cuDSS counterpart", ".\n") + names = matrices_of(f, cudss_rows, sds_rows) + if isempty(names) + println(io, "Not run yet.\n") + continue + end + print(io, "| matrix | n |") + foreach(p -> print(io, " $p cuDSS ms | SDS ms | ratio |"), PHASES) + println(io, " nnz(L) cuDSS | SDS | relres cuDSS | SDS |") + println(io, "|", repeat(" --- |", 2 + 3 * length(PHASES) + 4)) + failures, single = String[], String[] + for m in names + c, s = find_row(cudss_rows, f, m), find_row(sds_rows, f, m) + n = c !== nothing ? c["n"] : s["n"] + print(io, "| ", m, " | ", n, " |") + foreach(p -> print(io, " ", fmt_ms(c, p), " | ", fmt_ms(s, p), " | ", fmt_ratio(c, s, p), " |"), PHASES) + println(io, " ", fmt_field(c, "lu_nnz"), " | ", fmt_field(s, "lu_nnz"), " | ", fmt_field(c, "relres"), + " | ", fmt_field(s, "relres"), " |") + for (who, r) in (("cuDSS", c), ("SDS", s)) + r !== nothing && !ok(r) && push!(failures, "$who on $m: $(r["status"])") + ok(r) && get(r, "samples", "") == "1" && push!(single, "$who on $m") + end + end + println(io) + isempty(failures) || (foreach(x -> println(io, "* ", x), failures); println(io)) + isempty(single) || println(io, "Single run instead of a BenchmarkTools trial (factorization above the ", + "`--single-run-above` limit): ", join(single, ", "), ".\n") + end + println(io, "## Runs\n") + for (who, rows) in (("cuDSS", cudss_rows), ("SparseDirectSolver.jl", sds_rows)) + isempty(rows) && (println(io, "* ", who, ": no results."); continue) + runs = unique((r["device"], r["version"], r["git_sha"], r["date"]) for r in rows) + for (d, v, g, t) in runs + println(io, "* ", who, " ", v, " on ", d, ", repository ", isempty(g) ? "?" : g, ", ", t, ".") + end + end +end + +end # module BenchCompareReport + +using .BenchCompareReport + +const MAKE_PLOT = abspath(PROGRAM_FILE) == (@__FILE__) && !("--no-plot" in ARGS) +if MAKE_PLOT + using CairoMakie +end + +""" + write_plot(path, cudss_rows, sds_rows) + +Grouped bars of the geometric-mean SDS/cuDSS ratio per feature and phase, log +scale, bars drawn from 1; features without results keep an empty slot. +""" +function write_plot(path, cudss_rows, sds_rows) + F = BenchCompareReport.BenchFeatures + feats = F.COMPARE_FEATURES + xs, ys, groups = Int[], Float64[], Int[] + for (i, f) in enumerate(feats), (j, p) in enumerate(PHASES) + r = first(ratio_summary(f, cudss_rows, sds_rows))[p] + r === nothing || (push!(xs, i); push!(ys, r); push!(groups, j)) + end + labels = [F.feature_implemented(f) ? "$(f.id) ($(f.task))" : "$(f.id) ($(f.task), pending)" for f in feats] + fig = Figure(size = (1200, 560)) + ax = Axis(fig[1, 1]; yscale = log10, xticks = (1:length(feats), labels), xticklabelrotation = π / 4, + ylabel = "SDS time / cuDSS time (geometric mean)", + yticks = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100], + ytickformat = vs -> ["$(round(v; sigdigits = 2))×" for v in vs], + title = "SparseDirectSolver.jl vs cuDSS: below 1 is faster") + colors = Makie.wong_colors()[1:length(PHASES)] + isempty(xs) || barplot!(ax, xs, ys; dodge = groups, n_dodge = length(PHASES), width = 0.8, + color = colors[groups], fillto = 1.0) + hlines!(ax, [1.0]; color = :black, linestyle = :dash) + xlims!(ax, 0.5, length(feats) + 0.5) + lo, hi = isempty(ys) ? (1.0, 1.0) : extrema(ys) + ylims!(ax, min(lo, 1.0) / 1.5, max(hi, 1.0) * 1.5) + Legend(fig[1, 2], [PolyElement(color = c) for c in colors], collect(PHASES), "phase") + save(path, fig) + return path +end + +function main() + dir = BenchCompareReport.DIR + cudss_rows = read_rows(joinpath(dir, "cudss.csv")) + sds_rows = read_rows(joinpath(dir, "sds.csv")) + md = joinpath(dir, "comparison.md") + plot = MAKE_PLOT || isfile(joinpath(dir, "comparison.png")) + open(io -> render_markdown(io, cudss_rows, sds_rows; plot), md, "w") + println("wrote ", md) + MAKE_PLOT && println("wrote ", Base.invokelatest(write_plot, joinpath(dir, "comparison.png"), cudss_rows, sds_rows)) +end + +if abspath(PROGRAM_FILE) == @__FILE__ + main() +end diff --git a/bench/comparison/comparison.md b/bench/comparison/comparison.md new file mode 100644 index 0000000..d4f41e0 --- /dev/null +++ b/bench/comparison/comparison.md @@ -0,0 +1,222 @@ +# cuDSS vs SparseDirectSolver.jl + +Generated by `bench/compare_report.jl` from `bench/comparison/{cudss,sds}.csv` (`bench/compare.jl`). Times are BenchmarkTools medians per phase on a fresh solver; the ratio is SDS time / cuDSS time, so below 1 means SparseDirectSolver.jl is faster. Features whose task is not done in TASKS.md have blank SDS cells. + +![SDS/cuDSS time ratio per feature](comparison.png) + +## Overview + +Geometric mean of the SDS/cuDSS ratio over the matrices both solvers ran. + +| feature | task | status | matrices | analysis | factorization | refactorization | solve | +| --- | --- | --- | --- | --- | --- | --- | --- | +| Cholesky, Float64 | T13 | done | 14 | 0.60× | 5.64× | 9.06× | 8.93× | +| Cholesky, 16 right-hand sides | T12 | done | 14 | 0.60× | 6.06× | 9.52× | 7.28× | +| LDLᵀ, static pivoting | T15 | done | 23 | 1.12× | 20.44× | 29.78× | 13.42× | +| LDLᵀ + 2 refinement steps, K2 dumps | T16 | done | 9 | 2.67× | 23.40× | 35.99× | 33.25× | +| Uniform batch of 8, Cholesky | T17 | pending | | | | | | +| LU, unsymmetric | T19 | pending | | | | | | +| Schur complement, Cholesky | T20 | pending | | | | | | +| LDLᵀ + matching (algo5), K2 dumps | T21 | pending | | | | | | +| Non-uniform batch, condensed dumps | T22 | pending | | | | | | +| Partitioned-inverse solve (SDS algo1, cuDSS default) | T25 | pending | | | | | | +| Hybrid memory mode | T26 | pending | | | | | | +| Float32 factors, Float64 refinement | T27 | pending | | | | | | + +## Cholesky, Float64 + +`cholesky_f64`, T13 (done), structure `SPD`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Boeing/bcsstk38 | 8032 | 35.1 | 55 | 1.57× | 3.52 | 23.6 | 6.69× | 2.3 | 23.5 | 10.26× | 0.462 | 1.88 | 4.07× | 7.99e+05 | 8.05e+05 | 2.15e-10 | 1.05e-10 | +| GHS_psdef/apache2 | 715176 | 4.28e+03 | 6.08e+03 | 1.42× | 449 | 1.03e+03 | 2.30× | 421 | 1.02e+03 | 2.43× | 6.62 | 76.7 | 11.58× | 1.45e+08 | 1.29e+08 | 1.8e-10 | 1.58e-10 | +| HB/bcsstk17 | 10974 | 43.2 | 65.5 | 1.52× | 3.9 | 29.6 | 7.58× | 2.45 | 29.6 | 12.07× | 0.5 | 3.49 | 6.98× | 1.08e+06 | 1.04e+06 | 4.02e-11 | 5.05e-11 | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 13 | 4.46 | 0.34× | 0.992 | 3.87 | 3.90× | 0.438 | 3.88 | 8.86× | 0.256 | 2.72 | 10.63× | 1.52e+04 | 1.16e+04 | 7.26e-05 | 0.00015 | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 12.3 | 4.78 | 0.39× | 1.02 | 3.64 | 3.55× | 0.53 | 3.67 | 6.93× | 0.261 | 2.09 | 8.02× | 1.52e+04 | 1.16e+04 | 1.4e-05 | 1e-05 | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 12.8 | 4.77 | 0.37× | 1.06 | 3.66 | 3.44× | 0.351 | 3.77 | 10.73× | 0.257 | 2.07 | 8.08× | 1.52e+04 | 1.16e+04 | 0.293 | 0.0977 | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 54.2 | 50 | 0.92× | 1.35 | 39.9 | 29.45× | 0.585 | 39.9 | 68.17× | 0.269 | 19.7 | 73.12× | 1.55e+05 | 1.21e+05 | 0.000316 | 0.000282 | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 55.4 | 48.7 | 0.88× | 1.4 | 38.4 | 27.50× | 0.584 | 38.3 | 65.66× | 0.375 | 19.7 | 52.44× | 1.55e+05 | 1.21e+05 | 0.000142 | 0.00014 | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 55.4 | 49 | 0.88× | 1.39 | 38.3 | 27.48× | 0.685 | 38.4 | 56.03× | 0.387 | 19.7 | 50.79× | 1.55e+05 | 1.21e+05 | 7.94e-05 | 7.41e-05 | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 6.82 | 0.965 | 0.14× | 0.216 | 0.526 | 2.44× | 0.225 | 0.555 | 2.47× | 0.187 | 0.402 | 2.16× | 1.27e+03 | 1.03e+03 | 4.09e-07 | 1.65e-06 | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 6.77 | 1.55 | 0.23× | 0.221 | 0.565 | 2.56× | 0.212 | 0.54 | 2.55× | 0.195 | 0.392 | 2.01× | 1.27e+03 | 1.03e+03 | 0.000109 | 0.000157 | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 6.89 | 0.937 | 0.14× | 0.242 | 0.49 | 2.03× | 0.28 | 0.539 | 1.93× | 0.214 | 0.379 | 1.78× | 1.27e+03 | 1.03e+03 | 1.2e-05 | 1.67e-05 | +| lap2d_300 | 90000 | 281 | 371 | 1.32× | 6.84 | 36.4 | 5.32× | 3.84 | 36.3 | 9.45× | 0.852 | 4.1 | 4.82× | 2.43e+06 | 2.47e+06 | 1.84e-12 | 1.78e-12 | +| lap3d_40 | 64000 | 340 | 398 | 1.17× | 55.8 | 223 | 4.00× | 50.6 | 223 | 4.42× | 1.35 | 17 | 12.59× | 1.75e+07 | 1.44e+07 | 8.29e-14 | 7.48e-14 | + +## Cholesky, 16 right-hand sides + +`cholesky_nrhs16`, T12 (done), structure `SPD`, Float64, nrhs = 16. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Boeing/bcsstk38 | 8032 | 35.3 | 54 | 1.53× | 3.55 | 23.6 | 6.64× | 2.29 | 23.6 | 10.29× | 0.706 | 3.1 | 4.39× | 7.99e+05 | 8.05e+05 | 6.7e-10 | 1.66e-10 | +| GHS_psdef/apache2 | 715176 | 4.3e+03 | 6.23e+03 | 1.45× | 447 | 1.03e+03 | 2.30× | 417 | 1.02e+03 | 2.45× | 27.6 | 256 | 9.27× | 1.45e+08 | 1.29e+08 | 1.83e-10 | 1.6e-10 | +| HB/bcsstk17 | 10974 | 40.8 | 66.2 | 1.62× | 3.8 | 29.5 | 7.76× | 2.42 | 29.6 | 12.23× | 0.758 | 6.56 | 8.66× | 1.08e+06 | 1.04e+06 | 5.13e-11 | 5.92e-11 | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 11.8 | 4.7 | 0.40× | 0.911 | 3.87 | 4.25× | 0.341 | 3.88 | 11.36× | 0.375 | 2.18 | 5.82× | 1.52e+04 | 1.16e+04 | 6.7e-05 | 0.00015 | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 11.9 | 4.56 | 0.38× | 0.882 | 4.45 | 5.04× | 0.406 | 3.64 | 8.96× | 0.346 | 2.13 | 6.17× | 1.52e+04 | 1.16e+04 | 1.52e-05 | 1.1e-05 | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 12.2 | 4.74 | 0.39× | 0.889 | 3.7 | 4.16× | 0.359 | 4.01 | 11.17× | 0.26 | 2.05 | 7.87× | 1.52e+04 | 1.16e+04 | 0.492 | 0.318 | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 51.9 | 49.6 | 0.96× | 1.37 | 39.6 | 28.85× | 0.581 | 39.6 | 68.22× | 0.487 | 19.4 | 39.75× | 1.55e+05 | 1.21e+05 | 0.000394 | 0.000393 | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 52.9 | 49.7 | 0.94× | 1.5 | 38.4 | 25.64× | 0.614 | 38.2 | 62.24× | 0.457 | 19.3 | 42.25× | 1.55e+05 | 1.21e+05 | 0.000137 | 0.000144 | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 53.3 | 49.6 | 0.93× | 1.34 | 38.2 | 28.61× | 0.701 | 38.1 | 54.36× | 0.461 | 19.4 | 42.03× | 1.55e+05 | 1.21e+05 | 9.79e-05 | 9.67e-05 | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 7.25 | 0.974 | 0.13× | 0.199 | 0.555 | 2.79× | 0.24 | 0.543 | 2.26× | 0.221 | 0.449 | 2.03× | 1.27e+03 | 1.03e+03 | 6.35e-07 | 2.71e-06 | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 6.76 | 1.06 | 0.16× | 0.218 | 0.511 | 2.35× | 0.212 | 0.504 | 2.38× | 0.365 | 0.486 | 1.33× | 1.27e+03 | 1.03e+03 | 0.000179 | 0.000454 | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 6.84 | 0.941 | 0.14× | 0.24 | 0.521 | 2.17× | 0.222 | 0.543 | 2.45× | 0.261 | 0.446 | 1.71× | 1.27e+03 | 1.03e+03 | 3.34e-05 | 3.71e-05 | +| lap2d_300 | 90000 | 271 | 334 | 1.23× | 5.71 | 36.4 | 6.37× | 3.8 | 36.4 | 9.57× | 2.3 | 9.14 | 3.97× | 2.43e+06 | 2.47e+06 | 1.85e-12 | 1.8e-12 | +| lap3d_40 | 64000 | 329 | 409 | 1.24× | 50.5 | 223 | 4.41× | 45.7 | 223 | 4.88× | 5.58 | 50.5 | 9.05× | 1.75e+07 | 1.44e+07 | 8.99e-14 | 8.45e-14 | + +## LDLᵀ, static pivoting + +`ldlt`, T15 (done), structure `S`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Boeing/bcsstk38 | 8032 | 35.5 | 61.1 | 1.72× | 4.55 | 129 | 28.37× | 3.31 | 129 | 38.95× | 0.476 | 2.82 | 5.92× | 7.99e+05 | 8.05e+05 | 6.5e-11 | 1.25e-10 | +| GHS_psdef/apache2 | 715176 | 4.45e+03 | 6.97e+03 | 1.57× | 518 | 9.07e+04 | 175.14× | 489 | 9.12e+04 | 186.36× | 6.8 | 89.1 | 13.10× | 1.45e+08 | 1.29e+08 | 1.58e-10 | 1.63e-10 | +| HB/bcsstk17 | 10974 | 42.2 | 72.7 | 1.72× | 5.45 | 198 | 36.39× | 3.37 | 198 | 58.76× | 0.5 | 3.8 | 7.59× | 1.08e+06 | 1.04e+06 | 3.87e-11 | 3.71e-11 | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 12.9 | 5.04 | 0.39× | 0.905 | 5.03 | 5.56× | 0.39 | 5.03 | 12.89× | 0.383 | 2.61 | 6.82× | 1.52e+04 | 1.16e+04 | 2.99e-05 | 6.97e-05 | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 12 | 5.12 | 0.43× | 0.921 | 4.99 | 5.41× | 0.349 | 4.89 | 14.01× | 0.249 | 2.38 | 9.54× | 1.52e+04 | 1.16e+04 | 9.52e-06 | 9.74e-06 | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 12.9 | 5.04 | 0.39× | 0.899 | 5.04 | 5.61× | 0.351 | 5.03 | 14.31× | 0.282 | 2.38 | 8.44× | 1.52e+04 | 1.16e+04 | 0.108 | 0.0779 | +| kkt_pglib_opf_case118_ieee_k2_1 | 3150 | 16.2 | 54.2 | 3.34× | 0.845 | 13.8 | 16.31× | 0.363 | 13.8 | 38.08× | 0.229 | 7.73 | 33.81× | 2.02e+04 | 2.1e+04 | 2.4 | 0.237 | +| kkt_pglib_opf_case118_ieee_k2_10 | 3150 | 16.2 | 54.1 | 3.34× | 0.868 | 15 | 17.26× | 0.354 | 13.3 | 37.67× | 0.284 | 7.69 | 27.05× | 2.02e+04 | 2.05e+04 | 10.1 | 0.0106 | +| kkt_pglib_opf_case118_ieee_k2_20 | 3150 | 16.2 | 53.1 | 3.28× | 0.83 | 13.6 | 16.32× | 0.4 | 13.6 | 34.02× | 0.272 | 7.68 | 28.25× | 2.02e+04 | 2.05e+04 | 6.03 | 0.027 | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 53.3 | 52.1 | 0.98× | 1.39 | 56.3 | 40.63× | 0.684 | 56.3 | 82.22× | 0.355 | 22.6 | 63.57× | 1.55e+05 | 1.21e+05 | 0.000296 | 0.000322 | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 52.4 | 52 | 0.99× | 1.39 | 55.7 | 40.01× | 0.643 | 55.7 | 86.68× | 0.279 | 22.6 | 80.94× | 1.55e+05 | 1.21e+05 | 0.000122 | 9.53e-05 | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 53.1 | 52.2 | 0.98× | 1.65 | 56.1 | 34.07× | 0.706 | 56.1 | 79.48× | 0.611 | 22.6 | 37.00× | 1.55e+05 | 1.21e+05 | 7.55e-05 | 4.91e-05 | +| kkt_pglib_opf_case1354_pegase_k2_1 | 33811 | 97.4 | 1.03e+03 | 10.62× | 1.53 | 146 | 95.37× | 0.816 | 146 | 178.88× | 0.421 | 78.7 | 186.80× | 2.02e+05 | 2.16e+05 | 108 | 14.2 | +| kkt_pglib_opf_case1354_pegase_k2_10 | 33811 | 96.4 | 1.09e+03 | 11.28× | 1.55 | 161 | 103.65× | 0.827 | 145 | 175.73× | 0.448 | 79 | 176.38× | 2.02e+05 | 2.2e+05 | 52.2 | 51.7 | +| kkt_pglib_opf_case1354_pegase_k2_20 | 33811 | 100 | 1.1e+03 | 11.01× | 1.6 | 168 | 105.48× | 0.806 | 148 | 183.23× | 0.412 | 79.1 | 191.92× | 2.02e+05 | 2.21e+05 | 140 | 15.3 | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 6.65 | 1.17 | 0.18× | 0.226 | 0.615 | 2.73× | 0.192 | 0.629 | 3.27× | 0.321 | 0.418 | 1.30× | 1.27e+03 | 1.03e+03 | 9.81e-07 | 8.09e-07 | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 6.69 | 1.05 | 0.16× | 0.194 | 1.03 | 5.30× | 0.229 | 0.63 | 2.75× | 0.265 | 0.458 | 1.73× | 1.27e+03 | 1.03e+03 | 0.000129 | 0.000156 | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 6.74 | 1.06 | 0.16× | 0.212 | 0.681 | 3.21× | 0.291 | 0.605 | 2.08× | 0.299 | 0.504 | 1.69× | 1.27e+03 | 1.03e+03 | 1.44e-05 | 5.1e-06 | +| kkt_pglib_opf_case14_ieee_k2_1 | 344 | 9.21 | 4.08 | 0.44× | 0.216 | 2.02 | 9.32× | 0.28 | 1.59 | 5.66× | 0.265 | 0.96 | 3.62× | 2.02e+03 | 2.14e+03 | 0.182 | 1.07e-08 | +| kkt_pglib_opf_case14_ieee_k2_10 | 344 | 7.53 | 4.87 | 0.65× | 0.283 | 1.82 | 6.42× | 0.238 | 1.6 | 6.75× | 0.262 | 0.948 | 3.61× | 2.02e+03 | 2.15e+03 | 0.295 | 2.75e-05 | +| kkt_pglib_opf_case14_ieee_k2_15 | 344 | 7.63 | 3.56 | 0.47× | 0.217 | 1.71 | 7.87× | 0.322 | 1.75 | 5.44× | 0.435 | 0.842 | 1.93× | 2.02e+03 | 3.27e+03 | 0.221 | 0.324 | +| lap2d_300 | 90000 | 257 | 349 | 1.36× | 7.13 | 240 | 33.69× | 5.15 | 241 | 46.74× | 0.712 | 4.7 | 6.60× | 2.43e+06 | 2.47e+06 | 1.6e-12 | 1.68e-12 | +| lap3d_40 | 64000 | 332 | 416 | 1.25× | 62.9 | 1.46e+04 | 232.33× | 58.4 | 1.46e+04 | 250.37× | 1.41 | 19.4 | 13.68× | 1.75e+07 | 1.44e+07 | 7.68e-14 | 9.06e-14 | + +Single run instead of a BenchmarkTools trial (factorization above the `--single-run-above` limit): SDS on GHS_psdef/apache2, SDS on lap3d_40. + +## LDLᵀ + 2 refinement steps, K2 dumps + +`ldlt_ir2`, T16 (done), structure `S`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| kkt_pglib_opf_case118_ieee_k2_1 | 3150 | 15.8 | 54.3 | 3.43× | 0.827 | 13.8 | 16.68× | 0.371 | 13.8 | 37.20× | 0.6 | 23.4 | 39.01× | 2.02e+04 | 2.1e+04 | 0.00442 | 3.35e-09 | +| kkt_pglib_opf_case118_ieee_k2_10 | 3150 | 16 | 54.7 | 3.43× | 0.812 | 15.1 | 18.57× | 0.503 | 13.3 | 26.39× | 0.55 | 23 | 41.78× | 2.02e+04 | 2.05e+04 | 0.0164 | 5.78e-09 | +| kkt_pglib_opf_case118_ieee_k2_20 | 3150 | 15.5 | 53.1 | 3.42× | 0.828 | 13.6 | 16.47× | 0.339 | 13.6 | 40.15× | 0.596 | 22.9 | 38.43× | 2.02e+04 | 2.05e+04 | 0.189 | 7.51e-09 | +| kkt_pglib_opf_case1354_pegase_k2_1 | 33811 | 97.7 | 992 | 10.15× | 1.56 | 146 | 94.15× | 0.931 | 146 | 156.89× | 0.814 | 244 | 299.05× | 2.02e+05 | 2.16e+05 | 5.11 | 0.0159 | +| kkt_pglib_opf_case1354_pegase_k2_10 | 33811 | 97.4 | 1.09e+03 | 11.21× | 1.53 | 150 | 97.71× | 0.813 | 145 | 178.91× | 0.978 | 240 | 245.11× | 2.02e+05 | 2.2e+05 | 1.91 | 8.63 | +| kkt_pglib_opf_case1354_pegase_k2_20 | 33811 | 97.4 | 1.12e+03 | 11.53× | 1.55 | 151 | 96.87× | 0.825 | 148 | 178.98× | 0.958 | 241 | 251.59× | 2.02e+05 | 2.21e+05 | 13.9 | 0.148 | +| kkt_pglib_opf_case14_ieee_k2_1 | 344 | 7.76 | 4.38 | 0.56× | 0.222 | 1.59 | 7.17× | 0.215 | 1.58 | 7.36× | 0.719 | 2.76 | 3.84× | 2.02e+03 | 2.14e+03 | 3.23e-07 | 6.9e-13 | +| kkt_pglib_opf_case14_ieee_k2_10 | 344 | 7.47 | 5.09 | 0.68× | 0.295 | 1.63 | 5.52× | 0.233 | 2.09 | 8.98× | 1.26 | 3.89 | 3.09× | 2.02e+03 | 2.15e+03 | 9.14e-06 | 2.33e-14 | +| kkt_pglib_opf_case14_ieee_k2_15 | 344 | 7.46 | 2.54 | 0.34× | 0.206 | 2.41 | 11.71× | 0.235 | 1.82 | 7.74× | 0.65 | 2.36 | 3.63× | 2.02e+03 | 3.27e+03 | 2.4e-08 | 7.14e-09 | + +## Uniform batch of 8, Cholesky + +`ubatch8`, T17 (pending), structure `SPD`, Float64, nrhs = 1, uniform batch of 8. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 11.8 | | | 1.88 | | | 0.586 | | | 0.246 | | | 1.52e+04 | | 3.22e-05 | | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 12 | | | 1.87 | | | 0.562 | | | 0.326 | | | 1.52e+04 | | 1.2e-05 | | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 11.8 | | | 1.97 | | | 0.492 | | | 0.28 | | | 1.52e+04 | | 0.165 | | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 51.9 | | | 4 | | | 1.88 | | | 0.475 | | | 1.55e+05 | | 0.000339 | | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 51.9 | | | 4.61 | | | 1.56 | | | 0.503 | | | 1.55e+05 | | 0.000136 | | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 52.9 | | | 4 | | | 1.57 | | | 0.63 | | | 1.55e+05 | | 7.84e-05 | | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 7.32 | | | 0.739 | | | 0.213 | | | 0.375 | | | 1.27e+03 | | 8.25e-07 | | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 6.74 | | | 0.749 | | | 0.208 | | | 0.196 | | | 1.27e+03 | | 0.000156 | | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 7.1 | | | 0.713 | | | 0.222 | | | 0.223 | | | 1.27e+03 | | 1.88e-05 | | + +## LU, unsymmetric + +`lu`, T19 (pending), structure `G`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Rajat/rajat21 | 411676 | 1.77e+03 | | | 31.9 | | | 29.3 | | | 2.04 | | | 6.89e+06 | | 6.3e+07 | | +| TSOPF/TSOPF_RS_b39_c7 | 14098 | 89.2 | | | 2.63 | | | 1.03 | | | 0.451 | | | 1.47e+06 | | 2.24e+29 | | + +## Schur complement, Cholesky + +`schur`, T20 (pending), structure `SPD`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 11.7 | | | 0.945 | | | 0.374 | | | 0.201 | | | 1.96e+04 | | | | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 11.6 | | | 0.934 | | | 0.396 | | | 0.174 | | | 1.96e+04 | | | | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 12.1 | | | 0.911 | | | 0.363 | | | 0.201 | | | 1.96e+04 | | | | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 52.7 | | | 1.51 | | | 0.691 | | | 0.212 | | | 1.65e+05 | | | | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 52.5 | | | 1.68 | | | 0.685 | | | 0.216 | | | 1.65e+05 | | | | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 52.8 | | | 1.43 | | | 0.69 | | | 0.219 | | | 1.65e+05 | | | | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 7.09 | | | 0.281 | | | 0.232 | | | 0.167 | | | 1.51e+03 | | | | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 6.9 | | | 0.267 | | | 0.323 | | | 0.172 | | | 1.51e+03 | | | | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 8.14 | | | 0.256 | | | 0.237 | | | 0.179 | | | 1.51e+03 | | | | + +## LDLᵀ + matching (algo5), K2 dumps + +`ldlt_matching`, T21 (pending), structure `S`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| kkt_pglib_opf_case118_ieee_k2_1 | 3150 | 21.5 | | | 1.03 | | | 0.484 | | | 0.259 | | | 7.38e+04 | | 3.71e-12 | | +| kkt_pglib_opf_case118_ieee_k2_10 | 3150 | 21.7 | | | 1.05 | | | 0.481 | | | 0.243 | | | 7.1e+04 | | 7.86e-13 | | +| kkt_pglib_opf_case118_ieee_k2_20 | 3150 | 21.7 | | | 0.969 | | | 0.679 | | | 0.264 | | | 6.85e+04 | | 3.76e-13 | | +| kkt_pglib_opf_case1354_pegase_k2_1 | 33811 | 129 | | | 2.22 | | | 1.22 | | | 0.419 | | | 7.23e+05 | | 0.00489 | | +| kkt_pglib_opf_case1354_pegase_k2_10 | 33811 | 133 | | | 2.22 | | | 1.39 | | | 0.419 | | | 7.31e+05 | | 0.00471 | | +| kkt_pglib_opf_case1354_pegase_k2_20 | 33811 | 135 | | | 2.14 | | | 1.2 | | | 0.397 | | | 7.23e+05 | | 0.0156 | | +| kkt_pglib_opf_case14_ieee_k2_1 | 344 | 8.75 | | | 0.324 | | | 0.287 | | | 0.222 | | | 7.26e+03 | | 8.54e-13 | | +| kkt_pglib_opf_case14_ieee_k2_10 | 344 | 8.56 | | | 0.345 | | | 0.375 | | | 0.249 | | | 6.93e+03 | | 7.95e-14 | | +| kkt_pglib_opf_case14_ieee_k2_15 | 344 | 8.4 | | | 0.271 | | | 0.325 | | | 0.226 | | | 6.93e+03 | | 4.71e-14 | | + +## Non-uniform batch, condensed dumps + +`nubatch`, T22 (pending), structure `SPD`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| batch_of_9 | 37194 | 129 | | | 2.01 | | | 0.95 | | | 0.427 | | | 5.12e+05 | | 0.186 | | + +## Partitioned-inverse solve (SDS algo1, cuDSS default) + +`solve_algo1`, T25 (pending), structure `SPD`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Boeing/bcsstk38 | 8032 | 35.2 | | | 3.55 | | | 2.24 | | | 0.456 | | | 7.99e+05 | | 2.15e-10 | | +| GHS_psdef/apache2 | 715176 | 4.3e+03 | | | 447 | | | 417 | | | 6.53 | | | 1.45e+08 | | 1.8e-10 | | +| HB/bcsstk17 | 10974 | 41.5 | | | 3.77 | | | 2.38 | | | 0.51 | | | 1.08e+06 | | 4.28e-11 | | +| kkt_pglib_opf_case118_ieee_condensed_1 | 1088 | 11.8 | | | 0.89 | | | 0.385 | | | 0.243 | | | 1.52e+04 | | 3.45e-05 | | +| kkt_pglib_opf_case118_ieee_condensed_10 | 1088 | 11.8 | | | 0.908 | | | 0.345 | | | 0.249 | | | 1.52e+04 | | 1.17e-05 | | +| kkt_pglib_opf_case118_ieee_condensed_20 | 1088 | 11.6 | | | 0.859 | | | 0.392 | | | 0.24 | | | 1.52e+04 | | 0.375 | | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 54.6 | | | 1.33 | | | 0.754 | | | 0.29 | | | 1.55e+05 | | 0.000307 | | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 57.4 | | | 1.43 | | | 0.595 | | | 0.339 | | | 1.55e+05 | | 0.00014 | | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 54.1 | | | 1.33 | | | 0.736 | | | 0.335 | | | 1.55e+05 | | 7.78e-05 | | +| kkt_pglib_opf_case14_ieee_condensed_1 | 118 | 7.07 | | | 0.267 | | | 0.217 | | | 0.356 | | | 1.27e+03 | | 6.85e-07 | | +| kkt_pglib_opf_case14_ieee_condensed_10 | 118 | 7.17 | | | 0.224 | | | 0.224 | | | 0.345 | | | 1.27e+03 | | 0.000103 | | +| kkt_pglib_opf_case14_ieee_condensed_11 | 118 | 6.96 | | | 0.223 | | | 0.217 | | | 0.264 | | | 1.27e+03 | | 1.11e-05 | | +| lap2d_300 | 90000 | 261 | | | 5.73 | | | 3.8 | | | 0.702 | | | 2.43e+06 | | 1.85e-12 | | +| lap3d_40 | 64000 | 327 | | | 50.8 | | | 45.8 | | | 1.39 | | | 1.75e+07 | | 8.3e-14 | | + +## Hybrid memory mode + +`hybrid_memory`, T26 (pending), structure `SPD`, Float64, nrhs = 1. + +| matrix | n | analysis cuDSS ms | SDS ms | ratio | factorization cuDSS ms | SDS ms | ratio | refactorization cuDSS ms | SDS ms | ratio | solve cuDSS ms | SDS ms | ratio | nnz(L) cuDSS | SDS | relres cuDSS | SDS | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| GHS_psdef/apache2 | 715176 | 4.37e+03 | | | 446 | | | 418 | | | 6.51 | | | 1.45e+08 | | 1.8e-10 | | +| kkt_pglib_opf_case1354_pegase_condensed_1 | 11192 | 53.2 | | | 1.4 | | | 0.614 | | | 0.328 | | | 1.55e+05 | | 0.000291 | | +| kkt_pglib_opf_case1354_pegase_condensed_10 | 11192 | 54.7 | | | 1.41 | | | 0.593 | | | 0.452 | | | 1.55e+05 | | 0.000147 | | +| kkt_pglib_opf_case1354_pegase_condensed_20 | 11192 | 52 | | | 1.32 | | | 0.779 | | | 0.341 | | | 1.55e+05 | | 7.14e-05 | | + +## Float32 factors, Float64 refinement + +`mixed_precision`, T27 (pending), structure `SPD`, Float64, nrhs = 1, no cuDSS counterpart. + +Not run yet. + +## Runs + +* cuDSS 0.8.0 on NVIDIA GeForce RTX 4080, repository 57e2ea9+dirty, 2026-10-02. +* SparseDirectSolver.jl 0.1.0 on NVIDIA GeForce RTX 4080, repository 73b93aa+dirty, 2026-10-02. diff --git a/bench/comparison/comparison.png b/bench/comparison/comparison.png new file mode 100644 index 0000000..4e15294 Binary files /dev/null and b/bench/comparison/comparison.png differ diff --git a/bench/comparison/cudss.csv b/bench/comparison/cudss.csv new file mode 100644 index 0000000..f7ab1be --- /dev/null +++ b/bench/comparison/cudss.csv @@ -0,0 +1,109 @@ +solver,feature,task,matrix,structure,n,nnz,T,nrhs,nbatch,analysis_s,factorization_s,refactorization_s,solve_s,analysis_min_s,factorization_min_s,refactorization_min_s,solve_min_s,lu_nnz,flops,nsuperpanels,relres,samples,status,device,version,git_sha,date +cudss,cholesky_f64,T13,Boeing/bcsstk38,SPD,8032,355460,Float64,1,1,0.035060002,0.003521595,0.002295307,0.000462275,0.034522777,0.0034875,0.002263283,0.000407986,798965.0,1.30393272e8,0.0,2.1473371068813558e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,GHS_psdef/apache2,SPD,715176,4817870,Float64,1,1,4.284841065,0.449437059,0.42075667,0.006619135,4.268457182,0.4488586,0.419957507,0.006599641,1.44624555e8,2.28522934388e11,21.0,1.7980039292265598e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,HB/bcsstk17,SPD,10974,428650,Float64,1,1,0.043201537,0.003901651,0.002452095,0.000500465,0.041996133,0.003710314,0.002331657,0.00042721,1.077096e6,1.67140496e8,0.0,4.0165594207132357e-11,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,1,1,0.013016571,0.000992045,0.000437585,0.000256047,0.011950531,0.00095403,0.000347966,0.000232828,15200.0,272110.0,0.0,7.263795568128644e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,1,1,0.012301181,0.00102428,0.000530075,0.000260508,0.012135948,0.000948861,0.000342906,0.000215558,15200.0,272110.0,0.0,1.3950580448410445e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,1,1,0.012808625,0.001063664,0.000351437,0.000256737,0.011981259,0.000957265,0.000350086,0.000197788,15200.0,272110.0,0.0,0.2931576016826416,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,1,0.054164461,0.001354491,0.000585044,0.000268998,0.052228285,0.001332412,0.000575165,0.000263347,155201.0,3.329818e6,0.0,0.00031641658935317875,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,1,0.055415839,0.001396891,0.000584053,0.000375311,0.052421039,0.001355097,0.000572645,0.000304207,155201.0,3.329818e6,0.0,0.00014216981507751586,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,1,0.055449663,0.001394636,0.000685033,0.000387386,0.052590347,0.001383987,0.000586224,0.000262167,155201.0,3.329818e6,0.0,7.944102795473919e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,1,1,0.006824223,0.000215898,0.000224577,0.000186648,0.006661405,0.000187898,0.000192018,0.000152769,1268.0,15255.0,0.0,4.086807756802718e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,1,1,0.006767104,0.000220878,0.000212078,0.000194688,0.006613235,0.000191978,0.000193448,0.000172188,1268.0,15255.0,0.0,0.00010922717339638167,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,1,1,0.006889892,0.000241588,0.000279737,0.000213518,0.006720173,0.000210518,0.000215208,0.000173788,1268.0,15255.0,0.0,1.2042866448431041e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,lap2d_300,SPD,90000,448800,Float64,1,1,0.281285211,0.006836892,0.003838622,0.000852422,0.272735577,0.00557883,0.003732383,0.000717558,2.428175e6,3.17918802e8,0.0,1.8353669652327745e-12,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_f64,T13,lap3d_40,SPD,64000,438400,Float64,1,1,0.340153748,0.055813029,0.050563215,0.001354186,0.338310031,0.055176137,0.050433887,0.001291467,1.7527585e7,2.1925367162e10,2.0,8.288745113779613e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,Boeing/bcsstk38,SPD,8032,355460,Float64,16,1,0.03530498,0.00354818,0.002290817,0.000705533,0.034725604,0.003480765,0.002266887,0.000680208,798965.0,1.30393272e8,0.0,6.699560630996109e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,GHS_psdef/apache2,SPD,715176,4817870,Float64,16,1,4.295647942,0.446945079,0.417489275,0.027600041,4.261842556,0.446283285,0.416775345,0.027464247,1.44624555e8,2.28522934388e11,21.0,1.8268694751270727e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,HB/bcsstk17,SPD,10974,428650,Float64,16,1,0.040825598,0.003803122,0.002420276,0.000757663,0.040062441,0.003774353,0.002349867,0.000710303,1.077096e6,1.67140496e8,0.0,5.134389329571571e-11,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,16,1,0.011754842,0.000911131,0.000341426,0.000374646,0.011458684,0.000834968,0.000324621,0.000266788,15200.0,272110.0,0.0,6.700671713503177e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,16,1,0.011866391,0.000882265,0.000405905,0.000346147,0.011739179,0.000863406,0.000345766,0.000329077,15200.0,272110.0,0.0,1.5241538493958117e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,16,1,0.012169396,0.000888501,0.000358751,0.000260307,0.011675165,0.000854851,0.000332846,0.000252907,15200.0,272110.0,0.0,0.49192728304440614,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,16,1,0.051893503,0.001372387,0.000580934,0.000486955,0.051595996,0.001305798,0.000578154,0.000457122,155201.0,3.329818e6,0.0,0.00039420769649059734,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,16,1,0.052940774,0.001496338,0.00061401,0.000457495,0.050956513,0.001349396,0.000558549,0.00043896,155201.0,3.329818e6,0.0,0.00013727456047160072,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,16,1,0.053323019,0.001336281,0.000701363,0.000461225,0.052040808,0.001320402,0.000560154,0.000442065,155201.0,3.329818e6,0.0,9.791255582978397e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,16,1,0.007245347,0.000198698,0.000240258,0.000220768,0.006748813,0.000185988,0.000209958,0.000183899,1268.0,15255.0,0.0,6.349650263590208e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,16,1,0.006755114,0.000217718,0.000211748,0.000364627,0.006591565,0.000183709,0.000209288,0.000193658,1268.0,15255.0,0.0,0.00017854366933974119,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,16,1,0.006838361,0.000240158,0.000221628,0.000261147,0.006690338,0.000181328,0.000200088,0.000195988,1268.0,15255.0,0.0,3.343267461426919e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,lap2d_300,SPD,90000,448800,Float64,16,1,0.270593913,0.005709276,0.003803843,0.002302468,0.264057988,0.005675784,0.003758177,0.002242522,2.428175e6,3.17918802e8,0.0,1.8493163494148416e-12,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,cholesky_nrhs16,T12,lap3d_40,SPD,64000,438400,Float64,16,1,0.3287505,0.050543248,0.045663502,0.00557982,0.32678831,0.050412215,0.045301828,0.005529906,1.7527585e7,2.1925367162e10,2.0,8.988148911207075e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,Boeing/bcsstk38,S,8032,355460,Float64,1,1,0.035547276,0.004547345,0.003314338,0.000476385,0.035325259,0.004471816,0.003246062,0.00044544,798965.0,1.30393272e8,0.0,6.496398763236308e-11,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,GHS_psdef/apache2,S,715176,4817870,Float64,1,1,4.445488464,0.518107596,0.489350197,0.006803422,4.395045641,0.517172704,0.48834013,0.006732254,1.44624555e8,2.28522934388e11,21.0,1.5833232788559718e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,HB/bcsstk17,S,10974,428650,Float64,1,1,0.04223345,0.005448602,0.003374267,0.000500055,0.041295614,0.004759053,0.003276558,0.000466355,1.077096e6,1.67140496e8,0.0,3.871657523736132e-11,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_1,S,1088,12860,Float64,1,1,0.012892998,0.00090504,0.000390436,0.000383086,0.012711183,0.000887961,0.000328677,0.000210158,15200.0,272110.0,0.0,2.9856012503869884e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_10,S,1088,12860,Float64,1,1,0.0120357,0.000921386,0.000349386,0.000249257,0.011896031,0.000885042,0.000342756,0.000221558,15200.0,272110.0,0.0,9.524756251521279e-6,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_20,S,1088,12860,Float64,1,1,0.012924046,0.000898801,0.000351147,0.000282048,0.012052111,0.000894021,0.000324507,0.000249868,15200.0,272110.0,0.0,0.10788231601615018,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_1,S,3150,17714,Float64,1,1,0.016237889,0.000845492,0.000362796,0.000228698,0.016043515,0.000835202,0.000320807,0.000207168,20211.0,196794.0,0.0,2.3998849853705906,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_10,S,3150,17714,Float64,1,1,0.016180678,0.000867582,0.000353717,0.000284317,0.015647444,0.000817112,0.000324507,0.000254677,20211.0,196794.0,0.0,10.084656255768957,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_20,S,3150,17714,Float64,1,1,0.01617026,0.000830412,0.000399596,0.000271848,0.015906871,0.000804042,0.000365896,0.000259728,20211.0,196794.0,0.0,6.0336051500002705,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_1,S,11192,136724,Float64,1,1,0.053345349,0.001386526,0.000684413,0.000355206,0.051259324,0.001379215,0.000654863,0.000270188,155201.0,3.329818e6,0.0,0.00029614275663591045,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_10,S,11192,136724,Float64,1,1,0.052355873,0.001393086,0.000642869,0.000278637,0.05116971,0.001380426,0.000632463,0.000273607,155201.0,3.329818e6,0.0,0.0001224562514208483,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_20,S,11192,136724,Float64,1,1,0.053066679,0.001647274,0.000705523,0.000610564,0.051548198,0.001403246,0.000652673,0.000359671,155201.0,3.329818e6,0.0,7.55487743275319e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_1,S,33811,188063,Float64,1,1,0.097397122,0.00153126,0.000816451,0.000421192,0.095319062,0.001504125,0.000765232,0.000366806,202300.0,2.326076e6,0.0,108.0582883952038,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_10,S,33811,188063,Float64,1,1,0.096375736,0.00154884,0.000827192,0.00044804,0.094609414,0.00151934,0.000785198,0.000433046,202300.0,2.326076e6,0.0,52.17854436066793,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_20,S,33811,188063,Float64,1,1,0.10036616,0.001595909,0.000805892,0.000412261,0.094218957,0.001523895,0.000779842,0.000397091,202300.0,2.326076e6,0.0,140.0478360719644,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_1,S,118,1282,Float64,1,1,0.006654315,0.000225657,0.000192468,0.000321417,0.006598713,0.000188738,0.000169499,0.000232698,1268.0,15255.0,0.0,9.81468171037147e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_10,S,118,1282,Float64,1,1,0.006688553,0.000193968,0.000229428,0.000264877,0.006625943,0.000181279,0.000205268,0.000243147,1268.0,15255.0,0.0,0.00012883083671537157,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_11,S,118,1282,Float64,1,1,0.006743062,0.000212238,0.000290707,0.000299107,0.006663254,0.000186448,0.000177238,0.000166418,1268.0,15255.0,0.0,1.4434712774694826e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_1,S,344,1924,Float64,1,1,0.009205469,0.000216368,0.000280138,0.000264977,0.007392428,0.000182158,0.000174679,0.000189288,2024.0,15061.0,0.0,0.18246516229355206,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_10,S,344,1924,Float64,1,1,0.007534584,0.000283407,0.000237828,0.000262317,0.007520445,0.000250568,0.000207868,0.000194548,2024.0,15061.0,0.0,0.294793479199583,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_15,S,344,1924,Float64,1,1,0.007628965,0.000217088,0.000321507,0.000435436,0.007390027,0.000183308,0.000197218,0.000218747,2024.0,15061.0,0.0,0.2209028165354915,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,lap2d_300,S,90000,448800,Float64,1,1,0.25650659,0.007134768,0.005149699,0.000712128,0.251955638,0.00710648,0.005074279,0.000660573,2.428175e6,3.17918802e8,0.0,1.6049723724157528e-12,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt,T15,lap3d_40,S,64000,438400,Float64,1,1,0.33161942,0.062896139,0.058362218,0.001414836,0.325486651,0.062546769,0.058168071,0.001368406,1.7527585e7,2.1925367162e10,2.0,7.679721602411845e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_1,S,3150,17714,Float64,1,1,0.015821558,0.000827447,0.000370946,0.000600049,0.015663984,0.000792982,0.000363487,0.000540355,20211.0,196794.0,0.0,0.004422323681820168,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_10,S,3150,17714,Float64,1,1,0.015955475,0.000811912,0.000502855,0.00055033,0.015832857,0.000788533,0.000312181,0.000503565,20211.0,196794.0,0.0,0.016446167821606704,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_20,S,3150,17714,Float64,1,1,0.015504766,0.000828421,0.000338877,0.000595613,0.015441935,0.000762762,0.000308967,0.000477775,20211.0,196794.0,0.0,0.18897178625860092,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_1,S,33811,188063,Float64,1,1,0.097701808,0.001555304,0.000931341,0.000814286,0.094506549,0.00153716,0.000842992,0.000791527,202300.0,2.326076e6,0.0,5.107425409697022,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_10,S,33811,188063,Float64,1,1,0.09736267,0.001534901,0.000812772,0.000977825,0.095261481,0.00150829,0.000763362,0.000793712,202300.0,2.326076e6,0.0,1.9129096394710416,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_20,S,33811,188063,Float64,1,1,0.097420885,0.001554195,0.000825402,0.000957545,0.095711143,0.001541049,0.000786862,0.000806992,202300.0,2.326076e6,0.0,13.86903644125827,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_1,S,344,1924,Float64,1,1,0.007758553,0.000222357,0.000215238,0.000718819,0.007514985,0.000194518,0.000187978,0.000370976,2024.0,15061.0,0.0,3.2268591438362523e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_10,S,344,1924,Float64,1,1,0.007469755,0.000294767,0.000233088,0.001260488,0.007432257,0.000210468,0.000204258,0.000473776,2024.0,15061.0,0.0,9.140251785245421e-6,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_15,S,344,1924,Float64,1,1,0.007463276,0.000205608,0.000234768,0.000649624,0.007410946,0.000187528,0.000214528,0.000338227,2024.0,15061.0,0.0,2.3982316148866614e-8,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,1,8,0.011785488,0.001882661,0.000586314,0.000246118,0.011511936,0.001844622,0.000483335,0.000236768,15200.0,272110.0,0.0,3.217810034932607e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,1,8,0.011965242,0.001865081,0.000561824,0.000326207,0.011498377,0.001847687,0.000488045,0.000250607,15200.0,272110.0,0.0,1.2018641140881662e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,1,8,0.011830413,0.001971265,0.000492485,0.000279877,0.011569625,0.001867541,0.000478025,0.000260537,15200.0,272110.0,0.0,0.16536169031735817,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,8,0.051920204,0.003998411,0.001876202,0.000474765,0.051258174,0.003969922,0.001604934,0.000445376,155201.0,3.329818e6,0.0,0.00033907536094029506,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,8,0.051939349,0.004605709,0.001562904,0.000503245,0.050949969,0.003924111,0.001534472,0.000461185,155201.0,3.329818e6,0.0,0.0001359772524016248,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,8,0.052882669,0.003996862,0.001566714,0.000630124,0.051098876,0.00389837,0.001545668,0.000469485,155201.0,3.329818e6,0.0,7.836976721473675e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,1,8,0.007323498,0.000739307,0.000212718,0.000375006,0.006640973,0.000677543,0.000206008,0.000237708,1268.0,15255.0,0.0,8.245295917011054e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,1,8,0.006737062,0.000748688,0.000207818,0.000195688,0.006662424,0.000647532,0.000190019,0.000158349,1268.0,15255.0,0.0,0.0001559511859180611,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ubatch8,T17,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,1,8,0.007098868,0.000712893,0.000222487,0.000222658,0.006622695,0.000670204,0.000208248,0.000187638,1268.0,15255.0,0.0,1.8847019801264928e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,lu,T19,Rajat/rajat21,G,411676,1893370,Float64,1,1,1.772969221,0.031858759,0.029320553,0.00203524,1.767117448,0.031741144,0.029049092,0.00200654,6.891584e6,5.212013513e9,2.0,6.296735861977335e7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,lu,T19,TSOPF/TSOPF_RS_b39_c7,G,14098,252446,Float64,1,1,0.089234729,0.002627054,0.00102844,0.00045147,0.084698153,0.00255188,0.00098804,0.000327406,1.47e6,9.5459011e7,0.0,2.2410049029105248e29,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,1,1,0.011735983,0.000945062,0.000373877,0.000201348,0.011651173,0.000861051,0.000369615,0.000180628,19631,622719,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,1,1,0.011578734,0.000933777,0.000396186,0.000173608,0.011425206,0.000859707,0.000341637,0.000159088,19631,622719,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,1,1,0.01208741,0.000910696,0.000363306,0.000201418,0.011559116,0.000860595,0.000344556,0.000179999,19631,622719,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,1,0.0526824,0.001506665,0.000690703,0.000211968,0.052155314,0.001414196,0.000675033,0.000197578,165293,4462458,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,1,0.052461234,0.001679343,0.000685012,0.000216408,0.052247965,0.001424446,0.000645193,0.000199018,165293,4462458,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,1,0.052776825,0.001430416,0.000689813,0.000218817,0.051988683,0.001410626,0.000616669,0.000181698,165293,4462458,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,1,1,0.00709225,0.000280908,0.000231617,0.000166958,0.006702743,0.000208898,0.000216188,0.000153498,1511,23110,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,1,1,0.006898827,0.000267047,0.000323007,0.000171878,0.006725453,0.000240687,0.000239707,0.000155279,1511,23110,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,schur,T20,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,1,1,0.008140498,0.000256278,0.000237447,0.000179048,0.006923101,0.000236178,0.000220528,0.000146369,1511,23110,0,,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case118_ieee_k2_1,S,3150,17714,Float64,1,1,0.021474177,0.00102757,0.000483696,0.000259027,0.021152805,0.000912861,0.00045789,0.000241378,73778.0,1.64941e6,0.0,3.708588017598577e-12,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case118_ieee_k2_10,S,3150,17714,Float64,1,1,0.021688946,0.001047665,0.000480855,0.000242648,0.021428798,0.000942731,0.000450315,0.000230108,71018.0,1.513289e6,0.0,7.862883953651755e-13,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case118_ieee_k2_20,S,3150,17714,Float64,1,1,0.021701855,0.000969181,0.000678534,0.000264427,0.02117276,0.000937511,0.000487535,0.000239598,68472.0,1.396484e6,0.0,3.7614986115076254e-13,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case1354_pegase_k2_1,S,33811,188063,Float64,1,1,0.12949221,0.002224048,0.001216888,0.000418896,0.128672234,0.002103199,0.001201709,0.000412436,722739.0,1.9670743e7,0.0,0.004891380877560148,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case1354_pegase_k2_10,S,33811,188063,Float64,1,1,0.132934829,0.002223467,0.001392347,0.000418996,0.130164369,0.002191833,0.001245028,0.000380046,730963.0,2.0806467e7,0.0,0.004714071653711646,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case1354_pegase_k2_20,S,33811,188063,Float64,1,1,0.135263866,0.002141514,0.001203538,0.000397316,0.134955923,0.002095214,0.001118759,0.000380156,722763.0,1.9509233e7,0.0,0.015554030920514779,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case14_ieee_k2_1,S,344,1924,Float64,1,1,0.008748358,0.000324357,0.000286527,0.000221928,0.008574744,0.000240468,0.000249427,0.000203068,7264.0,137558.0,0.0,8.541235733582555e-13,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case14_ieee_k2_10,S,344,1924,Float64,1,1,0.008562856,0.000345377,0.000375377,0.000248797,0.008226709,0.000247698,0.000249388,0.000169018,6926.0,119037.0,0.0,7.951719673608634e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,ldlt_matching,T21,kkt_pglib_opf_case14_ieee_k2_15,S,344,1924,Float64,1,1,0.008398447,0.000271497,0.000324967,0.000226418,0.008249189,0.000239948,0.000309937,0.000210068,6926.0,119037.0,0.0,4.7070448639145856e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,nubatch,T22,batch_of_9,SPD,37194,452598,Float64,1,9,0.129192436,0.002006649,0.00094972,0.000426816,0.128671157,0.001997955,0.000927771,0.000416646,512386.0,1.0980714e7,0.0,0.1855924609238113,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,Boeing/bcsstk38,SPD,8032,355460,Float64,1,1,0.03519364,0.003551285,0.002242748,0.000455956,0.034483501,0.00345768,0.002195888,0.000443325,798965.0,1.30393272e8,0.0,2.1529756798740355e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,GHS_psdef/apache2,SPD,715176,4817870,Float64,1,1,4.300241032,0.447041143,0.417117744,0.006530704,4.265771335,0.446236761,0.416517738,0.006489032,1.44624555e8,2.28522934388e11,21.0,1.7986750735138067e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,HB/bcsstk17,SPD,10974,428650,Float64,1,1,0.041490758,0.003767072,0.002381005,0.000509775,0.040661166,0.003724293,0.002355786,0.000454925,1.077096e6,1.67140496e8,0.0,4.284380268951044e-11,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,1,1,0.011823822,0.000889541,0.000384556,0.000243097,0.011605846,0.000847427,0.000314935,0.000208568,15200.0,272110.0,0.0,3.451095742061928e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,1,1,0.011805553,0.000907841,0.000345436,0.000248888,0.011544824,0.000846391,0.000294587,0.000210308,15200.0,272110.0,0.0,1.1718305601301206e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,1,1,0.011582684,0.000858532,0.000392326,0.000239667,0.011541126,0.000847671,0.000316527,0.000210728,15200.0,272110.0,0.0,0.375282906413019,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,1,0.054624476,0.001330001,0.000754478,0.000290327,0.052442768,0.001317827,0.000562674,0.000262027,155201.0,3.329818e6,0.0,0.00030746890622787316,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,1,0.057367709,0.001428326,0.000595444,0.000339016,0.051727384,0.001387711,0.000581155,0.000269007,155201.0,3.329818e6,0.0,0.00014020524088089663,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,1,0.054101041,0.001328372,0.000736283,0.000335397,0.053496147,0.001279297,0.000571005,0.000249748,155201.0,3.329818e6,0.0,7.776584912878078e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,1,1,0.007071268,0.000267237,0.000216608,0.000355707,0.006794663,0.000195038,0.000190658,0.000172469,1268.0,15255.0,0.0,6.85483844053459e-7,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,1,1,0.007169144,0.000223568,0.000223628,0.000344817,0.007052829,0.000208938,0.000182609,0.000175548,1268.0,15255.0,0.0,0.0001034655941244147,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,1,1,0.006958001,0.000223258,0.000217048,0.000264088,0.006758034,0.000188108,0.000192678,0.000182848,1268.0,15255.0,0.0,1.1091126531769816e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,lap2d_300,SPD,90000,448800,Float64,1,1,0.261020839,0.005727948,0.003799182,0.000702483,0.259065453,0.005713919,0.003768582,0.000657094,2.428175e6,3.17918802e8,0.0,1.8478589965644124e-12,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,solve_algo1,T25,lap3d_40,SPD,64000,438400,Float64,1,1,0.326983407,0.050756211,0.045835803,0.001386986,0.323049685,0.050598516,0.045692599,0.001316497,1.7527585e7,2.1925367162e10,2.0,8.296433336120358e-14,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,hybrid_memory,T26,GHS_psdef/apache2,SPD,715176,4817870,Float64,1,1,4.374816114,0.445513119,0.417558463,0.006507555,4.286415223,0.445088838,0.417379808,0.006481426,1.44624555e8,2.28522934388e11,21.0,1.798573273274856e-10,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,hybrid_memory,T26,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,1,0.053210885,0.001402411,0.000613574,0.000328016,0.05177894,0.001319837,0.000591827,0.000265197,155201.0,3.329818e6,0.0,0.00029085192956193,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,hybrid_memory,T26,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,1,0.054697406,0.001411285,0.000593029,0.000452441,0.053131121,0.001307366,0.000561254,0.000249587,155201.0,3.329818e6,0.0,0.00014743927960820415,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 +cudss,hybrid_memory,T26,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,1,0.051966932,0.001318071,0.000779362,0.000340887,0.051623132,0.001301527,0.000588474,0.000265438,155201.0,3.329818e6,0.0,7.138105411625885e-5,5,ok,NVIDIA GeForce RTX 4080,0.8.0,57e2ea9+dirty,2026-10-02 diff --git a/bench/comparison/sds.csv b/bench/comparison/sds.csv new file mode 100644 index 0000000..7a8346e --- /dev/null +++ b/bench/comparison/sds.csv @@ -0,0 +1,61 @@ +solver,feature,task,matrix,structure,n,nnz,T,nrhs,nbatch,analysis_s,factorization_s,refactorization_s,solve_s,analysis_min_s,factorization_min_s,refactorization_min_s,solve_min_s,lu_nnz,flops,nsuperpanels,relres,samples,status,device,version,git_sha,date +sds,cholesky_f64,T13,Boeing/bcsstk38,SPD,8032,355460,Float64,1,1,0.055041544,0.023561976,0.023540804,0.001882663,0.05477267,0.023523856,0.023517671,0.001836221,804613,1.40793119e8,604,1.050998291749151e-10,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,GHS_psdef/apache2,SPD,715176,4817870,Float64,1,1,6.075783352,1.031854046,1.023644657,0.076661892,6.004857578,1.026676972,1.023323183,0.073941104,129200941,1.66491403722e11,123689,1.5829650410070863e-10,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,HB/bcsstk17,SPD,10974,428650,Float64,1,1,0.065546234,0.029568025,0.029604894,0.003491196,0.064005437,0.029508741,0.029566311,0.003450174,1043601,1.6795197e8,1300,5.049962573339207e-11,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,1,1,0.004455246,0.003872081,0.00387656,0.002723033,0.004427476,0.003861251,0.003867757,0.002229274,11634,219042.0,303,0.0001499152129335686,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,1,1,0.004783533,0.003635679,0.003674184,0.002090379,0.004704944,0.003616853,0.003617785,0.002076268,11634,219042.0,303,1.0007128179490731e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,1,1,0.004772433,0.003662303,0.003772103,0.00207468,0.004643315,0.003626044,0.003644184,0.00205492,11634,219042.0,303,0.0977012881293089,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,1,1,0.049981892,0.039883353,0.039883884,0.019669037,0.04814711,0.039817768,0.039802259,0.019621681,120598,2.787739e6,3134,0.00028169146220954487,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,1,1,0.04873287,0.038411673,0.038348444,0.019679444,0.047928509,0.038323848,0.038317108,0.019636183,120598,2.787739e6,3134,0.00014028077734730922,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,1,1,0.048956172,0.038327082,0.038384388,0.019673838,0.04874153,0.038309628,0.038284989,0.019523257,120598,2.787739e6,3134,7.407112355532926e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,1,1,0.00096492,0.000525965,0.000555025,0.000402396,0.000899841,0.000506245,0.00051384,0.000361576,1027,15193.0,33,1.6538473403875516e-6,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,1,1,0.001552204,0.000565479,0.000540295,0.000392166,0.0010087,0.000485235,0.000493485,0.000383046,1027,15193.0,33,0.00015711648509796294,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,1,1,0.00093695,0.000490015,0.000539125,0.000379317,0.000872541,0.000487475,0.000495235,0.000340847,1027,15193.0,33,1.670170208071547e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,lap2d_300,SPD,90000,448800,Float64,1,1,0.370827877,0.036380188,0.036289609,0.004104809,0.356950908,0.03629023,0.036283499,0.00404394,2465905,3.73611053e8,20495,1.7761691759148163e-12,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_f64,T13,lap3d_40,SPD,64000,438400,Float64,1,1,0.39802196,0.222990035,0.223344848,0.017043795,0.392282098,0.222942606,0.222917496,0.015558135,14387160,1.6401480134e10,11066,7.478815931690092e-14,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,Boeing/bcsstk38,SPD,8032,355460,Float64,16,1,0.053985858,0.023567186,0.023582937,0.003096266,0.053127947,0.023530144,0.023524176,0.003050938,804613,1.40793119e8,604,1.6616774132045366e-10,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,GHS_psdef/apache2,SPD,715176,4817870,Float64,16,1,6.234490898,1.027368919,1.023103829,0.255904835,6.084311257,1.025134144,1.022538139,0.255507332,129200941,1.66491403722e11,123689,1.59519352774917e-10,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,HB/bcsstk17,SPD,10974,428650,Float64,16,1,0.066237912,0.029497654,0.029602047,0.006562009,0.065259415,0.02945503,0.029526828,0.005622915,1043601,1.6795197e8,1300,5.922473282639887e-11,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_1,SPD,1088,12860,Float64,16,1,0.004700083,0.003873657,0.003877566,0.002180983,0.004562895,0.003854292,0.00384882,0.00205092,11634,219042.0,303,0.0001499152129335686,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_10,SPD,1088,12860,Float64,16,1,0.004559674,0.004448016,0.003637058,0.002134644,0.004472946,0.003651353,0.003604424,0.00209515,11634,219042.0,303,1.1028908236861046e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case118_ieee_condensed_20,SPD,1088,12860,Float64,16,1,0.004737484,0.003700274,0.004006584,0.002048999,0.004496825,0.003602254,0.003609785,0.00200596,11634,219042.0,303,0.31757187210790866,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_1,SPD,11192,136724,Float64,16,1,0.049626492,0.039599661,0.039632746,0.019355258,0.049022436,0.039589098,0.03958507,0.019294657,120598,2.787739e6,3134,0.000392992742458017,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_10,SPD,11192,136724,Float64,16,1,0.04966657,0.038364914,0.038218948,0.019330161,0.048206482,0.038135431,0.038175365,0.019274767,120598,2.787739e6,3134,0.00014411152068572583,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case1354_pegase_condensed_20,SPD,11192,136724,Float64,16,1,0.049616889,0.03822914,0.038125329,0.019383157,0.049367355,0.038117826,0.038098719,0.019352948,120598,2.787739e6,3134,9.671929703062016e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_1,SPD,118,1282,Float64,16,1,0.00097384,0.000555105,0.000542974,0.000449095,0.000866742,0.000521184,0.000535355,0.000358437,1027,15193.0,33,2.709170129303515e-6,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_10,SPD,118,1282,Float64,16,1,0.001064299,0.000510703,0.000504045,0.000485675,0.000858991,0.000500455,0.000486805,0.000375226,1027,15193.0,33,0.00045426768909551265,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,kkt_pglib_opf_case14_ieee_condensed_11,SPD,118,1282,Float64,16,1,0.00094125,0.000521325,0.000543315,0.000446326,0.000925591,0.000490775,0.000487025,0.000401526,1027,15193.0,33,3.7141469401124885e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,lap2d_300,SPD,90000,448800,Float64,16,1,0.334096298,0.036393987,0.036393583,0.009137589,0.333249383,0.036343764,0.036319827,0.009098138,2465905,3.73611053e8,20495,1.7988719466898246e-12,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,cholesky_nrhs16,T12,lap3d_40,SPD,64000,438400,Float64,16,1,0.409275291,0.222932391,0.223009715,0.050472229,0.404915674,0.222682934,0.22295914,0.049418747,14387160,1.6401480134e10,11066,8.447248176670233e-14,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,Boeing/bcsstk38,S,8032,355460,Float64,1,1,0.061063483,0.129022486,0.129089467,0.002818442,0.059272134,0.128936368,0.129019492,0.001903311,804613,1.40793119e8,604,1.2512823581094381e-10,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,GHS_psdef/apache2,S,715176,4817870,Float64,1,1,6.966277483,90.742153005,91.194098803,0.089128092,6.966277483,90.742153005,91.194098803,0.089128092,129200941,1.66491403722e11,123689,1.6291268746741202e-10,1,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,HB/bcsstk17,S,10974,428650,Float64,1,1,0.072706655,0.198275825,0.198263953,0.003797132,0.070868664,0.198257019,0.198193158,0.003681003,1043601,1.6795197e8,1300,3.707249888539958e-11,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_1,S,1088,12860,Float64,1,1,0.00503649,0.0050286,0.005032138,0.002611824,0.004889712,0.004991059,0.005015509,0.002338457,11634,219042.0,303,6.969655897665449e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_10,S,1088,12860,Float64,1,1,0.005121053,0.004988512,0.004894846,0.002376846,0.005033365,0.004834392,0.004850692,0.002365701,11634,219042.0,303,9.740282741453158e-6,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_condensed_20,S,1088,12860,Float64,1,1,0.00504261,0.005042945,0.005025285,0.002379726,0.004871682,0.00499047,0.004990749,0.002369027,11634,219042.0,303,0.07793477586360127,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_1,S,3150,17714,Float64,1,1,0.054193661,0.013793913,0.013814408,0.007732719,0.052808174,0.013779913,0.013785283,0.007706387,21032,308794.0,1917,0.23695532264533115,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_10,S,3150,17714,Float64,1,1,0.054115257,0.014978147,0.013323078,0.007690192,0.053494918,0.013254027,0.013263097,0.007660205,20542,292847.0,1906,0.01060874507064105,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case118_ieee_k2_20,S,3150,17714,Float64,1,1,0.053061332,0.01355436,0.013593394,0.007678673,0.052354006,0.013546596,0.013568231,0.007639475,20507,291377.0,1889,0.027042646838526467,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_1,S,11192,136724,Float64,1,1,0.052076252,0.056332599,0.056272926,0.022579436,0.051053828,0.056288656,0.05625831,0.022551016,120598,2.787739e6,3134,0.00032169280786670235,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_10,S,11192,136724,Float64,1,1,0.052021244,0.055731125,0.055726805,0.022552461,0.051619108,0.055686641,0.05568685,0.022537766,120598,2.787739e6,3134,9.534327884384974e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_condensed_20,S,11192,136724,Float64,1,1,0.05224864,0.056120652,0.056074372,0.022592766,0.051581671,0.056092957,0.056045671,0.022542996,120598,2.787739e6,3134,4.9109638733395656e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_1,S,33811,188063,Float64,1,1,1.034719937,0.146043353,0.146048612,0.078678983,1.018265641,0.146023671,0.146007897,0.078667558,215953,3.404739e6,19624,14.214742644178667,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_10,S,33811,188063,Float64,1,1,1.087224016,0.160531018,0.145358463,0.079023534,1.076392049,0.145818691,0.14531794,0.078921025,220146,3.494638e6,19496,51.66970951161263,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case1354_pegase_k2_20,S,33811,188063,Float64,1,1,1.104788265,0.168333076,0.147665805,0.079119723,1.09590177,0.147641951,0.147638537,0.079012984,221292,3.599399e6,19600,15.32248012620186,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_1,S,118,1282,Float64,1,1,0.001169209,0.000614974,0.000628584,0.000418186,0.00103519,0.000600084,0.000603454,0.000394086,1027,15193.0,33,8.086607326073917e-7,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_10,S,118,1282,Float64,1,1,0.001053199,0.001027139,0.000630214,0.000457705,0.00099222,0.000753818,0.000596454,0.000410996,1027,15193.0,33,0.0001562445067991457,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_condensed_11,S,118,1282,Float64,1,1,0.001057939,0.000681173,0.000604554,0.000504465,0.00100525,0.000588785,0.000596604,0.000393426,1027,15193.0,33,5.097826580562365e-6,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_1,S,344,1924,Float64,1,1,0.004082119,0.00201686,0.001586234,0.000960371,0.004022189,0.001946523,0.001536285,0.000947731,2139,26663.0,186,1.0697170401067997e-8,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_10,S,344,1924,Float64,1,1,0.004873231,0.001818783,0.001604724,0.000947545,0.004666403,0.001732722,0.001578415,0.000934141,2154,27106.0,185,2.7456609715314606e-5,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,kkt_pglib_opf_case14_ieee_k2_15,S,344,1924,Float64,1,1,0.003557984,0.001709313,0.001747463,0.000842302,0.002675153,0.001701744,0.001701943,0.000824522,3273,56950.0,85,0.3235038258289765,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,lap2d_300,S,90000,448800,Float64,1,1,0.348791021,0.240367346,0.240674043,0.004701802,0.345909569,0.240345981,0.24044258,0.004654757,2465905,3.73611053e8,20495,1.6832598767896702e-12,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt,T15,lap3d_40,S,64000,438400,Float64,1,1,0.415790411,14.612541103,14.612355501,0.019351862,0.415790411,14.612541103,14.612355501,0.019351862,14387160,1.6401480134e10,11066,9.061811084088796e-14,1,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_1,S,3150,17714,Float64,1,1,0.054299737,0.013801582,0.013799794,0.023410607,0.053704662,0.013783426,0.013765864,0.023257204,21032,308794.0,1917,3.3512086898080463e-9,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_10,S,3150,17714,Float64,1,1,0.054693776,0.01507601,0.013270667,0.022995126,0.053929471,0.01498966,0.013263759,0.022858374,20542,292847.0,1906,5.776933647623207e-9,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case118_ieee_k2_20,S,3150,17714,Float64,1,1,0.05306064,0.013643744,0.013607562,0.022889278,0.052331748,0.013555077,0.013550177,0.022725457,20507,291377.0,1889,7.507645151131128e-9,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_1,S,33811,188063,Float64,1,1,0.991926506,0.146429037,0.146120059,0.243511976,0.98327876,0.146056859,0.146034119,0.242889352,215953,3.404739e6,19624,0.01594796168284804,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_10,S,33811,188063,Float64,1,1,1.091847841,0.149976461,0.145415602,0.239672107,1.08411467,0.145363863,0.145329983,0.239304801,220146,3.494638e6,19496,8.630339939807564,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case1354_pegase_k2_20,S,33811,188063,Float64,1,1,1.123629585,0.150556733,0.147732345,0.240913364,1.097421125,0.147659733,0.147692785,0.239965147,221292,3.599399e6,19600,0.14771862721996226,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_1,S,344,1924,Float64,1,1,0.004375957,0.001593206,0.001583714,0.002756917,0.0039867,0.001559215,0.001540205,0.002722203,2139,26663.0,186,6.896972747993074e-13,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_10,S,344,1924,Float64,1,1,0.00509171,0.001626868,0.00209265,0.003889711,0.004957215,0.001564664,0.001592625,0.003410052,2154,27106.0,185,2.3271477086231642e-14,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 +sds,ldlt_ir2,T16,kkt_pglib_opf_case14_ieee_k2_15,S,344,1924,Float64,1,1,0.002540124,0.002406726,0.001815996,0.002360497,0.002492155,0.001705623,0.001719133,0.002343986,3273,56950.0,85,7.139728621879342e-9,5,ok,NVIDIA GeForce RTX 4080,0.1.0,73b93aa+dirty,2026-10-02 diff --git a/bench/features.jl b/bench/features.jl new file mode 100644 index 0000000..a7b0afa --- /dev/null +++ b/bench/features.jl @@ -0,0 +1,115 @@ +# Feature table of the cuDSS vs SparseDirectSolver.jl comparison (`compare.jl`, +# `compare_report.jl`): one entry per planned feature, in TASKS.md order. A +# feature counts as implemented when its task is marked done in TASKS.md; until +# then the SparseDirectSolver run skips it and the report leaves its cells blank. +# Plain Float32 factorizations are left out: cuDSS fails on every condensed KKT +# dump in Float32, and single precision is not accurate enough for these +# systems. Float32 factors appear only with Float64 refinement (T27). +# +# Declarative only: no GPU package, no solver package, so the test suite can +# include it. Matrix selectors take anything with `name`, `source` and +# `structures` fields (a `BenchMatrices.BenchMatrix`). + +module BenchFeatures + +export Feature, COMPARE_FEATURES, feature, task_status, feature_implemented + +""" + Feature(; id, title, task, structure, matrices, kwargs...) + +One comparison feature. `structure` is the cuDSS structure string, `T` the +element type, `nrhs` the right-hand sides per system. `kind` selects how the +systems are built: `:single` (one matrix per row), `:ubatch` (uniform batch of +`nbatch` value sets on one pattern), `:nubatch` (all selected matrices as one +non-uniform batch), `:schur` (partial factorization with a Schur block). +`matrices(M)` decides whether harness matrix `M` belongs to the feature. +`params` are set on both solvers (the names mirror cuDSS), `cudss_params` and +`sds_params` on one side only. `cudss_supported = false` marks a feature +without cuDSS counterpart. +""" +Base.@kwdef struct Feature + id::String + title::String + task::String + structure::String + matrices::Function + T::DataType = Float64 + nrhs::Int = 1 + nbatch::Int = 1 + kind::Symbol = :single + params::Dict{String, Any} = Dict{String, Any}() + cudss_params::Dict{String, Any} = Dict{String, Any}() + sds_params::Dict{String, Any} = Dict{String, Any}() + cudss_supported::Bool = true +end + +# matrix selectors +is_condensed(M) = M.source == :dump && occursin("_condensed_", M.name) +is_k2(M) = M.source == :dump && occursin("_k2_", M.name) +spd(M) = "SPD" in M.structures +sym(M) = "S" in M.structures +unsym(M) = "G" in M.structures +case1354_condensed(M) = is_condensed(M) && occursin("case1354", M.name) + +const COMPARE_FEATURES = Feature[ + Feature(id = "cholesky_f64", title = "Cholesky, Float64", task = "T13", structure = "SPD", matrices = spd), + Feature(id = "cholesky_nrhs16", title = "Cholesky, 16 right-hand sides", task = "T12", structure = "SPD", + matrices = spd, nrhs = 16), + Feature(id = "ldlt", title = "LDLᵀ, static pivoting", task = "T15", structure = "S", matrices = sym), + Feature(id = "ldlt_ir2", title = "LDLᵀ + 2 refinement steps, K2 dumps", task = "T16", structure = "S", + matrices = is_k2, params = Dict{String, Any}("ir_n_steps" => 2)), + Feature(id = "ubatch8", title = "Uniform batch of 8, Cholesky", task = "T17", structure = "SPD", + matrices = is_condensed, nbatch = 8, kind = :ubatch), + Feature(id = "lu", title = "LU, unsymmetric", task = "T19", structure = "G", matrices = unsym), + Feature(id = "schur", title = "Schur complement, Cholesky", task = "T20", structure = "SPD", + matrices = is_condensed, kind = :schur, params = Dict{String, Any}("schur_mode" => 1)), + Feature(id = "ldlt_matching", title = "LDLᵀ + matching (algo5), K2 dumps", task = "T21", structure = "S", + matrices = is_k2, params = Dict{String, Any}("matching_alg" => "algo5")), + Feature(id = "nubatch", title = "Non-uniform batch, condensed dumps", task = "T22", structure = "SPD", + matrices = is_condensed, kind = :nubatch), + Feature(id = "solve_algo1", title = "Partitioned-inverse solve (SDS algo1, cuDSS default)", task = "T25", + structure = "SPD", matrices = spd, sds_params = Dict{String, Any}("solve_alg" => "algo1")), + Feature(id = "hybrid_memory", title = "Hybrid memory mode", task = "T26", structure = "SPD", + matrices = M -> M.name == "GHS_psdef/apache2" || case1354_condensed(M), + params = Dict{String, Any}("hybrid_memory_mode" => 1)), + Feature(id = "mixed_precision", title = "Float32 factors, Float64 refinement", task = "T27", + structure = "SPD", matrices = spd, sds_params = Dict{String, Any}("factor_precision" => Float32), + cudss_supported = false), +] + +""" + feature(id) -> Feature + +The entry of [`COMPARE_FEATURES`](@ref) with this `id`. +""" +function feature(id::AbstractString) + i = findfirst(f -> f.id == id, COMPARE_FEATURES) + i === nothing && error("unknown feature \"$id\"; available: $(join((f.id for f in COMPARE_FEATURES), ", "))") + return COMPARE_FEATURES[i] +end + +const TASKS_MD = joinpath(@__DIR__, "..", "TASKS.md") +const TASK_HEADER = r"^#{2,3} (T\d\d) — .*`\[(.)\]`\s*$" + +""" + task_status(task; tasks_md = TASKS.md) -> Char + +Status marker of `task` (`"T13"`) in TASKS.md: `' '` open, `'~'` in progress, +`'x'` or `'!'` done. Errors if the task has no header. +""" +function task_status(task::AbstractString; tasks_md::AbstractString = TASKS_MD) + for line in eachline(tasks_md) + m = match(TASK_HEADER, line) + m !== nothing && m[1] == task && return only(m[2]) + end + error("$task has no header with a status marker in $tasks_md") +end + +""" + feature_implemented(f; tasks_md = TASKS.md) -> Bool + +Whether the task of feature `f` is marked done in TASKS.md. +""" +feature_implemented(f::Feature; tasks_md::AbstractString = TASKS_MD) = task_status(f.task; tasks_md) in ('x', '!') + +end # module BenchFeatures diff --git a/bench/report/Project.toml b/bench/report/Project.toml new file mode 100644 index 0000000..592e9dd --- /dev/null +++ b/bench/report/Project.toml @@ -0,0 +1,9 @@ +[deps] +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[compat] +CairoMakie = "0.15" +DelimitedFiles = "1" +Printf = "1.13" diff --git a/test/Project.toml b/test/Project.toml index 41584bd..414925d 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,9 +1,11 @@ [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Metis = "2679e427-3c69-5b7f-982b-ece356f1e94b" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" @@ -12,9 +14,11 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Adapt = "4" Aqua = "0.8" +DelimitedFiles = "1" KernelAbstractions = "0.9" LinearAlgebra = "1.13" Metis = "1" +Printf = "1.13" Random = "1.13" SparseArrays = "1.13" Statistics = "1" diff --git a/test/test_bench_compare.jl b/test/test_bench_compare.jl new file mode 100644 index 0000000..ca94142 --- /dev/null +++ b/test/test_bench_compare.jl @@ -0,0 +1,94 @@ +# The cuDSS comparison scripts (bench/features.jl, bench/compare_report.jl): the +# feature table, the TASKS.md status gate and the Markdown rendering on synthetic +# CSVs. CPU only, no solver runs, no plotting (bench/compare.jl needs a GPU or the +# bench environment and is run by hand). + +using DelimitedFiles + +include(joinpath(@__DIR__, "..", "bench", "matrices.jl")) +include(joinpath(@__DIR__, "..", "bench", "compare_report.jl")) +const BF = BenchCompareReport.BenchFeatures + +@testset "bench/features.jl: feature table" begin + feats = BF.COMPARE_FEATURES + @test allunique(f.id for f in feats) + @test all(f.structure in ("SPD", "S", "G") for f in feats) + @test all(f.kind in (:single, :ubatch, :nubatch, :schur) for f in feats) + @test all(BF.task_status(f.task) in (' ', '~', 'x', '!') for f in feats) # every task has a header + @test BF.feature("ldlt").task == "T15" + @test_throws ErrorException BF.feature("nope") + @test !feats[findfirst(f -> f.id == "mixed_precision", feats)].cudss_supported + + # every feature selects matrices from the harness (generated, SuiteSparse names, dump names) + fake(name, source, structures) = (; name, source, structures) + harness = vcat([fake(M.name, M.source, M.structures) for M in BenchMatrices.generated_matrices()], + [fake("GHS_psdef/apache2", :suitesparse, ["SPD", "S"]), fake("Rajat/rajat21", :suitesparse, ["G"]), + fake("kkt_pglib_opf_case1354_pegase_condensed_1", :dump, ["SPD", "S"]), + fake("kkt_pglib_opf_case1354_pegase_k2_1", :dump, ["S"])]) + for f in feats + @test any(M -> f.structure in M.structures && f.matrices(M), harness) + end + k2 = BF.feature("ldlt_ir2") + @test [M.name for M in harness if k2.matrices(M)] == ["kkt_pglib_opf_case1354_pegase_k2_1"] +end + +@testset "bench/features.jl: TASKS.md status gate" begin + mktempdir() do dir + path = joinpath(dir, "TASKS.md") + write(path, """ + ## T13 — Public API v0.1 `[!]` + text mentioning T15 — something `[x]` + ## T15 — GPU LDLᵀ `[ ]` + ### T25 — Performance pass `[x]` + """) + @test BF.task_status("T13"; tasks_md = path) == '!' + @test BF.task_status("T15"; tasks_md = path) == ' ' + @test BF.task_status("T25"; tasks_md = path) == 'x' + @test_throws ErrorException BF.task_status("T99"; tasks_md = path) + @test BF.feature_implemented(BF.feature("cholesky_f64"); tasks_md = path) + @test !BF.feature_implemented(BF.feature("ldlt"); tasks_md = path) + end +end + +@testset "bench/compare_report.jl: ratios and Markdown" begin + cols = ["solver", "feature", "task", "matrix", "structure", "n", "nnz", "T", "nrhs", "nbatch", + "analysis_s", "factorization_s", "refactorization_s", "solve_s", + "analysis_min_s", "factorization_min_s", "refactorization_min_s", "solve_min_s", + "lu_nnz", "flops", "nsuperpanels", "relres", "status", "device", "version", "git_sha", "date", "samples"] + row(solver, feature, matrix, t, status = "ok"; samples = "5") = + [solver, feature, "T13", matrix, "SPD", "100", "500", "Float64", "1", "1", + (status == "ok" ? fill(string(t), 8) : fill("", 8))..., (status == "ok" ? ["1000", "2.0e6", "0", "1.0e-12"] : fill("", 4))..., + status, "GPU", "0.8.0", "abc123", "2026-10-02", samples] + mktempdir() do dir + write_rows(path, rows) = open(io -> writedlm(io, [permutedims(cols); permutedims(reduce(hcat, rows))], ','), path, "w") + write_rows(joinpath(dir, "cudss.csv"), [row("cudss", "cholesky_f64", "a", 0.001), row("cudss", "cholesky_f64", "b", 0.002), + row("cudss", "ldlt", "a", 0.001)]) + write_rows(joinpath(dir, "sds.csv"), [row("sds", "cholesky_f64", "a", 0.002), row("sds", "cholesky_f64", "b", 0.008; samples = "1"), + row("sds", "cholesky_nrhs16", "a", 0.0, "NotSupportedError: not implemented yet (T99)")]) + c = read_rows(joinpath(dir, "cudss.csv")) + s = read_rows(joinpath(dir, "sds.csv")) + @test isempty(read_rows(joinpath(dir, "missing.csv"))) + @test length(c) == 3 && c[1]["matrix"] == "a" + + ratios, count = ratio_summary(BF.feature("cholesky_f64"), c, s) + @test count == 2 + @test ratios["factorization"] ≈ sqrt(2 * 4) # geometric mean of 2× and 4× + ratios, count = ratio_summary(BF.feature("ldlt"), c, s) + @test count == 0 && ratios["solve"] === nothing + + implemented = f -> f.task in ("T12", "T13") + md = sprint(io -> render_markdown(io, c, s; implemented, plot = false)) + @test occursin("| Cholesky, Float64 | T13 | done | 2 | 2.83× | 2.83× | 2.83× | 2.83× |", md) + @test occursin("| LDLᵀ, static pivoting | T15 | pending | | | | | |", md) + @test occursin("| a | 100 | 1 | 2 | 2.00× |", md) # analysis cuDSS 1 ms, SDS 2 ms + @test occursin("| a | 100 | 1 | | |", md) # ldlt: SDS cell blank + @test occursin("fail", md) && occursin("* SDS on a: NotSupportedError", md) + @test occursin("Not run yet.", md) + @test occursin("limit): SDS on b.", md) # single-run note # features without rows + @test occursin("cuDSS 0.8.0 on GPU, repository abc123, 2026-10-02.", md) + @test !occursin("comparison.png", md) + for f in BF.COMPARE_FEATURES + @test occursin("## " * f.title, md) + end + end +end