-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Overhead due to unneeded __error assignments #1592
Comments
As discussed in DM, might be more reasonable to test a rebased version. There's also nothing fancy around the benchmark. The reproducer is essentially testing how quickly Spicy can discard one byte at a time within a nested unit structure. |
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Per #1592, case 2 may also have overhead. Closes #1592.
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Per #1592, case 2 may also have overhead. Closes #1592.
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Couples notes on (2): - Per #1592, case 2 may also have overhead. Closes #1592. - Technically, this optimization isn't always correct: subsequent code could assume that `(*self).__error` is set, whereas after removal it's not (or not to the expected value). However, `__error` is strictly-internal state, and we know that we don't use it any different, so this seems ok until we have more general optimizer logic.
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Couples notes on (2): - Per #1592, case 2 may also have overhead. Closes #1592. - Technically, this optimization isn't always correct: subsequent code could assume that `(*self).__error` is set, whereas after removal it's not (or not to the expected value). However, `__error` is strictly-internal state, and we know that we don't use it any different, so this seems ok until we have more general optimizer logic.
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Couples notes on (2): - Per #1592, case 2 may also have overhead. Closes #1592. - Technically, this optimization isn't always correct: subsequent code could assume that `(*self).__error` is set, whereas after removal it's not (or not to the expected value). However, `__error` is strictly-internal state, and we know that we don't use it any different, so this seems ok until we have more general optimizer logic.
We use this to remove two statement constructs that the main optimizer may leave behind: 1. `default<void>()` 2. `(*self).__error = __error; __error = (*self).__error;` The second case is a quite specific situation that eventually, once we have CFG/DFG tracking, the main optimizer should be able to cover more generically. However, for now, it's just not nice to always have these blocks in the generated C++ code, so adding this special case seems useful. Couples notes on (2): - Per #1592, case 2 may also have overhead. Closes #1592. - Technically, this optimization isn't always correct: subsequent code could assume that `(*self).__error` is set, whereas after removal it's not (or not to the expected value). However, `__error` is strictly-internal state, and we know that we don't use it any different, so this seems ok until we have more general optimizer logic.
Hope that's a valid test. I'm not sure why there's all the redundant
(*__self).__error = __error
assignments, but it doesn't come for free. I took the generated C++ code of the following example (spicyc -D jit -T
and copying away the cc files and commands) and patched out the obvious ones that seemed superflous. This results in a 10-12% raw parsing performance improvement for this microbenchmark. (Debian 12, GCC 12.2).cat ./test-data.txt | spicy-driver Test.hlto
cat ./test-data.txt | spicy-driver Test3.hlto
test-data.txt was generated as follows:
There might some performance improvements by removing the unneeded assignments (or somehow convincing the compiler to not emit code for them).
Patch:
The text was updated successfully, but these errors were encountered: