changeset 11997:5530fe42c83b release-3-2-x

update coding tips
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 18 Jun 2009 07:09:17 +0200
parents 8c2a1c876c2c
children abe4d6657872
files doc/ChangeLog doc/interpreter/tips.txi
diffstat 2 files changed, 109 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2009-06-16  Jaroslav Hajek  <highegg@gmail.com>
+
+	* interpreter/tips.txi: Update.
+
 2009-06-07  Rik  <rdrider0-list@yahoo.com>
 
 	* interpreter/plot.txi: Update some of Advanced Plotting documentation.
--- a/doc/interpreter/tips.txi
+++ b/doc/interpreter/tips.txi
@@ -85,14 +85,83 @@
 
 @itemize @bullet
 @item
-Avoid looping wherever possible.
+Vectorize loops. For instance, rather than
+@example
+for i = 1:n-1
+  a(i) = b(i+1) - b(i);
+endfor
+@end example
+
+write
+
+@example
+a = b(2:n) - b(1:n-1);
+@end example
+
+This is especially important for loops with "cheap" bodies. Often it suffices to vectorize
+just the innermost loop to get acceptable performance. A general rule of thumb is that the
+"order" of the vectorized body should be greater or equal to the "order" of the enclosing loop.
+
+@item
+Use built-in and library functions if possible. Built-in and compiled functions are very fast.
+Even with a m-file library function, chances are good that it is already optimized, or will be
+optimized more in a future release.
+
+@item
+Avoid computing costly intermediate results multiple times. Octave currently
+does not eliminate common subexpressions.
 
 @item
-Use iteration rather than recursion whenever possible.
-Function calls are slow in Octave.
+Be aware of lazy copies (copy-on-write). When a copy of an object
+is created, the data is not immediately copied, but rather shared. The actual
+copying is postponed until the copied data needs to be modified. For example:
+
+@example
+a = zeros (1000); # create a 1000x1000 matrix
+b = a; # no copying done here
+b(1) = 1; # copying done here
+@end example
+
+Lazy copying applies to whole Octave objects such as matrices, cells, struct,
+and also individual cell or struct elements (not array elements).
+
+Additionally, index expressions also use lazy copying when Octave can determine
+that the indexed portion is contiguous in memory. For example:
+
+@example
+a = zeros (1000); # create a 1000x1000 matrix
+b = a(:,10:100); # no copying done here
+b = a(10:100,:); # copying done here
+@end example
+
+This applies to arrays (matrices), cell arrays, and structs indexed using ().
+Index expressions generating cs-lists can also benefit of shallow copying
+in some cases. In particular, when @var{a} is a struct array, expressions like
+@code{@{a.x@}, @{a(:,2).x@}} will use lazy copying, so that data can be shared
+between a struct array and a cell array.
+
+Most indexing expressions do not live longer than their `parent' objects.
+In rare cases, however, a lazily copied slice outlasts its parent, in which
+case it becomes orphaned, still occupying unnecessarily more memory than needed.
+To provide a remedy working in most real cases,
+Octave checks for orphaned lazy slices at certain situations, when a value
+is stored into a "permanent" location, such as a named variable or cell or
+struct element, and possibly economizes them. For example
+
+@example
+a = zeros (1000); # create a 1000x1000 matrix
+b = a(:,10:100); # lazy slice
+a = []; # the original a array is still allocated
+c@{1@} = b; # b is reallocated at this point
+@end example
 
 @item
-Avoid resizing matrices unnecessarily.  When building a single result
+Avoid deep recursion. Function calls to m-file functions carry a relatively significant overhead,
+so rewriting a recursion as a loop often helps. Also, note that the maximum level of recursion is
+limited.
+
+@item
+Avoid resizing matrices unnecessarily. When building a single result
 matrix from a series of calculations, set the size of the result matrix
 first, then insert values into it.  Write
 
@@ -119,8 +188,39 @@
 @end group
 @end example
 
+Sometimes the number of items can't be computed in advance, and stack-like operations
+are needed. When elements are being repeatedly inserted at/removed from the end of an
+array, Octave detects it as stack usage and attempts to use a smarter memory management
+strategy preallocating the array in bigger chunks. Likewise works for cell and
+struct arrays.
+
+@example
+a = [];
+while (condition)
+  @dots{}
+  a(end+1) = value; # "push" operation
+  @dots{}
+  a(end) = []; # "pop" operation
+  @dots{}
+endwhile
+@end example
+
 @item
-Avoid calling @code{eval} or @code{feval} whenever possible, because
+Use @code{cellfun} intelligently. The @code{cellfun} function is a useful tool
+for avoiding loops. @xref{Processing Data in Cell Arrays}.
+@code{cellfun} is often use with anonymous function handles; however, calling
+an anonymous function involves an overhead quite comparable to the overhead
+of an m-file function. Passing a handle to a built-in function is faster,
+because the interpreter is not involved in the internal loop. For example:
+
+@example
+a = @{@dots{}@}
+v = cellfun (@@(x) det(x), a); # compute determinants
+v = cellfun (@@det, a); # faster
+@end example
+
+@item
+Avoid calling @code{eval} or @code{feval} excessively, because
 they require Octave to parse input or look up the name of a function in
 the symbol table.