@@ -2213,11 +2213,52 @@ <h3 id="Doxygen">Doxygen</h3>
2213
2213
< h3 id ="Memory Allocation "> Memory Allocation</ h3 >
2214
2214
2215
2215
< 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.
2218
2223
</ p >
2219
2224
</ div >
2220
2225
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
+
2221
2262
</ div >
2222
2263
2223
2264
< h3 id ="Ownership_and_Smart_Pointers "> Ownership and Smart Pointers</ h3 >
0 commit comments