## Posts Tagged ‘performance’

### Eigen performance gotcha calling non-templated function from templated one

Tuesday, July 25th, 2017

I just spent a while tracking down a rather surprising performance bug in my code.

Here’s a minimal example:

#include <Eigen/Dense>
#include <iostream>

int simple_size(const Eigen::MatrixXi & Z)
{
return Z.size();
}

template <typename T> int templated_size(const Eigen::MatrixBase<T> & Y)
{
return simple_size(Y);
}

int main(int argc, const char * argv[])
{
const int s = 40000;
Eigen::MatrixXi X = Eigen::MatrixXi::Zero(40000,40000);
std::cout<<"Compare:"<<std::endl;
std::cout<<(X.size()         ?"done":"")<<std::endl;
std::cout<<(simple_size(X)          ?"done":"")<<std::endl;
std::cout<<(templated_size(X)?"done":"")<<std::endl;

}


Running this, it will show that the last call to templated_size is taking way too long. Inspection will show that a copy of Y is being created to create a Eigen::MatrixXi & reference.

Now, clearly it’s poor design to call a function expecting a Eigen::MatrixXi & reference with a generic templated type Eigen::MatrixBase<T> &, but unfortunately this happens quite often with legacy libigl functions. My expectation was that since T is Eigen::MatrixXi in this case a simple reference would be passed.

It’s worth noting that const is actually creating/hiding the problem. Because simple_size takes a const reference, the compiler is happy to construct a Eigen::MatrixXi on the fly to create a valid reference. Without the consts the compiler stops at an error.

### MATLAB classes are slow

Wednesday, May 7th, 2014

I was surprised to find out just how much overhead object-orient programming is in matlab. Consider this simple class:

classdef SlowWrapper < handle
properties ( Access = public )
A = [];
next = 0;
end
methods
function this = SlowWrapper(n)
this.A = zeros(n,1);
end
function set_next(this,a)
this.next = this.next+1;
this.A(this.next) = a;
end
end
end


Then if I call set_next 100000 times like this:

slow_wrapper = SlowWrapper(10e5);
tic;
for x = 1:numel(slow_wrapper.A)
slow_wrapper.set_next(x);
end
toc;


I see:

Elapsed time is 24.575752 seconds.


If instead I used primitives outside of a class and use inline code like this:

A = zeros(10e5,1);
next = 0;
tic;
for x = 1:numel(A)
next = next+1;
A(next) = x;
end
toc


I see

Elapsed time is 0.095078 seconds.


That’s a 258x slow down!

Update: Stupidly it’s slightly faster if you use the convention set_next(slow_wrapper,x); instead but only by about a 1.2x improvement.

### Fast, sparse kronecker product with identity in MATLAB

Friday, July 6th, 2012

I needed to compute:


K = kron(A,speye(n,n));


but was a little dismayed at the speed. Here’s how I get about a 6x speed up:


% Compute kron(speye(n,n),A) in a fast way
C = cell(n,1);
[C{:}] = deal(A);
K = blkdiag(C{:});
% Rearrange rows and columns
I = reshape(reshape(1:(size(A,1)*n),size(A,1),n)',size(A,1)*n,1);
J = reshape(reshape(1:(size(A,2)*n),size(A,2),n)',size(A,2)*n,1);
K = K(I,J);