# HG changeset patch # User Jaroslav Hajek # Date 1245155274 -7200 # Node ID b2133f97079d717f81a8ff484af0c7fc4cb63a41 # Parent 5e4da3b3747e57360e6c7eb5a3d3b5fe69974ede update coding tips diff -r 5e4da3b3747e -r b2133f97079d doc/ChangeLog --- a/doc/ChangeLog Tue Jun 16 09:49:25 2009 +0200 +++ b/doc/ChangeLog Tue Jun 16 14:27:54 2009 +0200 @@ -1,3 +1,7 @@ +2009-06-16 Jaroslav Hajek + + * interpreter/tips.txi: Update. + 2009-06-07 Rik * interpreter/plot.txi: Update some of Advanced Plotting documentation. diff -r 5e4da3b3747e -r b2133f97079d doc/interpreter/tips.txi --- a/doc/interpreter/tips.txi Tue Jun 16 09:49:25 2009 +0200 +++ b/doc/interpreter/tips.txi Tue Jun 16 14:27:54 2009 +0200 @@ -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.