Open travisfranck opened 6 years ago
I agree that Floats should be enough, and comparing to 32-bit Vensim makes sense.
It also turns out that Vensim stores all values as floats, even when it does double-precision computations. https://www.vensim.com/documentation/index.html?ref_variable_names.htm
I did a quick experiment to change all uses of doubles to floats (actually an sde_float
typedef) in SDEverywhere c files (and in the generated c file).
There are some good performance and size wins to be had from this change (see below), but we'd need to spend some time making sure that any differences in the new outputs are within an acceptable range, so I think we should hold off on the change until we get some more automated checks in place. The runtime performance gains appear to be very slight on modern processors; the main benefit appears to be in shaving off ~120kb from the wasm binary size.
Here are some performance numbers for the record relative to other performance work.
MacBook Pro (2019) | 2.4 GHz 8-core i9, 32 GB RAM, macOS 10.15
Issue | C run (ms) | Wasm run (ms) | Wasm init (ms) | JS mem (MB) | Page mem (MB) |
---|---|---|---|---|---|
baseline | 45.8 | 87.5 | 38.0 | 94 | 685 |
SDE 18 | 46.0 | 85.6 | 18.0 | 39 | 672 |
SDE 19 | 42.8 | 49.4 | 15.0 | 38 | 25 |
SDE 22 | 34.8 | 44.8 | 15.0 | 38 | 21 |
SDE 23 | 32.7 | 42.8 | 13.0 | 38 | 32 |
SDE 24 | 26.6 | 38.2 | 13.0 | 39 | 26 |
SDE 7 | 24.4 | 34.8 | 10.0 | 39 | 20 |
iPhone 8 | A11, iOS 13
Issue | C run (ms) | Wasm run (ms) | Wasm init (ms) | JS mem (MB) | Page mem (MB) |
---|---|---|---|---|---|
baseline | 39.9 | 187.0 | 165.0 | 39 | 645 |
SDE 18 | 40.3 | 219.0 | 86.0 | 38 | 724 |
SDE 19 | 40.1 | 81.6 | 83.0 | 38 | 41 |
SDE 22 | 35.5 | 74.6 | 86.0 | 40 | 40 |
SDE 23 | 31.1 | 73.6 | 82.0 | 41 | 39 |
SDE 24 | 28.5 | 71.6 | 82.0 | 40 | 38 |
SDE 7 | 28.7 | 70.0 | 70.0 | 36 | 36 |
iPad Air (2013) | A7, iOS 12
Issue | C run (ms) | Wasm run (ms) | Wasm init (ms) | JS mem (MB) | Page mem (MB) |
---|---|---|---|---|---|
baseline | 151.0 | 1372.2 | 30146.0 | 77 | 331 |
SDE 18 | 166.0 | 1408.0 | 4416.0 | 42 | 395 |
SDE 19 | 151.0 | 837.6 | 1291.0 | 45 | 41 |
SDE 22 | 137.0 | 771.6 | 1484.0 | 44 | 40 |
SDE 23 | 110.1 | 642.2 | 1148.0 | 44 | 41 |
SDE 24 | 111.8 | 638.4 | 1236.0 | 45 | 37 |
SDE 7 | 91.7 | 543.8 | 1120.0 | 43 | 51 |
Issue | Wasm size (bytes) |
---|---|
baseline | 1,084,036 |
SDE 18 | 773,968 |
SDE 19 | 776,851 |
SDE 22 | 737,028 |
SDE 23 | 741,668 |
SDE 24 | 741,677 |
SDE 7 | 616,264 |
Issue | Date | Notes |
---|---|---|
baseline | 2020/07/08 | baseline prior to performance work |
SDE 18 | 2020/07/09 | change lookup init to use static arrays |
SDE 19 | 2020/07/09 | break large functions into chunked subfunctions |
SDE 22 | 2020/07/10 | replace wrapper functions with macros |
SDE 23 | 2020/07/10 | replace dimension array access with simple index |
SDE 24 | 2020/07/10 | optimize __lookup function |
SDE 7 | 2020/07/10 | change from doubles to floats |
We use 64-bit math in SDEverywhere because of a long-standing rule in C that all internal math operations are 64 bit, even if the operands are floats, and results are ultimately rounded to 32 bit precision. I elected to maintain 64-bit precision throughout by storing data in C doubles.
But your comment led me to look into this further yesterday. I discovered that in the C99 standard that modern compilers like clang use, the precision of internal math operations is implementation dependent. And guess what? Clang does not enforce 64 bit precision internally. If you use float operands, math operations are 32-bit.
I think moving to 32-bit math makes sense for SDEverywhere. That is enough precision for SD work. Most people use the 32 bit version of Vensim. We could remove the requirement for validating against data from 64-bit Vensim. And we would cut our memory requirements for data in half. This mostly involves changing "double" to "float" everywhere and using the float versions of standard library functions.
-Todd