Nested Functions vs Object-Oriented Programming: k-D Tree example and relative performance
18 views (last 30 days)
Jacob Lynch August on 13 Aug 2020
My colleagues tend to criticize my use of nested functions in MATLAB, likening that to the professional no-no of modifying global variables. To placate those peers, I'll recode those methods that use nested functions into a handle-based object-oriented methods. Now, they accept that the current properties are accessible to the object's methods.
However, I have a specific instance where the nested functions implementation outperforms the handle-based object-oriented programming style: k-D Trees.
Using nested subfunctions. https://www.mathworks.com/matlabcentral/fileexchange/79101-ikdtree
Using subclass of handle. https://www.mathworks.com/matlabcentral/fileexchange/79104-kdtree
Here is the benchmark code run from the command window.
pdat = randn(130001,3); % position data
tic;a_tree = kDTree(pdat); disp(toc) % 9.0822 seconds
tic;i_tree = ikdtree(pdat);disp(toc) % 1.0869 seconds
I'm seeking insights into what is causing these performance differences.
per isakson on 14 Aug 2020
Edited: per isakson on 14 Aug 2020
On my R2018b,Win10 the diffence is even bigger
% 18.585, 0.79143
% 18.937, 0.75923
The profiling result of get_root_index shows
that assigning values to the properties, LeftIndices and RightIndices, takes nearly all the time.
It's a known fact that assigning values to properties is slow in Matlab. See Is MATLAB OOP slow or am I doing something wrong? and Numerical operations are slow on class properties versus in workspace.
The execution engine (/JIT) is The Mathworks' trade secret.
More Answers (1)
Olaf Constantin Schmidtmann on 3 May 2022
Even in R2022a, the performance gap between these two is quite huge on my machine (MACI64). This contradicted my results of Andrew Janke’s matlab-bench and I wondered why.
Without digging too deep into the functions themselves, I found that the OOP version (subclass of handle) uses property validation, which is expensive at this point. Hence, the comparison is a bit unfair. ;)
If you remove the validation (lines 11-14), like so:
properties (SetAccess = protected)
LeftIndices %(:, 1)
RightIndices %(:, 1)
… the tables turned on my machine; the OOP version was even a bit faster:
OOP (kDTree, original): Elapsed time is 5.630146 seconds.
OOP (kDTree, no validation of indices): Elapsed time is 0.579906 seconds.
Nested (ikdtree): Elapsed time is 0.641538 seconds.
You may add a dependent variable for subclasses to keep the validation. Also you might compare a custom validation in the nested version…
Btw, I do not believe, that OOP is a silver bullet, but there is clearly more to the decision than performance issues.