Simplify PoissonAllocationSampler's allocation hooks [chromium/src : main]

2 views
Skip to first unread message

Joe Mason (Gerrit)

unread,
Jan 6, 2023, 1:26:38 AM1/6/23
to lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

Attention is currently required from: Andre Kempe, Benoit Lize.

View Change

1 comment:

To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
Gerrit-Change-Number: 4140359
Gerrit-PatchSet: 2
Gerrit-Owner: Joe Mason <joenot...@google.com>
Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
Gerrit-Reviewer: Joe Mason <joenot...@google.com>
Gerrit-Attention: Andre Kempe <andre...@arm.com>
Gerrit-Attention: Benoit Lize <li...@chromium.org>
Gerrit-Comment-Date: Fri, 06 Jan 2023 06:24:10 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

Joe Mason (Gerrit)

unread,
Jan 6, 2023, 2:04:11 AM1/6/23
to lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

Attention is currently required from: Andre Kempe, Benoit Lize.

View Change

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 5
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Andre Kempe <andre...@arm.com>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 06 Jan 2023 07:00:58 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Andre Kempe (Gerrit)

    unread,
    Jan 6, 2023, 5:07:34 AM1/6/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Benoit Lize, Joe Mason.

    View Change

    3 comments:

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 5
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 06 Jan 2023 10:04:45 +0000

    Andre Kempe (Gerrit)

    unread,
    Jan 6, 2023, 8:15:33 AM1/6/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Benoit Lize, Joe Mason.

    View Change

    1 comment:

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 5
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 06 Jan 2023 13:13:09 +0000

    Joe Mason (Gerrit)

    unread,
    Jan 6, 2023, 10:31:11 AM1/6/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Andre Kempe, Benoit Lize.

    View Change

    4 comments:

    • Patchset:

      • Patch Set #5:

        I do not have powers to vote here, but looks mostly good to me, except for two nits and one question […]

        Thanks for pointing that out! I'll leave it in for now since it can't hurt to continue testing that scenario, but I added it to the list of code to clean up later in http://doc/1sA2pnvpRJGejfSoCxkQOo2lv2Fr6vH5Yn8JeUW1IFcw.

        I'll update the comment to be more accurate before submitting. (I'm editing through the web interface right now so changing files that aren't already in the patch is awkward.)

      • Patch Set #5:

        One more thing to be aware of: Installing the hooks that early in https://chromium-review. […]

        I think that will automatically work itself out in the next step. Since the new hook installer in https://crrev.com/c/4031766 needs to pass a pointer to the PoissonAllocationSampler, the caller will need to call `PoissonAllocationSampler::Get()` which will create the singleton as early as it's needed.

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • Nit: Is the problem really to access before initialization of instance_? Or to access without derefe […]

        Currently the allocator hooks are static functions, so in theory they could be called when `instance_` is unset, if some other code calls `InstallStandardAllocatorHooks`. (No other code actually does that AFAIK so maybe this comment is excessively cautious.)

        So I think "before initialization of instance" is more accurate. (It's not JUST for performance of not having to dereference.)

        But when we switch to the new hooks, `instance_` will always exist so the comment will become obsolete. I'll just remove it so we don't need to update it later.

      • Patch Set #5, Line 200: friend class ScopedMuteHookedSamplesForTesting;

        Nit: Do we need this? ScopedMuteHookedSamplesForTesting doesn't access any of the private members.

      • Good catch! This was part of a change that didn't work out, I forgot to remove it. Thanks.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 6
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Andre Kempe <andre...@arm.com>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 06 Jan 2023 15:28:02 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Andre Kempe <andre...@arm.com>
    Gerrit-MessageType: comment

    Joe Mason (Gerrit)

    unread,
    Jan 6, 2023, 1:42:45 PM1/6/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Andre Kempe, Benoit Lize.

    View Change

    1 comment:

    • Patchset:

      • Patch Set #5:

        Thanks for pointing that out! I'll leave it in for now since it can't hurt to continue testing that […]

        Updated the comment.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 8
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Andre Kempe <andre...@arm.com>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 06 Jan 2023 18:40:07 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Andre Kempe <andre...@arm.com>
    Comment-In-Reply-To: Joe Mason <joenot...@google.com>
    Gerrit-MessageType: comment

    Benoit Lize (Gerrit)

    unread,
    Jan 10, 2023, 8:29:12 AM1/10/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Andre Kempe, Joe Mason.

    Patch set 9:Code-Review +1

    View Change

    2 comments:

    • Patchset:

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • Patch Set #9, Line 193: // Fast, thread-safe access to the current profiling state.

        What is thread-safe about this? Since you're only reading it with relaxed atomics, the only guarantee you get is that you will read either true or false, not a garbage intermediate value.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 9
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Andre Kempe <andre...@arm.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Comment-Date: Tue, 10 Jan 2023 13:26:38 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Gerrit-MessageType: comment

    Joe Mason (Gerrit)

    unread,
    Jan 10, 2023, 2:46:17 PM1/10/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette.

    View Change

    1 comment:

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • What is thread-safe about this? Since you're only reading it with relaxed atomics, the only guarante […]

        Good point. The new use of `profiling_state_` introduces an ordering dependency between threads - if thread A calls RecordAlloc, thread B calls RecordFree, and thread C updates `profiling_state_` from kNeverStarted to kRunning, it would be possible for thread A to read kRunning and thread B to read kNeverStarted, meaning the free would be missed. I think we now need to use Release-Consume ordering. (Before this patch the state was only checked in RecordAlloc, not RecordFree, so at worst one extra allocation could be recorded after turning off profiling. There was no chance of an Alloc / Free mismatch.)

        `g_mute_hooked_samples` also needs to be Release-Consume. It used to only be read in test assertions, but now it's written on the main thread of unit tests (in the ScopedSuppressRandomnessForTesting constructor/destructor) and can be read in any
        thread. If thread A creates a ScopedSuppressRandomnessForTesting and then adds an observer, and thread B reads `g_mute_hooked_samples` as false, that could lead to test flakiness as the observer incorrectly sees some unexpected real memory allocations. (On thread B, the write `g_mute_hooked_samples = true` and `profiling_state_ = kRunning` need to be seen in the same order as on thread A.)

        +gab, can you verify the use of atomics here?

        `profiling_state_` is written in AddSamplesObserver and RemoveSamplesObserver, inside a mutex, and the possible state transitions are `kNeverStarted -> kRunning <-> kStopped`. It's read in RecordFree(), which early returns on `kNeverStarted`, and RecordAlloc(), which also early returns on `kNeverStarted` or does a bit more work and then branches on the other two states.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Gabriel Charette <g...@chromium.org>
    Gerrit-Comment-Date: Tue, 10 Jan 2023 19:43:36 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Benoit Lize <li...@chromium.org>
    Gerrit-MessageType: comment

    Andre Kempe (Gerrit)

    unread,
    Jan 11, 2023, 3:43:22 AM1/11/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette, Joe Mason.

    View Change

    2 comments:

    • Patchset:

      • Patch Set #10:

        Just my 5 Cent / 2 Pence on reading/storing of profiling_state_

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • Good point. […]

        So, std::atomics use std::memory_order_seq_cst by default for store and read operations, see https://en.cppreference.com/w/cpp/atomic/atomic/store and https://en.cppreference.com/w/cpp/atomic/memory_order#Sequentially-consistent_ordering

        So
        > [...] if thread A calls RecordAlloc, thread B calls RecordFree, and thread C updates `profiling_state_` from kNeverStarted to kRunning, it would be possible for thread A to read kRunning and thread B to read kNeverStarted, meaning the free would be missed [...]

        is NOT possible if the value is set before the reads. Both threads would read the same value.

        So, IMHO from a functional POV we're completely fine without specifying the memory order in details. May not be top-notch performance wise, but it sure is for correctness.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Gabriel Charette <g...@chromium.org>
    Gerrit-Comment-Date: Wed, 11 Jan 2023 08:40:54 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Joe Mason <joenot...@google.com>

    Joe Mason (Gerrit)

    unread,
    Jan 11, 2023, 11:42:56 AM1/11/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette.

    View Change

    1 comment:

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • So, std::atomics use std::memory_order_seq_cst by default for store and read operations, see https:/ […]

        Yes, using the full `memory_order_seq_cst` would definitely be correct, but I want to use the more performant semantics if possible. gab@ is our atomics expert. I'll defer to him.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Gabriel Charette <g...@chromium.org>
    Gerrit-Comment-Date: Wed, 11 Jan 2023 16:40:49 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Andre Kempe <andre...@arm.com>

    Gabriel Charette (Gerrit)

    unread,
    Jan 11, 2023, 12:41:01 PM1/11/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Joe Mason.

    View Change

    9 comments:

    • Patchset:

      • Patch Set #10:

        I strongly recommend this talk https://youtu.be/ZQFzMfHIxng on atomics

        The allocator is a very subtle place and, on first look, it's not doing atomics correctly. It should at very least be explicit on all memory barriers (never use operators - even the C++ committee agrees it was a mistake to add them).

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • Patch Set #10, Line 208: memory_order_consume

        1) First time I see std::memory_order_consume (I'm used to std::memory_order_acquire), looks like it's deprecated in C++17:
        ```
        The specification of release-consume ordering is being revised, and the use of memory_order_consume is temporarily discouraged.
        ```
        https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Consume_ordering

        Looks like the difference is that consume only synchronizes memory related to the state being consumed instead of everything the producing thread wrote.

        2) In either case, I don't think you need acquire nor consume here. Atomics (even when read with `std::memory_order_relaxed`) always guarantee that you see the whole variable. Your comment seems to hint at a desire for `std::memory_order_seq_cst` (i.e. total ordering of writes across threads) but that's rarely needed.

        3) Your comment also implies you want some kind of a flush/guarantee that other threads see writes right away. No memory order guarantees that. Cache coherency is what makes memory eventually consistent. What memory orders do is that *once* you see the value written by thread A, you also see other (atomic and non-atomic) memory written by thread A (for release-acquire; or not necessarily for relaxed).

        For state-like variables, relaxed is often correct, unless it's a one-way flag where upon seeing it signaled you assume the producer has set some key properties in memory that you may now also consume (e.g. base::AtomicFlag).

    • File base/sampling_heap_profiler/poisson_allocation_sampler.cc:

      • Patch Set #10, Line 161: g_mute_hooked_samples = true;

        ditto

      • Patch Set #10, Line 171: DCHECK(g_mute_hooked_samples);

        .load(std::memory_order_relaxed)

      • Patch Set #10, Line 177: g_mute_hooked_samples = false;

        Let's use an explicit memory order here. Operators on atomics are bad form because they always use the strictest memory order and fail at expressing the intent.

        Here's a good talk on atomics and direct link to a specific section on why explicit memory barriers: https://youtu.be/ZQFzMfHIxng?t=2988

      • Patch Set #10, Line 182: std::atomic<PoissonAllocationSampler::ProfilingState>

        `ABSL_CONST_INIT` is a nice addition here to be explicit (though this is currently initialized as a POD or static-initializers checks on bots would complain)

        `ABSL_CONST_INIT` is like `constexpr` but without `const`

      • Patch Set #10, Line 215: return g_mute_hooked_samples;

        .load(std::memory_order_relaxed)

        (unless this method guarantees some properties to callers based on returning true, and that this property is set by thread A which set it before setting `g_mute_hooked_samples.store(true, std::memory_order_release)`

      • Patch Set #10, Line 438: memory_order_acquire

        `memory_order_acquire` inside a `DCHECK` doesn't make sense as it's altering the state of *other* memory for this thread based on whether this is running in a DCHECK build. `std::memory_order_relaxed` is always sufficient when reading the state of a variable without acting upon its content.

      • Patch Set #10, Line 439: profiling_state_ = ProfilingState::kRunning;

        Explicit .store() and memory barrier. The question to ask yourself is whether a reader seeing kRunning expects any of the memory previously set by this thread to also be visible? If not, memory_order_relaxed is sufficient; if so, memory_order_release is required (https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering).

        Since the state modified above is only `observers_` which is `GUARDED_BY(mutex_)` (and future reader/modifier of `observers_` will therefore have a happens-after relationship with it), I suspect there isn't memory state that's expected by a reader based on reading kRunning?

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Comment-Date: Wed, 11 Jan 2023 17:38:37 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Joe Mason (Gerrit)

    unread,
    Jan 11, 2023, 2:16:33 PM1/11/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette.

    View Change

    3 comments:

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • 1) First time I see std::memory_order_consume (I'm used to std::memory_order_acquire), looks like it […]

        Ah, I didn't notice the deprecation warning. I'll either go back to relaxed to switch to Release/Aquire.

        Other threads don't need to see writes right away. Which comment implies that? I'll reword it.

        Here's an example situation:

        Thread A calls malloc(), which calls RecordAlloc(p) and then returns `p`. Thread B calls free(p), which calls RecordFree(p).

        It's important that when `profiling_state_` changes from kNeverStarted to anything else, then IF Thread A sees the new value in RecordAlloc, Thread B must NOT see kNeverStarted in RecordFree. Does relaxed guarantee that?

        I think in this case the RecordAlloc inter-thread happens-before RecordFree, because RecordAlloc(p) is sequenced-before the return from malloc on Thread A, and free(p) / RecordFree(p) consume the return value of malloc. Is that enough to guarantee that IF thread A sees the write to `profiling_state_`, so will thead B?

    • File base/sampling_heap_profiler/poisson_allocation_sampler.cc:

      • Patch Set #10, Line 280: memory_order_consume

        I need to avoid this situation:

        Thread A sets `g_mute_hooked_samples` to true, then changes `profiling_state_` from `kNeverStarted` to `kRunning`.

        Thread B in this code reads `profiling_state_` as `kRunning` and `g_mute_hooked_samples` as false.

        If I understand right, `g_mute_hooked_samples` needs a release/acquire memory barrier to guarantee this, so that compiler doesn't reorder the `profiling_state_` write before the `g_mute_hooked_samples` write, or reorder the `profiling_state_` read after the `g_mute_hooked_samples` read. `profiling_state_` can itself can use relaxed. Is that correct?

      • The only reason this would need `memory_order_acquire` is if that's required to ensure that `RecordAlloc(p)` and `RecordFree(p)` from different threads see the same value of `profiling_state_`, as described above.

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Gabriel Charette <g...@chromium.org>
    Gerrit-Comment-Date: Wed, 11 Jan 2023 19:13:42 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Gabriel Charette <g...@chromium.org>
    Gerrit-MessageType: comment

    Gabriel Charette (Gerrit)

    unread,
    Jan 11, 2023, 3:02:28 PM1/11/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Joe Mason.

    View Change

    3 comments:

    • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

      • Ah, I didn't notice the deprecation warning. I'll either go back to relaxed to switch to Release/Aquire.

      • Other threads don't need to see writes right away. Which comment implies that? I'll reword it.

      • ```
        // Load with release-consume ordering to make sure RecordAlloc() and
        // RecordFree() in different threads see the same writes to
        // `profiling_state_`.
        ```

      • Here's an example situation:

        Thread A calls malloc(), which calls RecordAlloc(p) and then returns `p`. Thread B calls free(p), which calls RecordFree(p).

        It's important that when `profiling_state_` changes from kNeverStarted to anything else, then IF Thread A sees the new value in RecordAlloc, Thread B must NOT see kNeverStarted in RecordFree. Does relaxed guarantee that?

      • The choice of a memory order model doesn't change which value this load sees. What it does is change what *other* memory is visible as a result of the value read.
        So no memory order on *this* atomic variable guarantees that, but 👇...


      • > I think in this case the RecordAlloc inter-thread happens-before RecordFree, because RecordAlloc(p) is sequenced-before the return from malloc on Thread A, and free(p) / RecordFree(p) consume the return value of malloc. Is that enough to guarantee that IF thread A sees the write to `profiling_state_`, so will thead B?
      • Correct. What guarantees that RecordFree sees the value set in RecordAlloc is that (short of a rogue thread freeing random memory) there's an happens-after relationship between the return of malloc() and the call to free().

        In other words, as far as this relationship is concerned, `profiling_state_` doesn't even need to be atomic. It only needs to be atomic if other threads (which don't care about such guarantees) are racing to read it.

    • File base/sampling_heap_profiler/poisson_allocation_sampler.cc:

      • I need to avoid this situation: […]

        A memory barrier on X doesn't affect which value X.load() returns, it affects the visibility of *other* memory.

        In this case, if g_mute_hooked_samples is set before and read after setting/reading profiling_state_, the release-acquire relationship needs to be on profiling_state_.

        `profiling_state_.store(kRunning, std::memory_order_release)` means "make all the memory side-effects I have caused visible to any thread that reads-with-acquire-semantics the value I've set"

        A future thread B which calls `profiling_state_.load(std::memory_order_release)` and sees `kRunning` will also see anything (atomic or non-atomic) written before the matching release.

        Now. This only works if thread B knows **which** instance of kRunning this is (e.g. one time transition or Thread B somehow knew it was previously kNeverStarted). This is why we don't allow resetting `base::AtomicFlag`, the relationship only works the first time.
        Subsequent times have an ABA problem.

        For instance, if thread A can do the following:
        T0 {g_mute_hooked_samples = false; profiling_state_ = kNeverStarted}
        T1 {g_mute_hooked_samples = false; profiling_state_ = kRunning}
        T2 {g_mute_hooked_samples = false; profiling_state_ = kNeverStarted}
        T3 {g_mute_hooked_samples = true; profiling_state_ = kRunning}

        Now, when thread B sees kRunning at T4, there's no guarantee that it's seeing the kRunning set at T3, it could be reading T1's value. At which point the acquire-release relationship is meaningless.

        `std::memory_order_seq_cst` is the solution to this as it enforces a total ordering across all threads between all atomics.
        https://en.cppreference.com/w/cpp/atomic/memory_order#Sequentially-consistent_ordering

        I've never seen a case of this before in Chromium but this might be one? Hopefully kNeverStarted=>kRunning is a one-way transition and acquire-release is sufficient?

        Note that this also brings the question of whether g_mute_hooked_samples needs to be atomic? It doesn't w.r.t. this relationship but it might if threads that don't have ordering requirements are also poking it? Ideally only threads that have an happens-after relationship with it being set are reading it, in which case it doesn't need to be atomic.

      • The only reason this would need `memory_order_acquire` is if that's required to ensure that `RecordA […]

        Not required but may need seq_cst for ordering w.r.t. g_mute_hooked_samples as discussed

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 10
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Joe Mason <joenot...@google.com>
    Gerrit-Comment-Date: Wed, 11 Jan 2023 19:59:33 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Joe Mason <joenot...@google.com>

    Joe Mason (Gerrit)

    unread,
    Jan 11, 2023, 10:24:08 PM1/11/23
    to lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette.

    Patch set 12:Commit-Queue +1

    View Change

    10 comments:

      • > Ah, I didn't notice the deprecation warning. […]

        Great! Updated to relaxed then.

    • File base/sampling_heap_profiler/poisson_allocation_sampler.cc:

      • Changed it to compare_exchange since it's more obviously correct than a load and then a store.

      • Let's use an explicit memory order here. […]

        Done

      • `ABSL_CONST_INIT` is a nice addition here to be explicit (though this is currently initialized as a […]

        Done

      • .load(std::memory_order_relaxed) […]

        Done

      • A memory barrier on X doesn't affect which value X. […]

        Argh, I got it backwards. I really don't want to impose a total ordering just for a test-only feature. The only point of g_mute_hooked_samples is to prevent tests from flaking.

        Instead I moved all the state into one atomic, so there's no dependency between two variables. That makes it more complicated to update the state, but that's ok because updating the state is much, much more rare than reading it so it's ok for it to be heavier.

      • `memory_order_acquire` inside a `DCHECK` doesn't make sense as it's altering the state of *other* me […]

        Done

      • Not required but may need seq_cst for ordering w.r.t. […]

        Ack

    To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
    Gerrit-Change-Number: 4140359
    Gerrit-PatchSet: 12
    Gerrit-Owner: Joe Mason <joenot...@google.com>
    Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
    Gerrit-Reviewer: Joe Mason <joenot...@google.com>
    Gerrit-Attention: Gabriel Charette <g...@chromium.org>
    Gerrit-Comment-Date: Thu, 12 Jan 2023 03:21:37 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes

    Pinpoint perf (Gerrit)

    unread,
    Jan 16, 2023, 5:45:40 AM1/16/23
    to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

    Attention is currently required from: Gabriel Charette.

    📍 Job complete.

    See results at: https://pinpoint-dot-chromeperf.appspot.com/job/1563903d3a0000

    View Change

      To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
      Gerrit-Change-Number: 4140359
      Gerrit-PatchSet: 14
      Gerrit-Owner: Joe Mason <joenot...@google.com>
      Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
      Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
      Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
      Gerrit-Reviewer: Joe Mason <joenot...@google.com>
      Gerrit-Attention: Gabriel Charette <g...@chromium.org>
      Gerrit-Comment-Date: Mon, 16 Jan 2023 10:43:17 +0000

      Gabriel Charette (Gerrit)

      unread,
      Jan 16, 2023, 2:16:35 PM1/16/23
      to Joe Mason, lizeb...@chromium.org, wfh+...@chromium.org, Pinpoint perf, Gabriel Charette, Benoit Lize, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

      Attention is currently required from: Joe Mason.

      View Change

      3 comments:

      • File base/sampling_heap_profiler/poisson_allocation_sampler.h:

        • Patch Set #14, Line 122: enum class ProfilingState {

          In order to avoid cases where a caller checks `== kRunning` and forgets to also checks `== kRunningMutedForTesting`, it's preferable to hide this packing inside a class whose only member is an atomic bitpack.

          e.g. base::internal::TaskTracker::State

          This also removes the need for helpers like AtomicallyUpdateProfilingState

      • File base/sampling_heap_profiler/poisson_allocation_sampler.cc:

        • Patch Set #14, Line 192: ABSL_CONST_INIT std::atomic<PoissonAllocationSampler::ProfilingState>

          // static

        • Patch Set #14, Line 210: g_sampled_addresses_set.store(sampled_addresses, std::memory_order_release);

          Let's move changes to atomics not directly related to this CL to another CL? Makes things easier in case it breaks anything?

      To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
      Gerrit-Change-Number: 4140359
      Gerrit-PatchSet: 14
      Gerrit-Owner: Joe Mason <joenot...@google.com>
      Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
      Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
      Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
      Gerrit-Reviewer: Joe Mason <joenot...@google.com>
      Gerrit-Attention: Joe Mason <joenot...@google.com>
      Gerrit-Comment-Date: Mon, 16 Jan 2023 19:13:56 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Gerrit-MessageType: comment

      Joe Mason (Gerrit)

      unread,
      Jan 16, 2023, 3:26:18 PM1/16/23
      to Benoit Lize, lizeb...@chromium.org, wfh+...@chromium.org, Pinpoint perf, Gabriel Charette, Andre Kempe, Chromium LUCI CQ, chromium...@chromium.org

      Attention is currently required from: Joe Mason.

      Joe Mason removed Benoit Lize from this change.

      View Change

      To view, visit change 4140359. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: I99aee5565751aed0dc8796f12df0a1dbb26fcb27
      Gerrit-Change-Number: 4140359
      Gerrit-PatchSet: 14
      Gerrit-Owner: Joe Mason <joenot...@google.com>
      Gerrit-Reviewer: Andre Kempe <andre...@arm.com>
      Gerrit-Reviewer: Gabriel Charette <g...@chromium.org>
      Gerrit-Reviewer: Joe Mason <joenot...@google.com>
      Gerrit-Attention: Joe Mason <joenot...@google.com>
      Gerrit-MessageType: deleteReviewer
      Reply all
      Reply to author
      Forward
      0 new messages