Benchmark results for several implementations of the moving sum of squares (MSS):

  • sequential, adapted from SleepECG
    • MSSi,k=MSSi1,k+xi+k122xik212MSS_{i,k} = MSS_{i-1,k} + x_{i+ \lfloor \frac{k-1}{2} \rfloor }^2 - x_{i - \lfloor \frac{k}{2} \rfloor - 1}^2,
    • Work=O(n)Work = O(n),
    • Span=O(n)Span = O(n),
  • parallel, but work-inefficient relative to the sequential algorithm
    • MSSi,k=j=ik2i+k12xj2MSS_{i,k} = \sum_{j=i-\lfloor \frac{k}{2} \rfloor}^{i+ \lfloor \frac{k-1}{2} \rfloor} x_j^2,
    • Work=O(nk)Work = O(n\,k),
    • Span=O(k)Span = O(k),

where n is signal length, k is window length and 0<kn0 < k \leq n.

The source code:

The benchmarks were performed on an Intel® Core™ i7-12700 with 16 GiB of RAM and AMD Radeon™ RX 6600 XT. Data type: float64.

  • Futhark: 0.25.22. Backends: C, Multicore, OpenCL (GPU).
  • Julia: 1.10.5.
  • Mojo: 24.4.
  • Elixir: 1.16.2. Erlang: 26.2.5. Backend: EXLA (CPU, JIT).
  • C++: GCC 14.2.1, OpenMP: 4.5 (CPU), ArrayFire: 3.9.0 (OpenCL, GPU).

Mean runtime vs. signal length for window length = 32 samples

Sequential

Signal length [samples]MojoC++Futhark CJuliaElixir EXLA
2,0481.7 μs1.7 μs2.0 μs2.2 μs22 μs
4,0963.4 μs3.5 μs3.8 μs4.4 μs50 μs
8,1926.9 μs6.9 μs7.4 μs8.7 μs69 μs
16,38414 μs14 μs15 μs17 μs0.12 ms
32,76827 μs27 μs29 μs34 μs0.29 ms
65,53655 μs55 μs58 μs69 μs0.53 ms
131,0720.11 ms0.11 ms0.12 ms0.14 ms1.0 ms
262,1440.22 ms0.22 ms0.23 ms0.28 ms1.9 ms
524,2880.44 ms0.44 ms0.46 ms0.59 ms3.9 ms
1,048,5760.88 ms0.89 ms0.97 ms1.2 ms7.2 ms
2,097,1521.8 ms1.9 ms2.0 ms2.4 ms15 ms
4,194,3043.8 ms3.9 ms4.0 ms4.8 ms28 ms
8,388,6087.8 ms7.8 ms7.9 ms9.5 ms56 ms
16,777,21616 ms16 ms16 ms19 ms0.11 s
33,554,43231 ms31 ms32 ms38 ms0.22 s
67,108,86462 ms62 ms62 ms76 ms-

Parallel (CPU)

Signal length [samples]JuliaC++ OpenMPMojoFuthark MulticoreElixir EXLA
2,04814 μs15 μs6.0 μs9.0 μs22 μs
4,09616 μs16 μs7.3 μs13 μs27 μs
8,19219 μs18 μs8.5 μs21 μs42 μs
16,38418 μs22 μs13 μs35 μs68 μs
32,76830 μs29 μs20 μs80 μs0.15 ms
65,53639 μs43 μs38 μs0.12 ms0.28 ms
131,07281 μs73 μs71 μs0.11 ms0.46 ms
262,1440.13 ms0.13 ms0.14 ms0.21 ms0.79 ms
524,2880.27 ms0.25 ms0.27 ms0.39 ms1.5 ms
1,048,5760.66 ms0.51 ms0.54 ms0.78 ms3.1 ms
2,097,1521.3 ms1.2 ms1.1 ms2.2 ms6.1 ms
4,194,3043.0 ms3.4 ms4.1 ms5.5 ms12 ms
8,388,6085.7 ms6.8 ms8.2 ms11 ms23 ms
16,777,21611 ms14 ms16 ms22 ms43 ms
33,554,43225 ms26 ms32 ms43 ms75 ms
67,108,86445 ms51 ms65 ms84 ms-

Parallel (GPU)

Signal length [samples]Futhark (OpenCL)C++ ArrayFire (OpenCL)
2,04830 μs28 μs
4,09630 μs28 μs
8,19230 μs29 μs
16,38432 μs31 μs
32,76836 μs37 μs
65,53644 μs44 μs
131,07250 μs59 μs
262,14473 μs88 μs
524,2880.11 ms0.15 ms
1,048,5760.19 ms0.27 ms
2,097,1520.47 ms0.66 ms
4,194,3041.0 ms1.3 ms
8,388,6081.9 ms2.6 ms
16,777,2163.9 ms4.9 ms
33,554,4327.7 ms9.9 ms
67,108,86415 ms19 ms

Mean runtime vs. window length for signal length = 50 × 10⁶ samples

Sequential

Window length [samples]C++MojoFuthark CJuliaElixir EXLA
146 ms47 ms47 ms56 ms0.17 s
246 ms47 ms47 ms57 ms0.24 s
447 ms46 ms46 ms57 ms0.34 s
846 ms46 ms47 ms57 ms0.32 s
1646 ms46 ms47 ms57 ms0.32 s
3246 ms47 ms47 ms56 ms0.35 s
6446 ms46 ms46 ms57 ms0.35 s
12846 ms46 ms46 ms57 ms0.40 s
25646 ms46 ms46 ms56 ms0.64 s
51246 ms46 ms47 ms57 ms0.97 s
1,02446 ms46 ms47 ms57 ms1.7 s
2,04846 ms47 ms47 ms57 ms2.9 s

Parallel (CPU)

Window length [samples]JuliaC++ OpenMPMojo (CPU)Elixir EXLAFuthark Multicore
129 ms32 ms34 ms35 ms55 ms
229 ms33 ms36 ms77 ms57 ms
430 ms33 ms39 ms79 ms59 ms
833 ms34 ms37 ms88 ms60 ms
1631 ms36 ms42 ms0.11 s60 ms
3234 ms39 ms48 ms0.11 s64 ms
6441 ms50 ms62 ms0.16 s0.10 s
12853 ms76 ms98 ms0.20 s0.22 s
25678 ms0.12 s0.17 s0.34 s0.44 s
5120.17 s0.24 s0.32 s0.62 s0.88 s
1,0240.26 s0.45 s0.61 s1.2 s1.7 s
2,0480.51 s0.85 s1.2 s2.3 s3.5 s

Parallel (GPU)

Window length [samples]C++ ArrayFire (OpenCL)Futhark (OpenCL)
17.4 ms7.3 ms
27.6 ms7.4 ms
47.7 ms7.3 ms
88.1 ms7.3 ms
1610.0 ms8.2 ms
3214 ms11 ms
6424 ms18 ms
12843 ms30 ms
2560.17 s55 ms
5120.17 s0.10 s
1,0240.17 s0.20 s
2,0480.17 s0.40 s

Conciseness of the source code

ImplementationNumber of non-whitespace tokensCompressed size (LZMA) [B]
Futhark sequential278434
Futhark parallel109266
Julia sequential208472
Julia parallel (CPU)132409
C++ sequential347593
C++ parallel (CPU)254629
C++ parallel (GPU)138422
Elixir+Nx sequential431713
Elixir+Nx parallel145424
Mojo sequential353565
Mojo parallel (CPU)249540