I tried element-wise sum, and got
julia> using LoopVectorization, BenchmarkTools
julia> A = rand(10_000, 10_000); B = rand(10_000, 10_000); C = similar(A);
julia> @benchmark vmapntt!(+, $C, $A, $B)
BenchmarkTools.Trial:
memory estimate: 13.19 KiB
allocs estimate: 91
--------------
minimum time: 29.103 ms (0.00% GC)
median time: 29.202 ms (0.00% GC)
mean time: 29.329 ms (0.00% GC)
maximum time: 30.658 ms (0.00% GC)
--------------
samples: 171
evals/sample: 1
While with NumPy
>>> import timeit
>>> u = timeit.Timer("A + B", setup='import numpy as np; A = np.random.rand(10_000, 10_000); B = np.random.rand(10_000,10_000)')
>>> u.repeat(10, 1)
[0.17918606100283796, 0.17888473700440954, 0.17893354399711825, 0.1790916720055975, 0.17922663199715316, 0.17935074500564951, 0.17939399600436445, 0.17940548500337172, 0.17933111900492804, 0.17920518800383434]
A 6x advantage for Julia. If I don't use multithreading, Julia slows down to 122.5ms, or about 1.5x faster.
Elementwise multiplication is the same fast.
If I get a little more creative and do
exp(A) + log(B) instead, multithreaded Julia still takes 30ms, while single threaded slows down to 169ms.
Meanwhile, NumPy slowed down to 847ms, making it 30x slower than multithreaded Julia (on my computer) and 5x slower than single threaded.
Shall I keep making programs more complicated?