Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB: Performance problem with anonymous functions

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.

like image 281
Brainy Avatar asked Mar 19 '11 02:03

Brainy


1 Answers

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.

like image 198
edgar.holleis Avatar answered Nov 16 '22 02:11

edgar.holleis