Skip to content

Octave micro benchmarks don't represent language characteristics #13042

Description

@oheim

Let me risk another approach on #2412 and #5128.

The Octave benchmark timings look rather extreme on your benchmark table (julialang.org). I have looked at the benchmark code and it simply does not represent how one would actually program in that language. You write that the micro benchmarks shall “give a sense how … numerical programming in that particular language is … all of the benchmarks are written to test the performance of specific algorithms, expressed in a reasonable idiom in each language”. The micro benchmark for Octave absolutely fails that pretended target.

Let me show you how I would reasonably implement the algorithms in Octave (probably also works in proprietary Matlab, but I can't check that). I haven't spend more than a minute to think about each algorithm.

  1. Fibonacci: Nobody would use a recursive algorithm in Octave if you can preallocate the memory and compute the number in a loop.
  2. Parseint: Why use a loop when vectorization is trivial?
  3. Mandelbrot set: Meshgrid is a typical function for creation of a 2D set. Again, vectorization is trivial if indexing is used. Indexing is a key language concept in Octave.
  4. Quicksort: The algorithm is much short, easier and faster if indexing and recursion is used instead of in-place computation with loops.
  5. Pisum and printfd: Again, vectorization is a key language concept that almost all functions support. Not using it shows that the programmer has no clue how Octave works.

Could you please clarify what the actual purpose of your benchmarks is? I would be fine with the benchmarks saying: Loops and recursion in Octave are slow. However, the benchmark table suggests that, e.g., computing the Mandelbrot set in Octave is much slower than it actually is.

diff --git a/test/perf/micro/perf.m b/test/perf/micro/perf.m
index 6c6a846..2a1fadb 100644
--- a/test/perf/micro/perf.m
+++ b/test/perf/micro/perf.m
@@ -32,9 +32,9 @@ function perf()
        assert(issorted(sortperf(5000)))
        timeit('quicksort', @sortperf, 5000)

-       s = pisum(true);
+       s = pisumvec(true);
        assert(abs(s-1.644834071848065) < 1e-12);
-       timeit('pi_sum',@pisum, true)
+       timeit('pi_sum',@pisumvec, true)

        %s = pisumvec(true);
        %assert(abs(s-1.644834071848065) < 1e-12);
@@ -80,25 +80,29 @@ function timeit(name, func, varargin)
 end

 %% recursive fib %%
+%% (the function definition is recursive, but the algorithm uses a loop) %%

-function f = fib(n)
-    if n < 2
-        f = n;
+function f = fib (n)
+    if n <= 0
+        f = 0;
         return
-    else
-        f = fib(n-1) + fib(n-2);
     end
+    
+    f = ones (1, n);
+    for k = 3 : n
+        f(k) = f(k-2) + f(k-1);
+    end
+    f = f(n);
 end

 %% parse int %%
+%% create t random uint32 numbers, convert them all to hex and parse them %%

-function n = parseintperf(t)
-    for i = 1:t
-        n = randi([0,2^32-1],1,'uint32');
-        s = dec2hex(n);
-        m = hex2dec(s);
-        assert(m == n);
-    end
+function n = parseintperf (t)
+    n = randi ([intmin('uint32'), intmax('uint32')], t, 1, 'uint32');
+    s = dec2hex (n);
+    m = hex2dec (s);
+    assert (m == n);
 end

 %% matmul and transpose %%
@@ -109,60 +113,44 @@ end

 %% mandelbrot set: complex arithmetic and comprehensions %%

-function n = mandel(z)
-    n = 0;
+function n = mandel (z)
+    n = zeros (size (z));
     c = z;
-    for n=0:79
-        if abs(z)>2
-            return
+    for k = 1 : 80
+        idx = abs (z) <= 2;
+        if any (any (idx))
+            n(idx) ++;
+            z(idx) = z(idx) .^ 2 + c(idx);
+        else
+            break
         end
-        z = z^2+c;
     end
-    n = 80;
 end

 function M = mandelperf(ignore)
-  M = zeros(length(-2.0:.1:0.5), length(-1:.1:1));
-  count = 1;
-  for r = -2:0.1:0.5
-    for i = -1:.1:1
-      M(count) = mandel(complex(r,i));
-      count = count + 1;
-    end
-  end
+  [r, i] = meshgrid (-2 : .1 : 0.5, -1 : .1 : 1);
+  M = mandel (complex (r, i));
 end

 %% numeric vector quicksort %%

-function b = qsort(a)
-    b = qsort_kernel(a, 1, length(a));
-end
-
-function a = qsort_kernel(a, lo, hi)
-    i = lo;
-    j = hi;
-    while i < hi
-        pivot = a(floor((lo+hi)/2));
-       while i <= j
-              while a(i) < pivot, i = i + 1; end
-              while a(j) > pivot, j = j - 1; end
-              if i <= j
-                t = a(i);
-                a(i) = a(j);
-                a(j) = t;
-                i = i + 1;
-                j = j - 1;
-                     end
-       end
-        if lo < j; a=qsort_kernel(a, lo, j); end
-        lo = i;
-           j = hi;
+function b = qsort (a)
+    if length (a) <= 1
+        b = a;
+        return
     end
+    
+    pivot = a(1);
+    lo = a <= pivot;
+    hi = a >= pivot;
+    % keep pivot out of lo and hi
+    lo(1) = hi(1) = false;
+    b = vertcat (qsort (a(lo)), pivot, qsort (a(hi)));
 end

-function v = sortperf(n)
-    v = rand(n,1);
-    v = qsort(v);
+function v = sortperf (n)
+    v = rand (n, 1);
+    v = qsort (v);
 end

 %% slow pi series %%
@@ -180,7 +168,7 @@ end
 %% slow pi series, vectorized %%

 function s = pisumvec(ignore)
-    a = [1:10000]
+    a = [1:10000];
     for j=1:500
         s = sum( 1./(a.^2));
     end
@@ -224,10 +212,8 @@ end

 %% printf %%

-function printfd(n)
-    f = fopen('/dev/null','w');
-    for i = 1:n
-        fprintf(f, '%d %d\n', i, i);
-    end
-    fclose(f);
+function printfd (n)
+    f = fopen ('/dev/null', 'w');
+    fprintf (f, '%d %d\n', 1:n, (1:n)+1);
+    fclose (f);
 end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions