[PATCH] D60593: [GwpAsan] Introduce GWP-ASan.
Mitch Phillips via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 18 16:01:20 PDT 2019
hctim marked 4 inline comments as done.
hctim added a comment.
In D60593#1472015 <https://reviews.llvm.org/D60593#1472015>, @vlad.tsyrklevich wrote:
> I'm struggling to understand why adding an additional branch on the fast path (e.g. init check in ret) would be faster. With the init check in the NextSampleCounter==0 branch we should be performing one fewer load/compare on the fast path in the enabled case. Could you show the code you used for the init check in ret/branch cases? I'm surprised by the results.
For the branch case, I had the conditional branch outside of `NextSampleCounter == 0`, so that the RT-disabled would incur minimal overhead (single branch instead of two branches), e.g.
shouldSample() {
if (!IsInitialised) return false;
if (NextSampleCounter == 0`) ...
Changing `shouldSample` and `pointerIsMine` to use thread-safe atomics, and changing the RT-disabled check to be inside the `NextSampleCounter == 0` branch:
| Option | Median Time (with 20 runs) | Runtime increase relative to CT-Disabled |
| Compile-time disabled | 3.5715s | 0.0000% |
| Runtime disabled (init check in ret) | 3.6270s | 1.5302% |
| Runtime disabled (init check in branch) | 3.6330s | 1.6928% |
| Runtime enabled (init check in ret) | 3.6290s | 1.5845% |
| Runtime enabled (init check in branch) | 3.6365s | 1.7874% |
|
Init check in ret:
ALWAYS_INLINE bool shouldSample() {
if (UNLIKELY(NextSampleCounter == 0))
NextSampleCounter =
(Random::getRandomUnsigned64() %
__atomic_load_n(&AdjustedSampleRate, __ATOMIC_RELAXED)) +
1;
return NextSampleCounter-- == 1 && __atomic_load_n(&IsInitialised, __ATOMIC_RELAXED);
}
Init check in branch:
ALWAYS_INLINE bool shouldSample() {
if (UNLIKELY(NextSampleCounter == 0)) {
if (!__atomic_load_n(&IsInitialised, __ATOMIC_RELAXED))
return false;
NextSampleCounter =
(Random::getRandomUnsigned64() %
__atomic_load_n(&AdjustedSampleRate, __ATOMIC_RELAXED)) +
1;
}
return NextSampleCounter-- == 1;
}
I thought the above results were counterintuitive at first, but stepping through the disassembly...
For disabled:
1. init-ret is a TLS load, a non taken branch (with probability `1 / 2**63`), the same TLS load (is reused), a TLS decrement, and a branch (with probability `1 / 2**64`). Summary: 1 TLS load, 1 TLS store, two branches.
2. init-branch is a TLS load, a relaxed atomic load, and two branches. Summary: 1 TLS load, 1 atomic load, two branches.
... this would explain the performance increase as we generally don't have to make the atomic load, which will likely not be in L1D.
With runtime-enabled, we can generally short-circuit the atomic load as `NextSampleCounter ∉ {0, 1}`.
================
Comment at: compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp:182
+
+ bool ShouldRightAlign = (*Size % 2 == 1);
+
----------------
vlad.tsyrklevich wrote:
> In Chrome we left- or right-align based on whether the (randomly chosen) slot is even/odd, that means an allocation will test for both under- and over-flows across different runs. However in this case we always left-/right-align based on the size which means a given type will only ever be tested one way (and I'd expect we have a lot more even allocations than odd allocations.)
Gotcha. In this case, we need a runtime option (like the previous `AlignmentStrategy`) to guarantee left && right alignment for testing, as we don't want flaky tests.
How would you prefer to go about this? Two runtime options, `NoRandomAlignment` and `AlignRight`?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D60593/new/
https://reviews.llvm.org/D60593
More information about the llvm-commits
mailing list