Commit ea29761
committed
stdlib: Fix O(n^2) algorithm in
`erl_eval:extended_parse_exprs/1` exhibited O(n^2) time complexity when
passed more and more tokens, with both erts and AtomVM. The reason seems
to be related to the
`try <expr> of ... <recurse> catch _:_ -> <recurse otherwise> end.` pattern,
where `<expr>` would usually fail.
By replacing `<expr>` (in this case `unscannable/1`) with some expression
that usually succeeds, evaluated complexity is back to O(n) which it should
be for this algorithm.
The script to evaluate the complexity can be found here:
https://gist.github.com/pguyot/1aa53791a819709f147e2ad55aadb279
With OTP 28.1.1:
```
=== Results Summary ===
Size | Tokens | Avg (ms) | Min (ms) | Max (ms) | StdDev | Ratio
-----|--------|----------|----------|----------|--------|-------
512 | 1026 | 4 | 3 | 4 | 1 | 0.31/0.5
1024 | 2050 | 13 | 12 | 13 | 0 | 0.27/0.5
2048 | 4098 | 49 | 48 | 49 | 1 | 0.26/0.5
4096 | 8194 | 188 | 187 | 189 | 1 | 0.25/0.5
8192 | 16386 | 739 | 736 | 743 | 2 | -
=== Complexity Analysis ===
Expected behavior for doubling size:
- O(n): 2x time
- O(n^2): 4x time
- O(n^3): 8x time
Size 512 -> 1024: time ratio 3.25 (between O(n) and O(n^2))
Size 1024 -> 2048: time ratio 3.77 (between O(n) and O(n^2))
Size 2048 -> 4096: time ratio 3.84 (between O(n) and O(n^2))
Size 4096 -> 8192: time ratio 3.93 (between O(n) and O(n^2))
```
With this change, it is both much faster and it exhibits O(n).
```
=== Results Summary ===
Size | Tokens | Avg (ms) | Min (ms) | Max (ms) | StdDev | Ratio
-----|--------|----------|----------|----------|--------|-------
512 | 1026 | 1 | 1 | 1 | 0 | 0.50/0.5
1024 | 2050 | 2 | 1 | 3 | 1 | 0.50/0.5
2048 | 4098 | 4 | 3 | 5 | 0 | 0.50/0.5
4096 | 8194 | 8 | 7 | 10 | 1 | 0.50/0.5
8192 | 16386 | 16 | 14 | 19 | 2 | -
=== Complexity Analysis ===
Expected behavior for doubling size:
- O(n): 2x time
- O(n^2): 4x time
- O(n^3): 8x time
Size 512 -> 1024: time ratio 2.00 (approximately O(n))
Size 1024 -> 2048: time ratio 2.00 (approximately O(n))
Size 2048 -> 4096: time ratio 2.00 (approximately O(n))
Size 4096 -> 8192: time ratio 2.00 (approximately O(n))
```
Signed-off-by: Paul Guyot <[email protected]>erl_eval:extended_parse_exprs/1
1 parent 0d588b9 commit ea29761
1 file changed
+12
-6
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2012 | 2012 | | |
2013 | 2013 | | |
2014 | 2014 | | |
2015 | | - | |
2016 | | - | |
2017 | | - | |
2018 | | - | |
2019 | | - | |
| 2015 | + | |
| 2016 | + | |
| 2017 | + | |
| 2018 | + | |
| 2019 | + | |
| 2020 | + | |
| 2021 | + | |
| 2022 | + | |
| 2023 | + | |
2020 | 2024 | | |
2021 | 2025 | | |
2022 | 2026 | | |
| |||
2033 | 2037 | | |
2034 | 2038 | | |
2035 | 2039 | | |
2036 | | - | |
| 2040 | + | |
| 2041 | + | |
| 2042 | + | |
2037 | 2043 | | |
2038 | 2044 | | |
2039 | 2045 | | |
| |||
0 commit comments