13

Optimizing my MATLAB code, I stumbled upon a weird problem regarding anonymous functions.

Like in this thread I realized, that sometimes anonymous functions are running really slow. But with minimal changes to the function, it runs as fast as subfunctions or nested functions.

I used this (simple) test file to reproduce the behaviour with Matlab R2010b under Windows 7 64-bit:

clear all; close all; clc;

% functions
fn1 = @(x) x^2;
fn2 = @(x) double(x^2);

% variables
x = linspace(-100,100,100000);
N = length(x);

%% anonymous function
y = zeros(1,N);
t = tic;
for i=1:N
    y(i) = fn1(x(i));
end
tm.anonymous_1 = toc(t);

%% anonymous function (modified)
y = zeros(1,N);
t = tic;
for i=1:N
    y(i) = fn2(x(i));
end
tm.anonymous_2 = toc(t);

%% print
tm

The results I got were:

tm = 

    anonymous_1: 1.0605
    anonymous_2: 0.1217

As you can see the first approach is about 10 times slower. I have no idea what triggers this speedup/slowdown. I tried different things, getting nearly the same (fast) timings:

fn2 = @(x) 1 * x^2;
fn2 = @(x) 0 + x^2;
fn2 = @(x) abs(x^2);
fn2 = @(x) x*x;


Before I start profiling all of my functions, I would like to know if anyone has an explanation for this behaviour?


P.S.: I know that "vectorized" approaches are much faster, but in my case a solver will be evaluating the function for each variable time step, so that is not an option.

4
  • 3
    Did you try switching fn1 and fn2? I wonder if Matlab optimizes the second function, after having performed the operations in the first function. Commented Mar 19, 2011 at 3:01
  • 2
    No, that doesn't help. If you make fn1 = fn2 = @(x) x^2 they're both slow and take the same time; if you make fn1 = fn2 = @(x) double(x^2) or fn1 = fn2 = @(x) 1 * x^2; they're both fast. It's quite curious, +1 for the question. It is something about fn1 = @(x) x^2 that is slow. Commented Mar 19, 2011 at 5:22
  • fn1 = @(x) int64(x^2); or fn1 = @(x) double(int64(x^2)); are even slower. Commented Mar 19, 2011 at 9:31
  • 2
    if you write a Matlab function, that gets compiled. If you write a Matlab script, that doesn't get compiled. Instead of writing inline/anonymous functions, make them into standalone functions (no matter how small or silly), and they should pick up speed. Commented Mar 22, 2011 at 17:51

2 Answers 2

9

It appears that in the case of 'fn2' the Matlab optimizer is able to inline the function, whereas it is unable to do so in the case of 'fn1'.

This probably has to do with what Matlab knows about the scalarity or complexity or structure of the argument and return value. It probably figures out that 'i' (the argument at the call-site) is necessarily scalar, real and non-strctured. Given a scalar argument it then tries to figure out the behaviour of the function. In the case of 'fn2' Matlab's optimizer statically determines that it can always fit all possible results of 'double()' into the target variable 'y(i)'. For some reason only known to the designers of the optimizer, Matlab is unable to come to the same conclusion for 'fn1'. Maybe there are some non-obvious corner-cases, or '^' lacks some piece of meta-data that the optimizer depends on. Anyway, the result is that in case of 'fn1' Matlab apparently re-evaluats the function at every iteration.

Anyway, statically optimizing dynamic languages is something of a black art in compiler design.

Sign up to request clarification or add additional context in comments.

2 Comments

It also happens with much more complex functions. But in all the cases an explicit typecast to double speeded things up. After all I think it's best to stay with nested functions for time critical applications to prevent such problems.
@Brainy: Double is an accelerated data type according to this source. These slides on optimization are also helpful. I'm not sure how the first function allocates its variables.
1

I believe that making the return type of a function independent of its argument's types makes it easier for Matlab to optimize. By the way, y = fn1(x); and y = fn2(x); have roughly the same proportion in terms of run time, so it's not the effect of arguments being scalar or complex.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.