@@ -2213,11 +2213,52 @@ <h3 id="Doxygen">Doxygen</h3>
22132213< h3 id ="Memory Allocation "> Memory Allocation</ h3 >
22142214
22152215< div class ="summary ">
2216- < p > No dynamic allocation in the inner simulation/control loops. Code should
2217- be still be thread-safe (e.g. be careful with pre-allocations).
2216+ < p > It's often important to avoid dynamic memory allocation within
2217+ performance-critical code regions (e.g., simulation steps, control loops). Code
2218+ that pre-allocates must be thread-safe, within common Drake thread use idioms
2219+ (see below). Performance-critical code that promises to avoid allocations must
2220+ have an automated acceptance test using the the Drake
2221+ < a href ="https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/limit_malloc.h "> LimitMalloc</ a >
2222+ tool.
22182223</ p >
22192224</ div >
22202225
2226+ < div class ="stylebody ">
2227+
2228+ < p > Pre-allocating memory for use in high-performance code avoids potentially
2229+ expensive operations to obtain memory from the heap. Importantly, since the
2230+ heap is a process-global resource, heap operations can incur synchronization
2231+ costs, such as waiting on a mutex. So, heap operations are not only expensive,
2232+ but also have a non-deterministic run-time cost.</ p >
2233+
2234+ < p > In some situations, it may be necessary to allocate memory inside a function
2235+ executed in a performance-critical loop. This may be acceptable if that
2236+ initialization occurs in the first few loop invocations and the function
2237+ subsequently ceases to allocate.</ p >
2238+
2239+ < p > One big advantage of conventional heap operations (e.g. a std::vector as a
2240+ function-local variable) is that they < i > are</ i > thread-safe, and their wide
2241+ use ensures that the implementations are efficient and high-quality. When
2242+ pre-allocating, the code is likely to reuse the storage in less common ways. Be
2243+ careful to avoid situations where the storage could be accessed from multiple
2244+ threads without synchronization.</ p >
2245+
2246+ < h4 > Systems, Contexts, and Threading</ h4 >
2247+
2248+ < p > In Drake, the most common thread use idiom is the single-system,
2249+ multiple-context idiom. Multiple threads each own a Drake context, and they
2250+ reuse a shared system (or diagram). To support this, system (or diagram)
2251+ classes must only store data necessary to maintain the structure of the system,
2252+ but not any data related to computation of inputs, outputs, or system state. If
2253+ persistent storage is needed to compute without requiring heap operations, that
2254+ storage should be obtained via a Drake cache entry. Cache entries will be
2255+ allocated on a per-context basis, so that there is no thread safety hazard when
2256+ using context-per-thread multithreading. An example of this technique can be
2257+ found in < a href ="https://github.com/RobotLocomotion/drake/pull/14929 "> PR
2258+ #14929</ a > .</ p >
2259+
2260+ </ div >
2261+
22212262</ div >
22222263
22232264< h3 id ="Ownership_and_Smart_Pointers "> Ownership and Smart Pointers</ h3 >
0 commit comments