Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

cellfun – undocumented performance boost

May 11, 2009 17 Comments

Matlab’s built-in cellfun function has traditionally enabled several named (string) processing functions such as ‘isempty’. The relevant code would look like this:

data = cellfun('isempty',cellArray);

In recent years, newer Matlab releases has added support for function handles, so the previous code snippet can now be written as follows:

data = cellfun(@isempty,cellArray);

The newer function-handle format is “cleaner” and more extensive than the former format, accepting any function, not just the limited list of pre-specified processing function names (‘isreal’, ‘islogical’, ‘length’, ‘ndims’, ‘prodofsize’). Some have even reported that the older format has limitations vis-a-vis compilation etc.
All this is well known and documented. However, it turns out that, counter-intuitively (and undocumented), the older format is actually much faster than the newer format for those pre-specified processing function names. The reason appears to be that ‘isempty’ (as well as the other predefined string functions) uses specific code-branches optimized for performance:

>> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
>> tic, d=cellfun('isempty',c); toc
Elapsed time is 0.115583 seconds.
>> tic, d=cellfun(@isempty,c); toc
Elapsed time is 7.493989 seconds.

Perhaps a future Matlab release will improve cellfun’s internal code, to check for function-handle equality to the optimized functions, and use the optimized code branch if possible. When I posted this issue today as a correction to a reader’s misconception, Matlab’s Loren Shure commented as follows:
We could improve cellfun to check function handles to see if they match specified strings. Even then MATLAB would have to be careful in case the user has overridden the built-in version of whatever the string points to.
While this comment seems to imply that the performance boost feature will be maintained and possibly improved in future releases, users should note that this is not guarantied. One could even argue that future code optimizations would be applied to the new (function-handle) format rather than the old string format. The performance pendulum might also change based on user platform. Therefore, users for whom performance is critical should always test both versions on their target system: ‘isempty’ vs. @isempty etc. (note that the corresponding function for ‘prodofsize’ is @numel).

Related posts:

  1. datestr performance – Caching is a simple and very effective means to improve code performance, as demonstrated for the datestr function....
  2. HG's undocumented parameters interface – Some HG functions also accept inputs parameters in a struct fields rather than the normal P-V pairs format. ...
  3. sprintfc – undocumented helper function – The built-in sprintfc function can be used to quickly generate a cell-array of formatted strings. ...
  4. Performance: scatter vs. line – In many circumstances, the line function can generate visually-identical plots as the scatter function, much faster...
  5. More undocumented timing features – There are several undocumented ways in Matlab to get CPU and clock data...
  6. Undocumented scatter plot behavior – The scatter plot function has an undocumented behavior when plotting more than 100 points: it returns a single unified patch object handle, rather than a patch handle for each specific point as it returns with 100 or less points....
cellfun Performance Undocumented feature
Print Print
« Previous
Next »
17 Responses
  1. Ashish Sadanadnan May 11, 2009 at 16:26 Reply

    They seem to already have improved it quite a bit in R2009a; here are my results from running your code:

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
     
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.032880 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.563284 seconds.

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.032880 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.563284 seconds.

    • Yair Altman May 11, 2009 at 16:32 Reply

      Ashish – actually your results show a factor of 17 between the slower @isempty and the faster ‘isempty’, consistent with the results I posted above (my reported factor of 65 is almost the same order of magnitude as 17, and may be due to external platform-dependent factors).

      The absolute values of the results of course depend on the platform: my results were for a run-down heavily-loaded laptop… The important thing here is the factor between @isempty and ‘isempty’ – not the absolute values. And a factor of 17 is still high enough to be taken into consideration in a performance-critical application.

      • Ashish Sadanadnan May 12, 2009 at 20:54

        Yair,
        I wasn’t disputing your results. Just wanted to show that the factor has improved significantly in newer version (65 to 17). Of course, 17 times faster is still very significant as you pointed out.

        – Ashish.

  2. Naor May 11, 2009 at 18:12 Reply

    wow. that’s a pretty significant unnecessary slowdown. at least this would be easy to catch with the profiler.

  3. Loren S May 12, 2009 at 04:10 Reply

    Yair-

    As I noted to you on my blog, MATLAB doesn’t convert from FH to string method because the user might have overridden whatever the method, e.g., isempty. MATLAB could, at runtime, see if it’s overridden, and if not, call the optimized version. But it can’t do that blindly without risk of wrong answers.

    –Loren

  4. datestr performance | Undocumented Matlab October 5, 2011 at 13:17 Reply

    […] Different performance hotspots can have different solutions: caching, vectorization, internal library functions, undocumented graphics properties, smart property selection, smart function selection, smart indexing, smart parameter selection etc. […]

  5. tdc November 24, 2011 at 04:48 Reply

    I know this is old, but I just noticed it gets even worse if you use the other way of calling cellfun (which I’ve been using a lot):

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
     
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.034638 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.859156 seconds.
     
    >> tic, d=cellfun(@(x) isempty(x),c); toc
    Elapsed time is 7.961039 seconds.

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.034638 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.859156 seconds. >> tic, d=cellfun(@(x) isempty(x),c); toc Elapsed time is 7.961039 seconds.

    • Jordi Gutiérrez Hermoso November 29, 2011 at 09:30 Reply

      I looked at your example, and I noticed that in Octave we hadn’t quite optimised this as much as possible. I went ahead and committed a change to fix this:

      http://hg.savannah.gnu.org/hgweb/octave/rev/cf8cd43cdeb3

      On my laptop with Intel Core 2 Duo @ 2.20G, I see the following:

      octave:1> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
      octave:2> tic, d=cellfun('isempty',c); toc
      Elapsed time is 0.0171831 seconds.
      octave:3> tic, d=cellfun('isempty',c); toc
      Elapsed time is 0.0182698 seconds.
      octave:4> tic, d=cellfun('isempty',c); toc
      Elapsed time is 0.0223808 seconds.
       
      octave:5> tic, d=cellfun(@isempty,c); toc
      Elapsed time is 0.0193319 seconds.
      octave:6> tic, d=cellfun(@isempty,c); toc
      Elapsed time is 0.01612 seconds.
      octave:7> tic, d=cellfun(@isempty,c); toc
      Elapsed time is 0.019449 seconds.

      octave:1> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); octave:2> tic, d=cellfun('isempty',c); toc Elapsed time is 0.0171831 seconds. octave:3> tic, d=cellfun('isempty',c); toc Elapsed time is 0.0182698 seconds. octave:4> tic, d=cellfun('isempty',c); toc Elapsed time is 0.0223808 seconds. octave:5> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.0193319 seconds. octave:6> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.01612 seconds. octave:7> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.019449 seconds.

      This should be part of our 3.6 release that should happen very soon!

      Sadly, your preferred method of calling cellfun cannot be easily optimised:

      octave:8> tic, d=cellfun(@(x) isempty(x),c); toc
      Elapsed time is 0.924903 seconds.
      octave:9> tic, d=cellfun(@(x) isempty(x),c); toc
      Elapsed time is 0.873197 seconds.
      octave:10> tic, d=cellfun(@(x) isempty(x),c); toc
      Elapsed time is 0.875425 seconds.

      octave:8> tic, d=cellfun(@(x) isempty(x),c); toc Elapsed time is 0.924903 seconds. octave:9> tic, d=cellfun(@(x) isempty(x),c); toc Elapsed time is 0.873197 seconds. octave:10> tic, d=cellfun(@(x) isempty(x),c); toc Elapsed time is 0.875425 seconds.

      Note that Octave still is single-threaded, so this does not benefit from any parallelisation right now. There’s work to build parallelisation into Octave, so perhaps we can see more dramatic speedups in the future.

  6. Jordi Gutiérrez Hermoso November 29, 2011 at 07:59 Reply

    This is very interesting. Our independent implementation of cellfun in Octave actually behaves very similarly! However, I did optimise it to check function handles for built-in string cases.

    We have a thread about it:

    http://octave.1599824.n4.nabble.com/More-cellfun-related-benchmarks-td3724314.html

    • Yair Altman November 29, 2011 at 08:05 Reply

      @Jordi – thanks. If you have any other comparisons to Octave for any of the other articles here, please do post a comment.

  7. damayi May 22, 2012 at 19:48 Reply

    MATLAB 2011b result:

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.032773 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 2.100385 seconds.
     
    >> 2.100385/0.032773
    ans =
       64.0889

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.032773 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 2.100385 seconds. >> 2.100385/0.032773 ans = 64.0889

  8. How to compute effectively string length of cell array of strings | PHP Developer Resource May 28, 2012 at 21:47 Reply

    […] – I found out the reason for the speedup. It is indeed recognition of length specifically. Thanks to @reve_etrange for the […]

  9. Rody Oldenhuis July 1, 2014 at 01:32 Reply

    MATLAB R2013a result:

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.038423 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.681082 seconds.
     
    >> 0.681082/0.038423
    ans =
       17.7259

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.038423 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.681082 seconds. >> 0.681082/0.038423 ans = 17.7259

    The MathWorks don’t seem to be in a rush to optimize this…

  10. Marco Riani October 19, 2015 at 13:22 Reply

    This is what happens in R2015b:

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.011079 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.618598 seconds.

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.011079 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.618598 seconds.

    The gap is still present

  11. Carlo Monjaraz December 13, 2016 at 12:54 Reply

    R2016a :/

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.008351 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.461371 seconds.
     
    >> 0.461371 / 0.008351
    ans =
       55.2474

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.008351 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.461371 seconds. >> 0.461371 / 0.008351 ans = 55.2474

  12. Anon December 11, 2017 at 18:07 Reply

    2017b

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.011489 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.927122 seconds.
     
    >> 0.927122/0.011489
    ans =
       80.6965

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.011489 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.927122 seconds. >> 0.927122/0.011489 ans = 80.6965

  13. juanpi carbajal March 22, 2018 at 15:22 Reply

    Octave 4.2.2

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6));
    >> tic, d=cellfun('isempty',c); toc
    Elapsed time is 0.0282919 seconds.
     
    >> tic, d=cellfun(@isempty,c); toc
    Elapsed time is 0.0258329 seconds.
     
    >> 0.0258329 / 0.0282919
    ans =  0.91308

    >> c = mat2cell(1:1e6,1,repmat(1,1,1e6)); >> tic, d=cellfun('isempty',c); toc Elapsed time is 0.0282919 seconds. >> tic, d=cellfun(@isempty,c); toc Elapsed time is 0.0258329 seconds. >> 0.0258329 / 0.0282919 ans = 0.91308

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (email)
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • JCFL (1 day 8 hours ago): I was trying the above trick to change the transparency of contour lines and wondering why not all the lines have changed — then I found your post. Thanks and your post saved me.
  • Patrick Fitzgerald (3 days 12 hours ago): Just a heads up to anyone else digging around for help related to this: if you assign BackrgoundColor to a pushbutton-style uicontrol, it seems to prevent you from...
  • Vasiliy (19 days 7 hours ago): Hi Yair, i’m trying to use the MonthChooserPanel class. com.mathworks.mwswing.MJUtilit ies.initJIDE; handles.jPanel = com.jidesoft.combobox.MonthCho oserPanel;...
  • DM (19 days 7 hours ago): Hi Yair, I’m trying to use the MonthChooserPanel class. com.mathworks.mwswing.MJUtilit ies.initJIDE; handles.jPanel = com.jidesoft.combobox.MonthCho oserPanel; [handles.hPanel,...
  • Yair Altman (23 days 0 hours ago): @Alex – thanks, but keep in mind that new functions will only work on the recent Matlab releases. If your code needs to work on older Matlab releases, you could revert to...
  • Alex Churchill (23 days 0 hours ago): I was looking up how to do this exact task today. I was about to hold my nose and use the internal controllib function, when I happened to chance across a slightly newer...
  • Sebastian Hölz (29 days 6 hours ago): I have not investigated this in detail, but I think one way to go in new versions of Matlab (>2019b) might be to use listeners to suitable figure properties, e.g. fig =...
  • Prathep (29 days 9 hours ago): Hi Yair, Thanks for your introduction on Matlab Toostrip. Is there any way to add Matlab toolstrip for uifigures as you have done already for figure?
  • Josh (35 days 16 hours ago): Dear Yair, Small typo; you wrote >>Move lines up or down – CTRL + ALT + UP or DOWN allows you to move selected lines up or down but it’s actually ALT+SHIFT then UP/DOWN...
  • Yair Altman (42 days 10 hours ago): You can try to increase the Java heap memory size in the Matlab preferences (General => Java Heap Memory). Any changes to the settings will only take effect after restarting...
  • Thomas (42 days 12 hours ago): Hello, thanks for sharing! I currently receive the following memory error message when using savezip with a big object (Matlab R2020b, Windows 10). Error using...
  • Yair Altman (45 days 19 hours ago): Yerlan – either use menuItem1.setEnabled(0) or set(menuItem1,'Enabled',0)
  • Manzn (45 days 22 hours ago): Thank you man! you saved me, when there was no more light 😀
  • Yerlan (47 days 3 hours ago): Hello Mr. Altman, how can I disable menu items in the context menu? E.g. when I am trying to do this: menuItems = jmenu.getSubElements; menuItem1 = menuItems(1);...
  • Yair Altman (47 days 19 hours ago): Thanks for the note Eric – you forgot the crucial call to jTable.setLabelTable(labelTabl e) – I added it into your code snippet above.
Contact us
Undocumented Matlab © 2009 - Yair Altman
Scroll to top