Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
#include <math.h> slows things way down?

Subject: #include <math.h> slows things way down?

From: Matt Fig

Date: 10 Feb, 2009 00:38:01

Message: 1 of 6

Hello,

I am going over an example I got out of a book. The example shows one way of MEXing the following code:

function [c] = countm(A,B)
% Count the number of times elements of A appear in B.
c = zeros(size(A));
for ii = 1:numel(A)
    c(ii) = sum(abs(A(ii)-B(:)) < eps);
end

The point of this thread isn't to optimize this Matlab code, I put the Matlab version in here so an experienced Matlaber can tell at a glance what is going on with the MEX-File....

The MEX-File that the author shows is much slower than the Matlab code, so I tried to speed it up by changing some things. I found that the main source of drag is from using the fabs function from the math C++ library. Here are timing results with his code as is:

N = 120;
a = round(rand(N)*10);
b = round(rand(N)*10);
tic,cpp = count(a,b);toc % The c++ code is called count.cpp
Elapsed time is 11.867683 seconds. % WOW!!
tic,mtlb = countm(a,b);toc
Elapsed time is 3.743850 seconds.


And here is the MEX-File

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#include <math.h>
#include "mex.h"

#define A prhs[0] /* Pointer to first right-hand-side argument */
#define B prhs[1] /* Pointer to second right-hand-side argument */
#define TOL prhs[2] /* Pointer to third right-hand-side argument */
#define C plhs[0] /* Pointer to first left-hand-side argument */

void mexFunction( int nlhs, mxArray *plhs[],
                   int nrhs, const mxArray *prhs[] )
{
    int i, j, sizea, sizeb;
    double tol, vcount;
    double *a, *b, *c;

    /* Do some error checking */
    if (nrhs < 2)
        mexErrMsgTxt("Missing input arguments.");
    else if (nrhs > 3)
        mexErrMsgTxt("Too many input arguments.");
    else if (nlhs > 1)
        mexErrMsgTxt("Too many output arguments.");

    /* Get tolerance value if supplied, otherwise use EPS. */
    if (nrhs == 3) {
        if (!mxIsNumeric(TOL) || mxIsComplex(TOL) ||
            mxGetNumberOfElements(TOL) != 1 )
            mexErrMsgTxt("TOL must be a real numeric scalar.");
        tol = mxGetScalar(TOL);
        if (tol < mxGetEps())
            mexErrMsgTxt("TOL must be a positive value.");
    }
    else
        tol = mxGetEps();
    
    /* Make sure input arrays are non-complex numeric arrays. */
    if (!mxIsNumeric(A) || !mxIsNumeric(B) ||
        mxIsComplex(A) || mxIsComplex(B))
        mexErrMsgTxt("Input arguments must be real of type double.");

    /* Create the output mxArray the same size as A */
    C = mxCreateNumericArray(mxGetNumberOfDimensions(A),
          mxGetDimensions(A), mxDOUBLE_CLASS, mxREAL);

    /* Get the number of elements in A and B and create pointers */
    /* to the input and output arrays. */
    sizea = mxGetNumberOfElements(A);
    sizeb = mxGetNumberOfElements(B);
    a = (double *) mxGetPr(A);
    b = (double *) mxGetPr(B);
    c = (double *) mxGetPr(C);

    /* Cycle through the elements of the arrays and count values */
    for (i = 0; i < sizea; i++)
    {
        vcount = 0.0;
        for (j = 0; j < sizeb; j++)
            // We can either use the next two lines, or everyting between
            // the next set of braces. Must uncomment include math.h above.
            if ((fabs(a[i] - b[j])) <= tol)
            vcount++;
// { // For the math library version, use above two lines instead.
// if (a[i]>b[j])
// {
// if (a[i]-b[j] < tol)
// vcount++;
// }
// else
// {
// if (b[j]-a[i] < tol)
// vcount++;
// }
// } // This is the matching brace for the above comment.
        c[i] = vcount;
    }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

When I took out the include <math.h>, and used the lines that are commented instead of the fabs call at the end of the function, I got some different timings. Here they are:

Elapsed time is 1.171837 seconds. % Borland Compiler (LCC gives 2.3 seconds)
Elapsed time is 3.770942 seconds.


So my question is this: Is the price for using standard functions always so high? I was expecting a little bit of difference, but not that much. So what is going on here?
By the way, this is out of Mastering Matlab 7.

Thanks.

Subject: #include <math.h> slows things way down?

From: James Tursa

Date: 10 Feb, 2009 08:09:01

Message: 2 of 6


I can't answer your question, but here are some relative timings for comparison on a WinXP machine (median of last 3 runs of a total of 4 runs):

>> tic,mtlb = countm(a,b);toc
Elapsed time is 3.078500 seconds.

>> tic,cpp = count(a,b);toc % lcc compiler, with the math.h and fabs
Elapsed time is 14.045623 seconds.

>> tic,cpp = count1(a,b);toc % lcc compiler, your other method
Elapsed time is 3.445705 seconds.

>> tic,cpp = count(a,b);toc % VC 8.0, with the math.h and fabs
Elapsed time is 0.818456 seconds.

>> tic,cpp = count1(a,b);toc % VC 8.0, your other method
Elapsed time is 1.939773 seconds.

So at least on my machine the problem is with the lcc compiler, not math.h and fabs in general. The mex routine with math.h and fabs using VC 8.0 was clearly the fastest. This matches quite a bit of my past experience with the lcc compiler. It is nice of TMW to include a C compiler along with their product, but lcc is often an order of magnitude or more slower than VC for comparisons I have made in the past.

James Tursa

Subject: #include <math.h> slows things way down?

From: Rune Allnor

Date: 10 Feb, 2009 09:04:44

Message: 3 of 6

On 10 Feb, 01:38, "Matt Fig" <spama...@yahoo.com> wrote:
> Hello,
>
> I am going over an example I got out of a book.
...
> So my question is this: =A0Is the price for using standard functions alwa=
ys so high? =A0

The same function (fabs()) is at the core of the matlab function,
if matlab is programmed in C or C++. Or in a language based
on C or C++.

You need to know how the programming *systems* C and C++ are
set up, to see the cause: The C and C++ programming systems
contain two main parts:

- Programming languages
- Additional libraries

The C and C++ programming languages are very small. They used
to be little more than 'elaborate' assembly; that is, they work
close to the binary architecture (but not as close as assembly)
while including some higher-level functionality (but not as much
as pascal, fortran or matlab).

The core language is anything you can do in C or C++ without
using any #include directives. Which isn't much.

The core languages, which are small, are extended by using
libraries. The standard libraries are standardized in terms
of what functionality they are required to provide, but are
not part of the language as such. These days just about all
the vendors supply brand-specific libraries in addition to
the standard libs.

It is the compiler vendor's responsibility to implement the
functionality required by the standrad libraries. And here,
the different brands of compilers can differ quite dramatically,
depending on the time and skills invested in any library:

- Some only wants minimum functionality and use naive methods
- Some emphasize accuracy and use slower methods
- Some emphasize speed and use less accurate methods
- Some provide CPU-specific methods
- Some provide generic methods

and so on. Just like with matlab, the programmers must
prioritize between several goals, which means their
code perform differently.

So you just have to test your different libraries and see
how well they perform. LCC is a minimum functionality,
inexpensive compiler so don't expect too much of it or
the libraries supplied with it.

Rune

Subject: #include <math.h> slows things way down?

From: Rune Allnor

Date: 10 Feb, 2009 09:25:53

Message: 4 of 6

On 10 Feb, 01:38, "Matt Fig" <spama...@yahoo.com> wrote:

> Elapsed time is 1.171837 seconds. % Borland Compiler (LCC gives 2.3 secon=
ds)
> Elapsed time is 3.770942 seconds.
>
> So my question is this: =A0Is the price for using standard functions alwa=
ys so high? =A0I was expecting a little bit of difference, but not that muc=
h. =A0So what is going on here?

When writing my first reply I missed the fact that
you use a Borland compiler. With the Borland you
have access to a C++ compiler, which might make a
difference.

Try this:

1) Change the filename extension to .cpp
2) Change the #include <math.h> to
   #include <cmath>

and test again. By changing the file name you force
the code to be compiled as C++ (not C) code, and
the <cmath> library takes advantage of certain
C++-specific features.

I suspect that you will find timings closer to the
no-library code this time.

The reason why the first attempt using libraries is
so much slower than the naive code, is that the C
library functionality is provided as fully compiled
object code in a separate translation unit, that
links into the executable. This means that there
is a run-time overhead involved in the function call
between translation units, which becomes significant
when the function is as small as fabs().

With C++ the libraries are usually provided as
templates, which is a 'code fragment' that is compiled
as part of the user's code. This has two advantages
over C:

1) The slow function call across translation units is
   eliminated
2) The code can be optimized more agressively

Item 1) will certainly be significant if you comile this
as C++. I doubdt item 2) will be in this particular case,
but I might be wrong. If you get faster times than with
the naive no-library code, there was an additional
optimization benefit.

Rune

Subject: #include <math.h> slows things way down?

From: Matt Fig

Date: 10 Feb, 2009 16:18:01

Message: 5 of 6

Thanks to James and Rune for replying, I was hoping at least one of you two would see this thread.

To Rune,

I already had the file as count.cpp when using Borland. When I tried your suggestion, i.e. changing

#include <math.h>
to
#include <cmath>

I get compile errors, most notably all the errors are in matrix.h and mex.h except for two:

Error E2268 count.cpp 29: Call to undefined function 'mxGetNumberOfElements' in function mexFunction(int,mxArray_tag * *,int,const mxArray_tag * *)
Error E2268 count.cpp 62: Call to undefined function 'fabs' in function mexFunction(int,mxArray_tag * *,int,const mxArray_tag * *)

Figuring that maybe the function in cmath is called abs instead of fabs, I made this change then the second error went away. Here are the rest of the compile errors:

Error E2147 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 282: 'size_t' cannot start a parameter declaration
Error E2147 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 290: 'size_t' cannot start a parameter declaration
Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 291: Type name expected
Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 304: Type name expected
Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 628: Declaration syntax error
Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 739: Declaration syntax error
Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 751: Declaration syntax error
Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 801: Declaration syntax error
Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\mex.h 82: Type name expected
Error E2139 C:\PROGRA~1\MATLAB\R2007a\extern\include\mex.h 82: Declaration missing ;

Can you tell where I am going wrong here? Thanks.

Subject: #include <math.h> slows things way down?

From: Rune Allnor

Date: 10 Feb, 2009 16:57:57

Message: 6 of 6

On 10 Feb, 17:18, "Matt Fig" <spama...@yahoo.com> wrote:
> Thanks to James and Rune for replying, I was hoping at least one of you t=
wo would see this thread.
>
> To Rune,
>
> I already had the file as count.cpp when using Borland. =A0When =A0I trie=
d your suggestion, i.e. changing
>
> #include <math.h>
> to
> #include <cmath>
>
> I get compile errors, most notably all the errors are in matrix.h and mex=
.h except for two:
>
> Error E2268 count.cpp 29: Call to undefined function 'mxGetNumberOfElemen=
ts' in function mexFunction(int,mxArray_tag * *,int,const mxArray_tag * *)
> Error E2268 count.cpp 62: Call to undefined function 'fabs' in function m=
exFunction(int,mxArray_tag * *,int,const mxArray_tag * *)
>
> Figuring that maybe the function in cmath is called abs instead of fabs, =
I made this change then the second error went away. =A0Here are the rest of=
 the compile errors:
>
> Error E2147 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 282: 'size_=
t' cannot start a parameter declaration
> Error E2147 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 290: 'size_=
t' cannot start a parameter declaration
> Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 291: Type n=
ame expected
> Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 304: Type n=
ame expected
> Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 628: Declar=
ation syntax error
> Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 739: Declar=
ation syntax error
> Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 751: Declar=
ation syntax error
> Error E2141 C:\PROGRA~1\MATLAB\R2007a\extern\include\matrix.h 801: Declar=
ation syntax error
> Error E2303 C:\PROGRA~1\MATLAB\R2007a\extern\include\mex.h 82: Type name =
expected
> Error E2139 C:\PROGRA~1\MATLAB\R2007a\extern\include\mex.h 82: Declaratio=
n missing ;
>
> Can you tell where I am going wrong here? =A0Thanks.

Haven't seen those before.

It's been a few years since I used the Borland compiler,
but below is the start of the last file I compiled with it.
Except for the indicated line, I can't see much difference
from what you do.

Try and compile the .cpp example file distributed
with matlab. If that doesn't compile, there is a problem
with your compiler set-up. If it does, there is a problem
with your code.

You can also try and delete any files generated by the
compiler before attempting to compile.

Rune

///////////////////////////////////////////
#include "mex.h"
#include "matrix.h"

#include <ctype.h>

extern void __main(); // <<<=3D=3D=3D=3D=3D=3D

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us