A Million A Minute, in a browser?

MILAMIN's 2008 headline: one million degrees of freedom per minute in native MATLAB, pre-processing, solving and post-processing included. This page runs the browser solver from this site on your machine, live, at increasing problem size, and plots assembly-plus-solution time.

The problem is the benchmark inclusion on unstructured Triangle meshes with the 7-node Crouzeix–Raviart element. The production pipeline, supernodal Cholesky (AMD), factorizes with CHOLMOD on an AMD fill-reducing ordering, compiled to WebAssembly. The opt-in comparison line, banded Cholesky (RCM), replaces only the factorization with a plain banded Cholesky in TypeScript on a reverse Cuthill–McKee ordering; mesh, element matrices, assembly and Powell–Hestenes iterations are the same code.

Reading the plot

Two references from MILAMIN 2008 are drawn. The star is Table 2's assembly-plus-solution time at one million velocity unknowns: 15 s for matrix computation and assembly plus 34 s for solution (AMD Opteron, MATLAB 2007a). The browser curves sum the same stages, element matrices and assembly, factorization and Powell–Hestenes iterations, so the star is the like-for-like point. The dashed grey curve is Figure 5 of the paper, the total time of the mechanical test problem against size; its scope is slightly wider, the paper calls the boundary conditions and post-processing minor, and it is the only reference that shows how the 2008 time grew with size: nearly straight in this log-log plot with a slope of about 1.1. The table below the plot also reports meshing and the broader pipeline total.

This is a historical comparison across different problems and machines. The 2008 test used a box with a circular hole and an inclusion ten times more viscous than the matrix under pure shear; this page uses a disc with an inclusion a thousand times more viscous under simple shear. Both counts include the bubble velocities, although this solver condenses them before global assembly. The speed-up quoted on the million page excludes meshing, rendering and initialization on both sides; that page separately shows its five-stage total. No historical time is extrapolated to another problem size.

The banded Cholesky line is off by default; enable "include banded Cholesky" to add it, up to 30 000 unknowns. It scales as n1.9, that is O(n·hbw²) with a bandwidth of about √n, so the gap to the supernodal solver widens rapidly: the right tool for demo-sized problems and the wrong tool for a million, which is precisely why the sparse backend exists.

The supernodal solver closes that gap with the very solver MILAMIN used natively: CHOLMOD's supernodal Cholesky (the engine behind MATLAB's chol) with a fill-reducing AMD ordering, compiled to WebAssembly. The supernodal algorithm concentrates its flops in dense matrix kernels, which this build vectorizes with wasm SIMD and, on cross-origin isolated pages (this one included), spreads across worker threads. On a 2013 desktop 1.4 million unknowns take about 34 seconds single-threaded and 23 seconds with four threads, and 2.8 million unknowns complete in about a minute inside wasm's 4 GB; the status line below shows which build your browser is running. The same discrete problem, the same Powell–Hestenes iterations, verified against the banded solution to 10 digits; only the linear-solver backend differs. The thread control defaults to four rather than to everything your machine has: 2D factorizations are memory-bandwidth-bound and, as the isoefficiency law in the 2011 notes predicts, more threads soon stop helping and then hurt: in a controlled sweep a 2013 six-core desktop peaked at four threads and lost 20% with all twelve, and a 2025 phone was fastest at two.

Numbers depend on your machine; the benchmark runs on yours, in a Web Worker. The largest setting allocates several GB and needs a 64-bit browser with memory to spare. What each stage is built on is on the how it works page.