You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When investigating performance/crashing issues with En-ROADS on iPad, in addition to the findings from #18, I discovered another source of memory pressure: the large number of instructions in the generated functions of the En-ROADS model leads to a large stack frame size.
The functions in question are:
initConstants (~1500 lines)
initLevels (~3900 lines)
evalAux (~4000 lines)
evalLevels (~350 lines)
Each of these functions operates on what are essentially global variables, so as long as we execute the operations in the same order, there's no harm in breaking up these large functions into smaller sub-functions that execute a chunk of instructions.
I experimented a bit with the "chunk" size and it looks like 30 operations per sub-function is a sweet spot.
Here are some preliminary numbers that show the performance benefits of this approach, as compared to the original baseline (i.e., last week's code) as well as implementing these optimizations on top of #18.
This is really cool. Some things I note from reviewing the tables:
Memory size a much improved. WASM code overall is much better. Very nice.
In my head, we always had a goal to have the model run in under 10ms. I think Todd said that was what the human brain thought was "instant". Seems like we're already well above that now. Maybe closer to 100ms on older than 2019 laptops.
For the iOS data, C code is significantly faster than JS code. Good to keep in mind if when we consider our iOS deployment strategy.
When investigating performance/crashing issues with En-ROADS on iPad, in addition to the findings from #18, I discovered another source of memory pressure: the large number of instructions in the generated functions of the En-ROADS model leads to a large stack frame size.
The functions in question are:
initConstants
(~1500 lines)initLevels
(~3900 lines)evalAux
(~4000 lines)evalLevels
(~350 lines)Each of these functions operates on what are essentially global variables, so as long as we execute the operations in the same order, there's no harm in breaking up these large functions into smaller sub-functions that execute a chunk of instructions.
For example, instead of:
We can have:
I experimented a bit with the "chunk" size and it looks like 30 operations per sub-function is a sweet spot.
Here are some preliminary numbers that show the performance benefits of this approach, as compared to the original baseline (i.e., last week's code) as well as implementing these optimizations on top of #18.
Performance
MacBook Pro (2019) | 2.4 GHz 8-core i9, 32 GB RAM, macOS 10.15
iPhone 8 | A11, iOS 13
iPad Air (2013) | A7, iOS 12
Size
The text was updated successfully, but these errors were encountered: