## Writing Advanced Matlab Code ### SSW #### David Eriksson & Eric Lee
# Outline 1. Programming practices 2. Performance examples 3. Profiling 4. Parallel toolbox
## MATLAB programming practices - Preallocate ```matlab x = 0; for k = 2:1000000 x(k) = x(k-1) + 5; end ``` ```matlab x = zeros(1000000, 1); for k = 2:1000000 x(k) = x(k-1) + 5; end ```
## MATLAB programming practices - Vectorize ```matlab t = 0:.01:10; y = sin(t); ``` ```matlab i = 0; for t = 0:.01:10 i = i + 1; y(i) = sin(t); end ```
## MATLAB programming practices - Place independent operations outside loops ```matlab for i=1:n val = fun(i); for j=1:n ... end end ``` ```matlab for i=1:n for j=1:n val = fun(i); ... end end ```
## MATLAB programming practices - Create new variables if data type changes - Create a new variable rather than assigning data of a different type to an existing variable - Changing the class or array shape of an existing variable takes extra time to process - Use short-circuit operators - Use && and || when possible. - Efficient because MATLAB evaluates the second operand only when it is necessary
## MATLAB programming practices - Avoid global variables - Good programming practice - Can decrease performance of your code - Avoid overloading built-ins - Avoid overloading built-in functions on any standard MATLAB data classes. - Please avoid using `sum` as a variable name =(
## MATLAB programming practices - Avoid using "data as code" - Avoid lots of code that generate variables - It is better to load them from a MAT-file - Use functions instead of scripts. - Functions are generally faster. - Prefer local functions over nested functions - Use modular programming
# Example 1: Dynamic memory allocation 1. We only allocate once (good) 2. MATLAB uses column-major, so it can just extend the memory when we add a column (ok) 3. Adding a row forces us to move most of the elements in X (bad) 4. MATLAB first forms [X, x] before assigning (bad) 5. Avoids the for-loop, fastest way I know of **Note:** 3-4 allocate $\mathcal{O}(np^2)$ memory
# Example 2: Sparse memory allocation 1. Add element by element to the sparse matrix 2. Say what the non-zero elements are but assign values later 3. Initialize with non-zero values **Note:** 1 requires inserting elements into the compressed sparse column (CSC) format (expensive) **Note:** 2 avoids inserting elements, but need to fill out the values
# Example 3: Using () 1. Matrix times vector $\mathcal{O}(n^2)$ 2. MATLAB evaluates from left to right, same as above 3. Dot product $\mathcal{O}(n)$ **Note:** Equivalent mathematically, but vastly different flop counts
# Example 4: Never trust JIT! - MATLAB uses Just-in-Time (JIT) compilation to optimize your code - Don't expect JIT to always speed-up your code! - Better to write efficient code than rely on GIT - JIT can speed up 1 and 2, but not 3 - A bit surprising since 3 is so similar to 1
# Example 5: Symmetry - MATLAB uses the fact that $A^TA$ and $AA^T$ are symmetric to speed up the computation!
# Example 6: Inlining - Inline simple functions that are called frequently - The communication overhead can be significant
# Example 7: Indexing - Both logical indexing and find are much faster than the loop - JIT is able to vectorize the loop
# Example 8: More rows or more columns? - The code is ~70 times faster when we have more rows than columns - CSC is great for quickly acessing columns - Not great if the columns are small - Larger speed-up makes the matvecs faster
# Profiling - Program analysis that measures memory/time complexity of a program and the frequency/duration of function calls. - Lots of software for profiling out there - Language specific; MATLAB has own! - MATLAB Profiler rich with features
# General Idea - Run Profiler on your code. - Look for functions that use a significant amount of time or that are called most frequently. - Determine whether there are changes you can make to those lines of code to improve performance. - Implement the potential performance improvements in your code. - **If you profile the identical code twice, you can get slightly different results each time**.
# Profiling in Code ```matlab {r, eval=FALSE} profile('on') ... dostuff() // we would like dostuff to run faster ... profile('viewer') profsave() ```
# Parallel Pool - Set of workers allocated before large task - Expensive to allocate and deallocate! - Workers located on local or remote machine - Local is the default
# Pool Managment ```matlab {r, eval=FALSE} parpool(4) //Before parallel area ... ... p = gcp('nocreate') //nocreate flag delete(p) ``` - Pool also automatically created at the start of parallel function calls - Manual managment in code base is superior (and very easy)
# Parallel Loops ```matlab {r, eval=FALSE} for i = 1:n dostuff(i) end ``` ```matlab {r, eval=FALSE} parfor i = 1:n dostuff(i) end ``` - Note that loop iterations are independent! - Ordering of loop nondeterministic - i.e. 6, 2, 3, 1, 5, 4
# Other Paradigms Supported - Mapreduce - SPSD (Single Program Multiple Data) - Shared Arrays - (Distributed Memory Paradigms) - Most of these can be accomplished via parfor - these implementations are optimized and less of a headache - No While-Looping (out-of-the-box)
# Interactive Parallel ```matlab {r, eval=FALSE} pmode('start',4) //opens up GUI ... ... pmode('quit') ``` - Interative Parallel mode provides a GUI to each worker - GUI limited (not regular MATLAB command line)
# Limitations - Not good for fine-grained managment - "I want worker A to do task A, worker B to do task B ... worker K to do task K" - Hacky (and very inefficient) Solution: ```matlab {r, eval=FALSE} function hacky(data_1, data_2 ... data_k) parfor i = 1:k switch idx case 1 case 2 ... case k end end ```
# Limitations - Some functions will use parallelism - Hard to know ... sometimes adding workers slows down code - Toolboxes in Comp Bio, Optimization, Singal Processing - In general, far less expressive than a dedicated parallel language - but nonetheless an **excellent** tool for many purposes