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);