[canvas] Add a feature to defer hibernation [chromium/src : main]

0 views
Skip to first unread message

Benoit Lize (Gerrit)

unread,
Sep 17, 2025, 12:01:32โ€ฏPMSep 17
to Jean-Philippe Gravel, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
Attention needed from Jean-Philippe Gravel

New activity on the change

Open in Gerrit

Related details

Attention is currently required from:
  • Jean-Philippe Gravel
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
Gerrit-Change-Number: 6954268
Gerrit-PatchSet: 2
Gerrit-Owner: Benoit Lize <li...@chromium.org>
Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
Gerrit-CC: Stephen Chenney <sche...@chromium.org>
Gerrit-Attention: Jean-Philippe Gravel <jpgr...@chromium.org>
Gerrit-Comment-Date: Wed, 17 Sep 2025 16:01:20 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Jean-Philippe Gravel (Gerrit)

unread,
Sep 17, 2025, 9:40:34โ€ฏPMSep 17
to Benoit Lize, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
Attention needed from Benoit Lize

Jean-Philippe Gravel added 18 comments

Commit Message
Line 15, Patchset 2 (Latest):- Wasteful: In case of rapid back and forth
Jean-Philippe Gravel . resolved

Also note that according to the `Blink.Canvas.HibernationEvents` histogram in UMA, 82% of hibernations abort because the tab does background rendering. This is definitely harmful because in these cases, we hibernated for no reason. This CL provides the mechanism to address this!

File third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
Line 2424, Patchset 2 (Latest): CanvasHibernationHandler::HibernationEvent::kHibernationScheduled, 1);
Jean-Philippe Gravel . unresolved

This is unfortunate. This test used to give us confidence that two visibility cycle in a row would only trigger hibernation once. How do we know that the code is well behaved now?

Could we add a new `HibernationEvent`, increased when hibernation is actually done? You could check that it has a count of `1` in this test, to make sure that hibernation only happened once despite being scheduled twice. It would also be useful to monitor the feature once launched, because otherwise, you'd have no (direct) way of knowing the number of time delayed hibernation was triggered.

I could similarly be useful to have an event incremented when the canvas is compressed, so we'd have visibility on the hit rate of that code path.

File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
File-level comment, Patchset 2 (Latest):
Jean-Philippe Gravel . unresolved

I think that there's something missing here. Originally, we called `HibernateOrLogFailure` on an idle task and this task ended up setting `image_`. From this point, `IsHibernating()` would return true. `IsHibernating` is what we check to know we must wake up from hibernation [if the page does background rendering](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1457-1485;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18), of if [the page becomes visible again](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1040-1042;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18). Because `HibernateOrLogFailure` was called as soon as idle (hopefully before the next JavaScript task, but maybe not?), `IsHibernating()` returned mostly the right value.

With the new code though, `IsHibernating()` will only start to return `true` after several minutes. This leaves plenty of time of the page to restart rendering in the background (82% of hibernation cases). If this happens, `Hibernate()` will run unimpeded because the page is still hidden. But that will hibernate the canvas while it's being used in the background.

Line 71, Patchset 2 (Parent): DCHECK(handlers_.Contains(handler));
Jean-Philippe Gravel . unresolved

What changed in this CL for `Unregister` to be called when `Register` wasn't?

Line 386, Patchset 2 (Latest): // The canvas was hibernated again since the task was posted, let the next
// task deal with it.
Jean-Philippe Gravel . unresolved

The comment describes the `else` case which isn't even there. Can you update the comment to describe the positive case instead? Maybe just prefixing with `If` would be enough: `If the canvas was hibernated ...`.

Line 463, Patchset 2 (Parent): if (hibernation_scheduled_) {
Jean-Philippe Gravel . unresolved

Have you verified that `InitiateHibernationIfNecessary` is never called multiple times for a given canvas and page visibility change event?

Line 475, Patchset 2 (Latest): epoch_++;
Jean-Philippe Gravel . unresolved

Nit: do `++epoch_` instead ([required by the style guide](https://google.github.io/styleguide/cppguide.html#Preincrement_and_Predecrement)).

File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
Line 99, Patchset 2 (Latest): auto params = GetParam();
Jean-Philippe Gravel . unresolved

Nit: avoid using `auto` โ€œmerely to avoid the inconvenience of writing an explicit type.โ€
https://google.github.io/styleguide/cppguide.html#Type_deduction

Same for the other new usages of `auto` below (except for the `base::MakeRefCounted` factory method because the type is already spelled explicitly as template parameter, that's one of the few cases where `auto` is recommended by https://abseil.io/tips/232).

Here however, the variable `params` provides very little value. You could very well just remove it and inline `GetParam()` below.

Line 242, Patchset 2 (Latest): ::testing::Combine(
Jean-Philippe Gravel . unresolved

Nit, add using declarations for `testing::` symbols, to improve clarity. This is recommended by internal guidelines, but also by the official GoogleTest documentation:

โ€œNote: gMock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by gMock. We omit such `using` statements in this section for brevity, but you should do it in your own code.โ€
https://google.github.io/googletest/gmock_cook_book.html

The idea is that GoogleTest statements are designed to roughly read like english sentenses, e.g. `EXPECT_THAT(foo, SizeIs(Lt(3)))` -> "expect that foo's size is less than 3". Adding namespace qualification everywhere hampers the clarity of these statements.

Line 330, Patchset 2 (Latest): if (!base::FeatureList::IsEnabled(features::kCanvas2DHibernationDefer)) {
GTEST_SKIP();
}
Jean-Philippe Gravel . unresolved

Why skipping this test? The original test seemed useful for the normal operation mode. Why drop the test coverage?

Line 366, Patchset 2 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundBeforeHibernationStarts) {
Jean-Philippe Gravel . unresolved

This test looks identical to `ForegroundTooEarly` above. Or am I missing something?.

Line 366, Patchset 2 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundBeforeHibernationStarts) {
Jean-Philippe Gravel . unresolved

Shouldn't this be something like "ForegroundBeforeEncodingStarts"? Hibernation did happen, `IsHibernating` is true.

Line 367, Patchset 2 (Latest): auto task_runner = base::MakeRefCounted<TestSingleThreadTaskRunner>();
Jean-Philippe Gravel . unresolved

Shouldn't the test do `handler.SetBackgroundTaskRunnerForTesting(task_runner);`? If this works without, why are all other tests doing it? Could you remove that from other tests?

Line 386, Patchset 2 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundAfterEncoding) {
Jean-Philippe Gravel . unresolved

The new test version seems to foregrounds **before** encoding, not after. Isn't it essentially testing the same thing as `ForegroundTooEarly` and the new test above? Could you keep logic waiting for the encoding?

Line 411, Patchset 2 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForAfterEncoding) {
Jean-Philippe Gravel . unresolved

Was this meaning to say "FlipFlop"?

Line 433, Patchset 2 (Latest): // EXPECT_TRUE(handler.IsHibernating());
Jean-Philippe Gravel . unresolved

Why the commented code? Delete or restore?

Line 442, Patchset 2 (Latest): delay = WaitForHibernation();
Jean-Philippe Gravel . unresolved

There's already a `WaitForHibernation()` on line 432. Isn't this one redundant?

Line 453, Patchset 2 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForBeforeEncoding) {
Jean-Philippe Gravel . unresolved

Same here (`FlipFlop`)?

Open in Gerrit

Related details

Attention is currently required from:
  • Benoit Lize
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
    Gerrit-Change-Number: 6954268
    Gerrit-PatchSet: 2
    Gerrit-Owner: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
    Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
    Gerrit-CC: Stephen Chenney <sche...@chromium.org>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Thu, 18 Sep 2025 01:40:30 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    AI Code Reviewer (Gerrit)

    unread,
    Sep 18, 2025, 8:18:05โ€ฏAMSep 18
    to Benoit Lize, Jean-Philippe Gravel, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
    Attention needed from Benoit Lize

    AI Code Reviewer added 3 comments

    File third_party/blink/common/features.cc
    Line 356, Patchset 3 (Latest):BASE_FEATURE(kCanvas2DHibernationDefer,
    AI Code Reviewer . unresolved

    Please keep features sorted by identifier name. `kCanvas2DHibernationDefer` should be placed after `kCanvas2DHibernation` to maintain alphabetical order. (Blink Style Guide: Feature definitions and associated constants)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    File third_party/blink/public/common/features.h
    Line 225, Patchset 3 (Latest):BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kCanvas2DHibernationDefer);
    AI Code Reviewer . unresolved

    Please keep feature declarations sorted by identifier name. `kCanvas2DHibernationDefer` should be placed after `kCanvas2DHibernation` to maintain alphabetical order. (Blink Style Guide: Feature declarations and associated constants)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.h
    Line 85, Patchset 3 (Latest): void SaveForHibernation(sk_sp<SkImage>&& image,
    AI Code Reviewer . unresolved

    nit: Per the style guide, obvious parameter names may be omitted from function declarations in header files. Consider removing the names for `image`, `recorder`, and `context` as their purpose is clear from their types. (Blink Style Guide: Naming - May leave obvious parameter names out of function declarations)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Benoit Lize
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
    Gerrit-Change-Number: 6954268
    Gerrit-PatchSet: 3
    Gerrit-Owner: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
    Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
    Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
    Gerrit-CC: Stephen Chenney <sche...@chromium.org>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Thu, 18 Sep 2025 12:18:01 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Benoit Lize (Gerrit)

    unread,
    Sep 18, 2025, 11:28:06โ€ฏAMSep 18
    to Chromium Metrics Reviews, AyeAye, AI Code Reviewer, Jean-Philippe Gravel, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, asvitkine...@chromium.org, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
    Attention needed from Jean-Philippe Gravel

    Benoit Lize added 17 comments

    Patchset-level comments
    File-level comment, Patchset 3 (Latest):
    Benoit Lize . resolved

    Thanks!

    File third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
    Line 2424, Patchset 2: CanvasHibernationHandler::HibernationEvent::kHibernationScheduled, 1);
    Jean-Philippe Gravel . unresolved

    This is unfortunate. This test used to give us confidence that two visibility cycle in a row would only trigger hibernation once. How do we know that the code is well behaved now?

    Could we add a new `HibernationEvent`, increased when hibernation is actually done? You could check that it has a count of `1` in this test, to make sure that hibernation only happened once despite being scheduled twice. It would also be useful to monitor the feature once launched, because otherwise, you'd have no (direct) way of knowing the number of time delayed hibernation was triggered.

    I could similarly be useful to have an event incremented when the canvas is compressed, so we'd have visibility on the hit rate of that code path.

    Benoit Lize

    The foreground / background cycles are tested in CanvasHibernationHandler tests, which are admittedly lower level.

    Added an element to the enum, and also fixed the enum, which was out of sync. Did not change the name of the histogram or enum, since it was the XML that was incorrect, not the emitting code that changed, and it's only adding a new value to the enum.

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
    Jean-Philippe Gravel . unresolved

    I think that there's something missing here. Originally, we called `HibernateOrLogFailure` on an idle task and this task ended up setting `image_`. From this point, `IsHibernating()` would return true. `IsHibernating` is what we check to know we must wake up from hibernation [if the page does background rendering](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1457-1485;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18), of if [the page becomes visible again](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1040-1042;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18). Because `HibernateOrLogFailure` was called as soon as idle (hopefully before the next JavaScript task, but maybe not?), `IsHibernating()` returned mostly the right value.

    With the new code though, `IsHibernating()` will only start to return `true` after several minutes. This leaves plenty of time of the page to restart rendering in the background (82% of hibernation cases). If this happens, `Hibernate()` will run unimpeded because the page is still hidden. But that will hibernate the canvas while it's being used in the background.

    Benoit Lize

    I guess there are a couple solutions here: we could either give up on hibernation when rendering happens in background, or only hibernate if the canvas hasn't been rendering for a while.

    The first one is more conservative and easier to implement, by bumping `epoch_` in `Clear()`. This is what I've done in this CL. wdyt?

    Line 71, Patchset 2 (Parent): DCHECK(handlers_.Contains(handler));
    Jean-Philippe Gravel . unresolved

    What changed in this CL for `Unregister` to be called when `Register` wasn't?

    Benoit Lize

    Added a comment in the code.

    Line 386, Patchset 2: // The canvas was hibernated again since the task was posted, let the next

    // task deal with it.
    Jean-Philippe Gravel . resolved

    The comment describes the `else` case which isn't even there. Can you update the comment to describe the positive case instead? Maybe just prefixing with `If` would be enough: `If the canvas was hibernated ...`.

    Benoit Lize

    Done

    Line 463, Patchset 2 (Parent): if (hibernation_scheduled_) {
    Jean-Philippe Gravel . unresolved

    Have you verified that `InitiateHibernationIfNecessary` is never called multiple times for a given canvas and page visibility change event?

    Benoit Lize

    The only place that calls this is CanvasRenderingContext2D::PageVisibilityChanged(), which is called once.

    And even if called several times, it is only a minor inefficiency, since it just posts a task that will do nothing.

    Line 475, Patchset 2: epoch_++;
    Jean-Philippe Gravel . resolved

    Nit: do `++epoch_` instead ([required by the style guide](https://google.github.io/styleguide/cppguide.html#Preincrement_and_Predecrement)).

    Benoit Lize

    Done

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
    Line 99, Patchset 2: auto params = GetParam();
    Jean-Philippe Gravel . resolved

    Nit: avoid using `auto` โ€œmerely to avoid the inconvenience of writing an explicit type.โ€
    https://google.github.io/styleguide/cppguide.html#Type_deduction

    Same for the other new usages of `auto` below (except for the `base::MakeRefCounted` factory method because the type is already spelled explicitly as template parameter, that's one of the few cases where `auto` is recommended by https://abseil.io/tips/232).

    Here however, the variable `params` provides very little value. You could very well just remove it and inline `GetParam()` below.

    Benoit Lize

    Done

    Line 242, Patchset 2: ::testing::Combine(
    Jean-Philippe Gravel . resolved

    Nit, add using declarations for `testing::` symbols, to improve clarity. This is recommended by internal guidelines, but also by the official GoogleTest documentation:

    โ€œNote: gMock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by gMock. We omit such `using` statements in this section for brevity, but you should do it in your own code.โ€
    https://google.github.io/googletest/gmock_cook_book.html

    The idea is that GoogleTest statements are designed to roughly read like english sentenses, e.g. `EXPECT_THAT(foo, SizeIs(Lt(3)))` -> "expect that foo's size is less than 3". Adding namespace qualification everywhere hampers the clarity of these statements.

    Benoit Lize

    Done

    Line 330, Patchset 2: if (!base::FeatureList::IsEnabled(features::kCanvas2DHibernationDefer)) {
    GTEST_SKIP();
    }
    Jean-Philippe Gravel . unresolved

    Why skipping this test? The original test seemed useful for the normal operation mode. Why drop the test coverage?

    Benoit Lize

    Done.

    Line 366, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundBeforeHibernationStarts) {
    Jean-Philippe Gravel . resolved

    Shouldn't this be something like "ForegroundBeforeEncodingStarts"? Hibernation did happen, `IsHibernating` is true.

    Benoit Lize

    Done

    Line 366, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundBeforeHibernationStarts) {
    Jean-Philippe Gravel . resolved

    This test looks identical to `ForegroundTooEarly` above. Or am I missing something?.

    Benoit Lize

    Done

    Line 367, Patchset 2: auto task_runner = base::MakeRefCounted<TestSingleThreadTaskRunner>();
    Jean-Philippe Gravel . resolved

    Shouldn't the test do `handler.SetBackgroundTaskRunnerForTesting(task_runner);`? If this works without, why are all other tests doing it? Could you remove that from other tests?

    Benoit Lize

    Done

    Line 386, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundAfterEncoding) {
    Jean-Philippe Gravel . unresolved

    The new test version seems to foregrounds **before** encoding, not after. Isn't it essentially testing the same thing as `ForegroundTooEarly` and the new test above? Could you keep logic waiting for the encoding?

    Benoit Lize

    Changed the tests, to avoid redundant, and keep the same / better coverage. Thanks for the comment.

    Line 411, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForAfterEncoding) {
    Jean-Philippe Gravel . resolved

    Was this meaning to say "FlipFlop"?

    Benoit Lize

    Done

    Line 433, Patchset 2: // EXPECT_TRUE(handler.IsHibernating());
    Jean-Philippe Gravel . resolved

    Why the commented code? Delete or restore?

    Benoit Lize

    Done

    Line 453, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForBeforeEncoding) {
    Jean-Philippe Gravel . resolved

    Same here (`FlipFlop`)?

    Benoit Lize

    Done

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Jean-Philippe Gravel
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
    Gerrit-Change-Number: 6954268
    Gerrit-PatchSet: 3
    Gerrit-Owner: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
    Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
    Gerrit-CC: Chromium Metrics Reviews <chromium-met...@google.com>
    Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
    Gerrit-CC: Stephen Chenney <sche...@chromium.org>
    Gerrit-Attention: Jean-Philippe Gravel <jpgr...@chromium.org>
    Gerrit-Comment-Date: Thu, 18 Sep 2025 15:27:41 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Jean-Philippe Gravel <jpgr...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Jean-Philippe Gravel (Gerrit)

    unread,
    Sep 18, 2025, 10:13:04โ€ฏPMSep 18
    to Benoit Lize, Chromium Metrics Reviews, AyeAye, AI Code Reviewer, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, asvitkine...@chromium.org, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
    Attention needed from Benoit Lize

    Jean-Philippe Gravel added 15 comments

    File third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
    Line 2424, Patchset 2: CanvasHibernationHandler::HibernationEvent::kHibernationScheduled, 1);
    Jean-Philippe Gravel . resolved

    This is unfortunate. This test used to give us confidence that two visibility cycle in a row would only trigger hibernation once. How do we know that the code is well behaved now?

    Could we add a new `HibernationEvent`, increased when hibernation is actually done? You could check that it has a count of `1` in this test, to make sure that hibernation only happened once despite being scheduled twice. It would also be useful to monitor the feature once launched, because otherwise, you'd have no (direct) way of knowing the number of time delayed hibernation was triggered.

    I could similarly be useful to have an event incremented when the canvas is compressed, so we'd have visibility on the hit rate of that code path.

    Benoit Lize

    The foreground / background cycles are tested in CanvasHibernationHandler tests, which are admittedly lower level.

    Added an element to the enum, and also fixed the enum, which was out of sync. Did not change the name of the histogram or enum, since it was the XML that was incorrect, not the emitting code that changed, and it's only adding a new value to the enum.

    Jean-Philippe Gravel

    Added an element to the enum

    Sounds good.

    and also fixed the enum, which was out of sync

    Good catch! Thanks for fixing this.

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.h
    Line 85, Patchset 3 (Latest): void SaveForHibernation(sk_sp<SkImage>&& image,
    AI Code Reviewer . unresolved

    nit: Per the style guide, obvious parameter names may be omitted from function declarations in header files. Consider removing the names for `image`, `recorder`, and `context` as their purpose is clear from their types. (Blink Style Guide: Naming - May leave obvious parameter names out of function declarations)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    Jean-Philippe Gravel

    The style guide says "may omit", which I take as an optional recommendation. FWIW, I'm not a fan of this guideline because it prevents clang-tidy from validating `/*parameter_name=*/` comments at call sites. Here, `recorder` is a pointer, so what if a caller ever wanted to do `/*recorder=*/nullptr`? That doesn't really make sense in this particular example, but it goes to show that this general guideline is flawed.

    I wonder if this recommendation is still up to date. Maybe it predates clang-tidy's check?

    In any case, don't mind me. Feel free to follow the recommendation if you want. It's in the style guide! ;)

    Line 60, Patchset 3 (Latest): kMaxValue = kHibernationAbortedBecauseNoSurface,
    Jean-Philippe Gravel . unresolved

    Update kMaxValue.

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
    Jean-Philippe Gravel . unresolved

    I think that there's something missing here. Originally, we called `HibernateOrLogFailure` on an idle task and this task ended up setting `image_`. From this point, `IsHibernating()` would return true. `IsHibernating` is what we check to know we must wake up from hibernation [if the page does background rendering](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1457-1485;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18), of if [the page becomes visible again](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1040-1042;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18). Because `HibernateOrLogFailure` was called as soon as idle (hopefully before the next JavaScript task, but maybe not?), `IsHibernating()` returned mostly the right value.

    With the new code though, `IsHibernating()` will only start to return `true` after several minutes. This leaves plenty of time of the page to restart rendering in the background (82% of hibernation cases). If this happens, `Hibernate()` will run unimpeded because the page is still hidden. But that will hibernate the canvas while it's being used in the background.

    Benoit Lize

    I guess there are a couple solutions here: we could either give up on hibernation when rendering happens in background, or only hibernate if the canvas hasn't been rendering for a while.

    The first one is more conservative and easier to implement, by bumping `epoch_` in `Clear()`. This is what I've done in this CL. wdyt?

    Jean-Philippe Gravel

    Increasing `epoch_` sounds reasonable. But I wonder what will happen if you toggle between tabs a lot. Say you have many tabs each with lots of canvases and you ctrl-tab constantly for 5 minutes. How many pending tasks will accumulate? Can this be a problem? Is there a way of actively cancelling tasks?

    Line 71, Patchset 2 (Parent): DCHECK(handlers_.Contains(handler));
    Jean-Philippe Gravel . unresolved

    What changed in this CL for `Unregister` to be called when `Register` wasn't?

    Benoit Lize

    Added a comment in the code.

    Jean-Philippe Gravel

    You mean this comment?
    ```
    // Hibernation may not be pending, we may not be registered.
    ```
    Comments should explains the why, but not the what. I still understand how it's possible for `Clear()` to be called if `Register()` wasn't. All calls to `Clear()` are guarded by `if (IsHibernating())` checks and `IsHibernating()` is only `true` if `Register()` is called. Isn't it?

    That being said, I suppose we are better off without the `DCHECK` regardless... It's not protecting against anything harmful. `handlers_.erase(handler);` is a no-op if `handler` isn't in `handlers_`, right?

    Line 356, Patchset 3 (Latest): ++epoch_;
    Jean-Philippe Gravel . unresolved

    Please add a test de-hibernating while the page is hidden, simulating background rendering? I think that's a very important feature of this CL.

    Line 357, Patchset 3 (Latest): // Hibernation may not be pending, we may not be registered.
    Jean-Philippe Gravel . unresolved

    Following up on the other comment about the `DCHECK` in `Unregister`. If my understanding is correct that `Clear()` is only ever called when we `IsHibernating()` is true, it's not true that "Hibernation may not be pending". I'd just remove the comment.

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
    Line 242, Patchset 3 (Latest):using ::testing::Bool;
    using ::testing::Combine;
    using ::testing::Values;
    Jean-Philippe Gravel . unresolved

    Move these to line 37, with the other using declarations.

    For bonus point (optionally), you could move all 4 using declarations to line 39, right after opening the anonymous namespace. This is recommended in https://abseil.io/tips/119:

    โ€œDeclare namespace aliases and using-declarations inside the innermost namespace, whether named or anonymous. (Do not add an anonymous namespace just for this purpose.)โ€

    Line 324, Patchset 3 (Latest): task_environment_.FastForwardBy(
    CanvasHibernationHandler::kBeforeCompressionDelay - delay -
    base::Seconds(1));
    Jean-Philippe Gravel . unresolved
    Is this statement needed? Wouldn't it be equivalent to do the following?
    ```
    auto delay = WaitForHibernation();
    EXPECT_TRUE(handler.IsHibernating());
    SetPageVisible(&delegate, &handler, platform, true);
    task_environment_.FastForwardBy(
    CanvasHibernationHandler::kBeforeCompressionDelay - delay);
    ```
    Line 367, Patchset 2: auto task_runner = base::MakeRefCounted<TestSingleThreadTaskRunner>();
    Jean-Philippe Gravel . unresolved

    Shouldn't the test do `handler.SetBackgroundTaskRunnerForTesting(task_runner);`? If this works without, why are all other tests doing it? Could you remove that from other tests?

    Benoit Lize

    Done

    Jean-Philippe Gravel

    So, why isn't `SetBackgroundTaskRunnerForTesting` needed here? Is it needed in other tests?

    Line 388, Patchset 3 (Parent):TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForBeforeEncoding) {
    Jean-Philippe Gravel . unresolved

    Why removing this test? It looked useful. `ForegroundFlipFlopDuringCompression` tests toggling visibility after compression but before the OnEncoded callback, whereas this test was toggling visibility before encoding. Isn't it?

    Line 390, Patchset 3 (Latest): ForegroundAfterHibernationBeforeCompression) {
    Jean-Philippe Gravel . unresolved

    How is this test different than `ForegroundBeforeCompression`? Both foreground the page after hibernation and before compression.

    Line 390, Patchset 3 (Latest): ForegroundAfterHibernationBeforeCompression) {
    Jean-Philippe Gravel . unresolved
    There's one test missing. We are testing:
    - foregrounding before hibernation starts
    - foregrounding after hibernation but before compression.

    We are not however testing foregrounding **during** encoding, that is, after compression but before the `OnEncoded` callback is invoked. There's a FlipFlopDuringCompression, but I suppose that's a different use case because that's testing the epoch logic.

    Line 411, Patchset 3 (Latest):TEST_P(CanvasHibernationHandlerTest, ForegroundFlipFlopDuringCompression) {
    Jean-Philippe Gravel . unresolved

    Shouldn't there also be a test flip-flopping before hibernation?

    File tools/metrics/histograms/metadata/blink/enums.xml
    Line 84, Patchset 3 (Latest):<enum name="CanvasHibernationEvent">
    <int value="0" label="Scheduled"/>
    <int value="1"
    label="Aborted due to destruction while hibernate was pending"/>
    <int value="2" label="Aborted due to pending destruction (obsolete)"/>
    <int value="3" label="Aborted due to visibility change"/>
    <int value="4" label="Aborted due to GPU Context loss"/>
    <int value="5" label="Aborted due to switch to unaccelerated rendering"/>
    <int value="6" label="Aborted due to allocation failure (obsolete)"/>
    <int value="7" label="Aborted due to snapshot failure"/>
    <int value="8" label="Ended normally"/>
    <int value="9" label="Ended with switch to background rendering"/>
    <int value="10" label="Ended with fallback to software"/>
    <int value="11" label="Ended with teardown"/>
    <int value="12" label="Aborted because there was no surface"/>
    <int value="13"
    label="Aborted because of epoch mismatch (e.g. fg/bg transitions)"/>
    </enum>
    Jean-Philippe Gravel . unresolved

    Hum. Does this mean that the numbers we are seeing in UMA aren't label correctly? Have I been interpreting the numbers wrong this whole time? That's a bummer.

    Looking closer, I realized that the histograms for normal vs. background rendering aren't even recorded correctly. I sent https://crrev.com/c/6968030 to fix this.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Benoit Lize
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
    Gerrit-Change-Number: 6954268
    Gerrit-PatchSet: 3
    Gerrit-Owner: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
    Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
    Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
    Gerrit-CC: Chromium Metrics Reviews <chromium-met...@google.com>
    Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
    Gerrit-CC: Stephen Chenney <sche...@chromium.org>
    Gerrit-Attention: Benoit Lize <li...@chromium.org>
    Gerrit-Comment-Date: Fri, 19 Sep 2025 02:12:59 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Benoit Lize <li...@chromium.org>
    Comment-In-Reply-To: Jean-Philippe Gravel <jpgr...@chromium.org>
    Comment-In-Reply-To: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Benoit Lize (Gerrit)

    unread,
    Dec 16, 2025, 11:41:42โ€ฏAMย (4 days ago)ย Dec 16
    to Chromium Metrics Reviews, AyeAye, AI Code Reviewer, Jean-Philippe Gravel, Chromium LUCI CQ, chromium...@chromium.org, Dirk Schulze, Stephen Chenney, asvitkine...@chromium.org, blink-re...@chromium.org, blink-reviews-p...@chromium.org, blink-...@chromium.org, drott+bl...@chromium.org, fmalit...@chromium.org, fserb...@chromium.org, kinuko...@chromium.org
    Attention needed from Jean-Philippe Gravel

    Benoit Lize added 20 comments

    Patchset-level comments
    File-level comment, Patchset 5 (Latest):
    Benoit Lize . resolved

    Thanks!

    Apologies for the very long delay, getting back to it now.

    File third_party/blink/common/features.cc
    Line 356, Patchset 3:BASE_FEATURE(kCanvas2DHibernationDefer,
    AI Code Reviewer . resolved

    Please keep features sorted by identifier name. `kCanvas2DHibernationDefer` should be placed after `kCanvas2DHibernation` to maintain alphabetical order. (Blink Style Guide: Feature definitions and associated constants)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:


    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    Benoit Lize

    Done

    File third_party/blink/public/common/features.h
    Line 225, Patchset 3:BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kCanvas2DHibernationDefer);
    AI Code Reviewer . resolved

    Please keep feature declarations sorted by identifier name. `kCanvas2DHibernationDefer` should be placed after `kCanvas2DHibernation` to maintain alphabetical order. (Blink Style Guide: Feature declarations and associated constants)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:


    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    Benoit Lize

    Done

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.h
    Line 85, Patchset 3: void SaveForHibernation(sk_sp<SkImage>&& image,
    AI Code Reviewer . resolved

    nit: Per the style guide, obvious parameter names may be omitted from function declarations in header files. Consider removing the names for `image`, `recorder`, and `context` as their purpose is clear from their types. (Blink Style Guide: Naming - May leave obvious parameter names out of function declarations)

    _To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **Won't fix**: reason | **b/<bug_id>** | **Invalid:** reason

    This comment was generated by [Experimental Blink C++ Code Review Agent](http://go/blink-c++-code-review-agent).AI reviews can sometimes be inaccurate; We appreciate your ๐Ÿ™ feedback ๐Ÿ™ to help us improve.[File a bug](http://go/blink-c++-code-review-agent-feedback) | [Provide feedback on chat](https://chat.google.com/room/AAQA0zhQHe0?cls=4) | [Opt-out](https://ganpati2.corp.google.com/group/peep-genai-blink-agent-optout.prod)_

    Jean-Philippe Gravel

    The style guide says "may omit", which I take as an optional recommendation. FWIW, I'm not a fan of this guideline because it prevents clang-tidy from validating `/*parameter_name=*/` comments at call sites. Here, `recorder` is a pointer, so what if a caller ever wanted to do `/*recorder=*/nullptr`? That doesn't really make sense in this particular example, but it goes to show that this general guideline is flawed.

    I wonder if this recommendation is still up to date. Maybe it predates clang-tidy's check?

    In any case, don't mind me. Feel free to follow the recommendation if you want. It's in the style guide! ;)

    Benoit Lize

    Yes, I also prefer keeping parameter names, for the same reason. Keeping it for consistency with the rest of the code as well.

    Line 60, Patchset 3: kMaxValue = kHibernationAbortedBecauseNoSurface,
    Jean-Philippe Gravel . resolved

    Update kMaxValue.

    Benoit Lize

    Done

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
    Jean-Philippe Gravel . unresolved

    I think that there's something missing here. Originally, we called `HibernateOrLogFailure` on an idle task and this task ended up setting `image_`. From this point, `IsHibernating()` would return true. `IsHibernating` is what we check to know we must wake up from hibernation [if the page does background rendering](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1457-1485;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18), of if [the page becomes visible again](https://crsrc.org/c/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc;l=1040-1042;drc=48d6f7175422b2c969c14258f9f8d5b196c28d18). Because `HibernateOrLogFailure` was called as soon as idle (hopefully before the next JavaScript task, but maybe not?), `IsHibernating()` returned mostly the right value.

    With the new code though, `IsHibernating()` will only start to return `true` after several minutes. This leaves plenty of time of the page to restart rendering in the background (82% of hibernation cases). If this happens, `Hibernate()` will run unimpeded because the page is still hidden. But that will hibernate the canvas while it's being used in the background.

    Benoit Lize

    I guess there are a couple solutions here: we could either give up on hibernation when rendering happens in background, or only hibernate if the canvas hasn't been rendering for a while.

    The first one is more conservative and easier to implement, by bumping `epoch_` in `Clear()`. This is what I've done in this CL. wdyt?

    Jean-Philippe Gravel

    Increasing `epoch_` sounds reasonable. But I wonder what will happen if you toggle between tabs a lot. Say you have many tabs each with lots of canvases and you ctrl-tab constantly for 5 minutes. How many pending tasks will accumulate? Can this be a problem? Is there a way of actively cancelling tasks?

    Benoit Lize

    The cost of a single task is ~2-3us, and looking at the implementation of CancellableTask, is fairly similar to what's being done here, possibly more expensive, on top of being less easy to use (since you need to keep a tab on all the TaskHandle objects).
    https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h;drc=aff3b5b1f9a377ec59b599200d2fbe6611941361;l=78

    So I am not very worried about the cost (I don't think a user can switch tabs more than every 100ms, and even with 100 canvas elements per page, this would still be 0.01% of CPU time), and think this is the simpler approach.

    Line 71, Patchset 2 (Parent): DCHECK(handlers_.Contains(handler));
    Jean-Philippe Gravel . unresolved

    What changed in this CL for `Unregister` to be called when `Register` wasn't?

    Benoit Lize

    Added a comment in the code.

    Jean-Philippe Gravel

    You mean this comment?
    ```
    // Hibernation may not be pending, we may not be registered.
    ```
    Comments should explains the why, but not the what. I still understand how it's possible for `Clear()` to be called if `Register()` wasn't. All calls to `Clear()` are guarded by `if (IsHibernating())` checks and `IsHibernating()` is only `true` if `Register()` is called. Isn't it?

    That being said, I suppose we are better off without the `DCHECK` regardless... It's not protecting against anything harmful. `handlers_.erase(handler);` is a no-op if `handler` isn't in `handlers_`, right?

    Benoit Lize

    I think this is true, but wasn't certain enough, and as you say, it's a noop if the handler is not registered.

    Line 356, Patchset 3: ++epoch_;
    Jean-Philippe Gravel . resolved

    Please add a test de-hibernating while the page is hidden, simulating background rendering? I think that's a very important feature of this CL.

    Benoit Lize

    This is already tested, added a comment.

    Line 357, Patchset 3: // Hibernation may not be pending, we may not be registered.
    Jean-Philippe Gravel . resolved

    Following up on the other comment about the `DCHECK` in `Unregister`. If my understanding is correct that `Clear()` is only ever called when we `IsHibernating()` is true, it's not true that "Hibernation may not be pending". I'd just remove the comment.

    Benoit Lize

    Done

    File third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
    Line 242, Patchset 3:using ::testing::Bool;

    using ::testing::Combine;
    using ::testing::Values;
    Jean-Philippe Gravel . resolved

    Move these to line 37, with the other using declarations.

    For bonus point (optionally), you could move all 4 using declarations to line 39, right after opening the anonymous namespace. This is recommended in https://abseil.io/tips/119:

    โ€œDeclare namespace aliases and using-declarations inside the innermost namespace, whether named or anonymous. (Do not add an anonymous namespace just for this purpose.)โ€

    Benoit Lize

    Done

    Line 242, Patchset 3:using ::testing::Bool;

    using ::testing::Combine;
    using ::testing::Values;
    Jean-Philippe Gravel . resolved

    Move these to line 37, with the other using declarations.

    For bonus point (optionally), you could move all 4 using declarations to line 39, right after opening the anonymous namespace. This is recommended in https://abseil.io/tips/119:

    โ€œDeclare namespace aliases and using-declarations inside the innermost namespace, whether named or anonymous. (Do not add an anonymous namespace just for this purpose.)โ€

    Benoit Lize

    Done

    Line 324, Patchset 3: task_environment_.FastForwardBy(

    CanvasHibernationHandler::kBeforeCompressionDelay - delay -
    base::Seconds(1));
    Jean-Philippe Gravel . resolved
    Is this statement needed? Wouldn't it be equivalent to do the following?
    ```
    auto delay = WaitForHibernation();
    EXPECT_TRUE(handler.IsHibernating());
    SetPageVisible(&delegate, &handler, platform, true);
    task_environment_.FastForwardBy(
    CanvasHibernationHandler::kBeforeCompressionDelay - delay);
    ```
    Benoit Lize

    Done

    Line 324, Patchset 3: task_environment_.FastForwardBy(

    CanvasHibernationHandler::kBeforeCompressionDelay - delay -
    base::Seconds(1));
    Jean-Philippe Gravel . resolved
    Is this statement needed? Wouldn't it be equivalent to do the following?
    ```
    auto delay = WaitForHibernation();
    EXPECT_TRUE(handler.IsHibernating());
    SetPageVisible(&delegate, &handler, platform, true);
    task_environment_.FastForwardBy(
    CanvasHibernationHandler::kBeforeCompressionDelay - delay);
    ```
    Benoit Lize

    Done

    Line 330, Patchset 2: if (!base::FeatureList::IsEnabled(features::kCanvas2DHibernationDefer)) {
    GTEST_SKIP();
    }
    Jean-Philippe Gravel . resolved

    Why skipping this test? The original test seemed useful for the normal operation mode. Why drop the test coverage?

    Benoit Lize

    Done.

    Benoit Lize

    Done

    Line 367, Patchset 2: auto task_runner = base::MakeRefCounted<TestSingleThreadTaskRunner>();
    Jean-Philippe Gravel . unresolved

    Shouldn't the test do `handler.SetBackgroundTaskRunnerForTesting(task_runner);`? If this works without, why are all other tests doing it? Could you remove that from other tests?

    Benoit Lize

    Done

    Jean-Philippe Gravel

    So, why isn't `SetBackgroundTaskRunnerForTesting` needed here? Is it needed in other tests?

    Benoit Lize

    The TaskEnvironment runs the thread pool tasks on the same thread as the main thread tasks, and since these tasks are not delayed, they would run all at once. Using an explicit background task runner allows to change things while compression has been posted, but the main thread callback hasn't executed.

    It also allows to distinguish the cases of "compression task hasn't been posted" from the "compression happened, the result was discarded".

    Line 386, Patchset 2:TEST_P(CanvasHibernationHandlerTest, ForegroundAfterEncoding) {
    Jean-Philippe Gravel . resolved

    The new test version seems to foregrounds **before** encoding, not after. Isn't it essentially testing the same thing as `ForegroundTooEarly` and the new test above? Could you keep logic waiting for the encoding?

    Benoit Lize

    Changed the tests, to avoid redundant, and keep the same / better coverage. Thanks for the comment.

    Benoit Lize

    Done

    Line 388, Patchset 3 (Parent):TEST_P(CanvasHibernationHandlerTest, ForegroundFlipForBeforeEncoding) {
    Jean-Philippe Gravel . unresolved

    Why removing this test? It looked useful. `ForegroundFlipFlopDuringCompression` tests toggling visibility after compression but before the OnEncoded callback, whereas this test was toggling visibility before encoding. Isn't it?

    Benoit Lize

    The background compression task is static, does not acquire locks nor look at the main thread state, so it is not relevant when it runs, which is why I removed this test. I can bring it back, but it felt redundant here.

    Line 390, Patchset 3: ForegroundAfterHibernationBeforeCompression) {
    Jean-Philippe Gravel . unresolved
    There's one test missing. We are testing:
    - foregrounding before hibernation starts
    - foregrounding after hibernation but before compression.

    We are not however testing foregrounding **during** encoding, that is, after compression but before the `OnEncoded` callback is invoked. There's a FlipFlopDuringCompression, but I suppose that's a different use case because that's testing the epoch logic.

    Benoit Lize

    Added this test, I think it is effectively covered by the other test, but you're right, better be explicit.

    Line 411, Patchset 3:TEST_P(CanvasHibernationHandlerTest, ForegroundFlipFlopDuringCompression) {
    Jean-Philippe Gravel . unresolved

    Shouldn't there also be a test flip-flopping before hibernation?

    Benoit Lize

    This is covered by the ForegroundBackgroundWithDelay test, which tests multiple such transitions, and that the canvas eventually hibernates.

    File tools/metrics/histograms/metadata/blink/enums.xml
    Line 84, Patchset 3:<enum name="CanvasHibernationEvent">

    <int value="0" label="Scheduled"/>
    <int value="1"
    label="Aborted due to destruction while hibernate was pending"/>
    <int value="2" label="Aborted due to pending destruction (obsolete)"/>
    <int value="3" label="Aborted due to visibility change"/>
    <int value="4" label="Aborted due to GPU Context loss"/>
    <int value="5" label="Aborted due to switch to unaccelerated rendering"/>
    <int value="6" label="Aborted due to allocation failure (obsolete)"/>
    <int value="7" label="Aborted due to snapshot failure"/>
    <int value="8" label="Ended normally"/>
    <int value="9" label="Ended with switch to background rendering"/>
    <int value="10" label="Ended with fallback to software"/>
    <int value="11" label="Ended with teardown"/>
    <int value="12" label="Aborted because there was no surface"/>
    <int value="13"
    label="Aborted because of epoch mismatch (e.g. fg/bg transitions)"/>
    </enum>
    Jean-Philippe Gravel . resolved

    Hum. Does this mean that the numbers we are seeing in UMA aren't label correctly? Have I been interpreting the numbers wrong this whole time? That's a bummer.

    Looking closer, I realized that the histograms for normal vs. background rendering aren't even recorded correctly. I sent https://crrev.com/c/6968030 to fix this.

    Benoit Lize

    Yes, this is my understanding.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Jean-Philippe Gravel
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement is not satisfiedCode-Owners
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: I0e989fae20618a1e73fe7b5e3a3a0e685e007224
      Gerrit-Change-Number: 6954268
      Gerrit-PatchSet: 5
      Gerrit-Owner: Benoit Lize <li...@chromium.org>
      Gerrit-Reviewer: Benoit Lize <li...@chromium.org>
      Gerrit-Reviewer: Jean-Philippe Gravel <jpgr...@chromium.org>
      Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Gerrit-CC: Chromium Metrics Reviews <chromium-met...@google.com>
      Gerrit-CC: Dirk Schulze <dsch...@chromium.org>
      Gerrit-CC: Stephen Chenney <sche...@chromium.org>
      Gerrit-Attention: Jean-Philippe Gravel <jpgr...@chromium.org>
      Gerrit-Comment-Date: Tue, 16 Dec 2025 16:41:25 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Benoit Lize <li...@chromium.org>
      Comment-In-Reply-To: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Comment-In-Reply-To: Jean-Philippe Gravel <jpgr...@chromium.org>
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy
      Reply all
      Reply to author
      Forward
      0 new messages