[task] Use TaskEnvironment in blink platform tests [chromium/src : main]

0 views
Skip to first unread message

Etienne Pierre-Doray (Gerrit)

unread,
Apr 1, 2026, 2:55:27 PM (24 hours ago) Apr 1
to Scott Haseley, Jacob Hady, Chromium LUCI CQ, chromium...@chromium.org, AyeAye, penghuan...@chromium.org, chrome-intelligence-te...@google.com, cblume...@chromium.org, chrome-intell...@chromium.org, devtools...@chromium.org, kinuko...@chromium.org, chikamu...@chromium.org, scheduler-...@chromium.org, blink-...@chromium.org
Attention needed from Scott Haseley

Etienne Pierre-Doray added 10 comments

Patchset-level comments
File-level comment, Patchset 36 (Latest):
Etienne Pierre-Doray . resolved

PTAL
The CL is quite big, but mostly mechanical (I highlighted the subtleties).
All tests are independent, but let me know if I should break it down in multiple CLs.

File third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
Line 74, Patchset 34: task_environment_.AdvanceClock(
now.SnappedToNextTick(base::TimeTicks(), base::Hours(1)) - now);
Etienne Pierre-Doray . resolved

Whereas we previously set expectation relative to TimeTicks(), MOCK_TIME will give us a random start time.
This is needed to align time on (at least) 1h boundary, and expectations below are updated to be relative to start_time_.

File third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
Line 755, Patchset 36 (Parent): void SimulateMainThreadInputHandlingCompositorTask(
Etienne Pierre-Doray . resolved

Unused

Line 761, Patchset 36 (Latest): void SimulateMainThreadCompositor(base::TimeTicks frame_time,
Etienne Pierre-Doray . resolved

(this is the trickiest bit)
Previously: RunUntilIdle() (from caller) relies on TestMockTimeTaskRunner that would pump all immediate tasks. SimulateMainThreadCompositorTask does AdvanceClock(), but the TestMockTimeTaskRunner doesn't re-evaluate time.

TaskEnvironment will re-evaluate time between each task and run tasks that become ready after SimulateMainThreadCompositorTask's AdvanceClock.

Solution: all relates tests want to interleave MainThreadCompositor with other tasks and see what gets starve. Instead of relying on RunUntilIdle() subtleties, I've made this a PostDelayedTask with the next frame time, so that the scheduler gets a chance to run tasks in between.

Line 847, Patchset 36 (Latest): base::RunLoop run_loop;
compositor_task_runner_->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
DoMainFrame();
SimulateMainThreadCompositorTask(base::Milliseconds(1000));
run_loop.Quit();
}));
run_loop.Run();
Etienne Pierre-Doray . resolved

This would previously rely on the fact that nothing runs between DoMainFrame() (from caller) and SimulateMainThreadCompositorTask(); this isn't always true, so I moved DoMainFrame() inside the task to make sure the scheduler always considers this task "main frame"

https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc;l=1127?q=MainThreadSchedulerImpl::WillBeginFrame&ss=chromium

Line 2529, Patchset 36 (Parent): EXPECT_EQ(2u, count) << "i = " << i;
Etienne Pierre-Doray . resolved

This seems a consequence of RunUntilIdle() subtlety, but 1u is the desired behavior AFAICT.

Line 2706, Patchset 36 (Parent): EXPECT_EQ(279u, run_order.size());
Etienne Pierre-Doray . resolved

This seems a consequence of RunUntilIdle() subtlety, but 0u is the desired behavior AFAICT.
I couldn't find an explanation in history for 279.

Line 2822, Patchset 36 (Latest): base::test::TaskEnvironment::TimeSource::SYSTEM_TIME) {}
Etienne Pierre-Doray . resolved

SequenceManager doesn't support nesting TimeDomain (which both TaskEnvironment MOCK_TIME and EnableVirtualTime rely on).
But these tests don't actually need MOCK_TIME.

File third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
Line 288, Patchset 36 (Latest): base::test::TaskEnvironment::ThreadingMode::DEFAULT) {}
Etienne Pierre-Doray . resolved

Ideally this would be ThreadingMode::MAIN_THREAD_ONLY, but Android uses the thread pool in SelfCompactionManager::OnRunningCompact() (this is true ToT)

File third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl_unittest.cc
Line 283, Patchset 36 (Parent): EXPECT_THAT(tasks, ElementsAre(base::TimeTicks() + base::Seconds(1),
Etienne Pierre-Doray . resolved

The test fixture starts with TimeTicks() + 5ms, which shifts everything by 1s when aligning timers.
For simplicity I used aligned start_time_.

Open in Gerrit

Related details

Attention is currently required from:
  • Scott Haseley
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • 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: I8aca1fb6af61effb486bf548a98c31b8a2a99d8a
Gerrit-Change-Number: 7704132
Gerrit-PatchSet: 36
Gerrit-Owner: Etienne Pierre-Doray <etie...@chromium.org>
Gerrit-Reviewer: Etienne Pierre-Doray <etie...@chromium.org>
Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
Gerrit-CC: Jacob Hady <jacob...@gmail.com>
Gerrit-Attention: Scott Haseley <shas...@chromium.org>
Gerrit-Comment-Date: Wed, 01 Apr 2026 18:55:19 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

AI Code Reviewer (Gerrit)

unread,
Apr 1, 2026, 2:56:38 PM (24 hours ago) Apr 1
to Etienne Pierre-Doray, Scott Haseley, Jacob Hady, Chromium LUCI CQ, chromium...@chromium.org, AyeAye, penghuan...@chromium.org, chrome-intelligence-te...@google.com, cblume...@chromium.org, chrome-intell...@chromium.org, devtools...@chromium.org, kinuko...@chromium.org, chikamu...@chromium.org, scheduler-...@chromium.org, blink-...@chromium.org
Attention needed from Scott Haseley

AI Code Reviewer added 2 comments

File third_party/blink/renderer/platform/scheduler/test/task_environment.h
Line 121, Patchset 36 (Latest): scheduler::NonMainThreadSchedulerHelper* non_main_thread_scheduler() {
AI Code Reviewer . unresolved

nit: Blink Style Guide: Naming - Use 'CamelCase' for all function names. Consider renaming this getter to 'NonMainThreadScheduler()' to adhere to Blink's getter naming conventions.

To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
**Done** | **OK But Won't Fix**: reason | **Later**: 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)_

Line 84, Patchset 36 (Latest): MainThreadScheduler* main_thread_scheduler() const {
AI Code Reviewer . unresolved

nit: Blink Style Guide: Naming - Use 'CamelCase' for all function names. Since the bare word 'MainThreadScheduler' collides with the template type name, consider renaming this getter to 'GetMainThreadScheduler()'.

To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
**Done** | **OK But Won't Fix**: reason | **Later**: 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:
  • Scott Haseley
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement 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: I8aca1fb6af61effb486bf548a98c31b8a2a99d8a
    Gerrit-Change-Number: 7704132
    Gerrit-PatchSet: 36
    Gerrit-Owner: Etienne Pierre-Doray <etie...@chromium.org>
    Gerrit-Reviewer: Etienne Pierre-Doray <etie...@chromium.org>
    Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
    Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
    Gerrit-CC: Jacob Hady <jacob...@gmail.com>
    Gerrit-Attention: Scott Haseley <shas...@chromium.org>
    Gerrit-Comment-Date: Wed, 01 Apr 2026 18:56:35 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Scott Haseley (Gerrit)

    unread,
    Apr 1, 2026, 7:53:15 PM (19 hours ago) Apr 1
    to Etienne Pierre-Doray, AI Code Reviewer, Jacob Hady, Chromium LUCI CQ, chromium...@chromium.org, AyeAye, penghuan...@chromium.org, chrome-intelligence-te...@google.com, cblume...@chromium.org, chrome-intell...@chromium.org, devtools...@chromium.org, kinuko...@chromium.org, chikamu...@chromium.org, scheduler-...@chromium.org, blink-...@chromium.org
    Attention needed from Etienne Pierre-Doray

    Scott Haseley voted and added 16 comments

    Votes added by Scott Haseley

    Code-Review+1

    16 comments

    Patchset-level comments
    File-level comment, Patchset 37 (Latest):
    Scott Haseley . resolved

    Sweet! I thought this was coming some day. Just a few small things, but overall LGTM.

    File third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
    Line 761, Patchset 36: void SimulateMainThreadCompositor(base::TimeTicks frame_time,
    Etienne Pierre-Doray . unresolved

    (this is the trickiest bit)
    Previously: RunUntilIdle() (from caller) relies on TestMockTimeTaskRunner that would pump all immediate tasks. SimulateMainThreadCompositorTask does AdvanceClock(), but the TestMockTimeTaskRunner doesn't re-evaluate time.

    TaskEnvironment will re-evaluate time between each task and run tasks that become ready after SimulateMainThreadCompositorTask's AdvanceClock.

    Solution: all relates tests want to interleave MainThreadCompositor with other tasks and see what gets starve. Instead of relying on RunUntilIdle() subtleties, I've made this a PostDelayedTask with the next frame time, so that the scheduler gets a chance to run tasks in between.

    Scott Haseley

    (opening for visibility, but I think this LGTM)

    Yeah quite tricky! Some of the tests are explicitly testing starvation via priority, such that the compositor TQ doesn't get prioritized if rendering takes too long, in which case adding delay could be problematic -- but I think as long as those tests are immediately reposting (because next frame is expected immediately), this should be fine.

    ---

    Aside: Some of these tests might be based on old, removed policies (e.g. IIRC we used to throttle timers based on policy, but now only pause certain queues if touchstart is pending -- everything else is priority), so I'm not sure they _all_ make sense anymore -- but some do.

    Aside 2: I don't know why the related tests call WillBeginMainFrame and DidCommitFrameToCompositor in a separate task -- these are expected to happen in the same task.

    Anyway, thanks for getting these working -- I may audit and clean these up further at some point, some day...

    Line 850, Patchset 36: DoMainFrame();
    Scott Haseley . unresolved

    It's a little unfortunate that `DoMainFrame()` and `SimulateMainThreadCompositorTask()` both call `DidCommitFrameToCompositor()`. You could consider making `DoMainFrame()` take a duration (Default=0) and insert the delay between WillBeginFrame() and Commit() ?

    Line 1036, Patchset 36: std::optional<TaskEnvironmentForMainThreadSchedulerTest> task_environment_;
    Scott Haseley . unresolved

    Same question as other file: does this need to be optional<>, or can it be initialized in the c'tor initializer list?

    Line 2706, Patchset 36 (Parent): EXPECT_EQ(279u, run_order.size());
    Etienne Pierre-Doray . resolved

    This seems a consequence of RunUntilIdle() subtlety, but 0u is the desired behavior AFAICT.
    I couldn't find an explanation in history for 279.

    Scott Haseley

    Yeah that makes sense. Probably control tasks / policy updates or something.

    File third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
    Line 261, Patchset 36: std::optional<blink::test::TaskEnvironmentWithMainThreadScheduler>
    Scott Haseley . unresolved

    Why optional? It's set in both c'tors. Can it be instantiated in the c'tor initializer list?

    Line 288, Patchset 36: base::test::TaskEnvironment::ThreadingMode::DEFAULT) {}
    Etienne Pierre-Doray . unresolved

    Ideally this would be ThreadingMode::MAIN_THREAD_ONLY, but Android uses the thread pool in SelfCompactionManager::OnRunningCompact() (this is true ToT)

    Scott Haseley

    Worth adding a comment here?

    Line 565, Patchset 36: EXPECT_LT(real_time - initial_real_time, TestTimeouts::tiny_timeout());
    Scott Haseley . resolved

    TIL!

    Line 596, Patchset 36: // The global tick clock has not moved, yet we ran a large number of "delayed"
    Scott Haseley . unresolved

    Is this somewhat outdated now? This still uses MOCK_TIME, but the IIUC the expectation below is now comparing actual elapsed wall time, so I'm not sure how much this comment applies anymore.

    File third_party/blink/renderer/platform/scheduler/test/task_environment.h
    Line 121, Patchset 37 (Latest): scheduler::NonMainThreadSchedulerHelper* non_main_thread_scheduler() {
    Scott Haseley . unresolved

    Maybe GetNonMainThreadSchedulerHelper() to match the type? That could make some call sites more readable since this isn't actually returning a NonMainThreadSchedulerBase.

    Line 25, Patchset 37 (Latest):// These classes instantiate specific scheduling environments that's not
    Scott Haseley . unresolved

    ```suggestion
    // These classes instantiate specific scheduling environments that are not
    ```

    (or remove "that's")

    Line 105, Patchset 36:class TaskEnvironmentWithNonMainThreadScheduler
    Scott Haseley . unresolved

    Should this be `TaskEnvironmentWithNonMainThreadSchedulerHelper`? This isn't really a (full) NonMainThreadScheduler -- it's just part of one for tests that test/need that bit directly.

    Alternatively, and maybe this is overkill, this could create an actual non-main thread scheduler and tests could get the Helper from it?

    (Aside: FWIW I'd love to get rid of SchedulerHelper and merge it with `ThreadSchedulerBase` (crbug.com/40246056))

    Line 84, Patchset 36: MainThreadScheduler* main_thread_scheduler() const {
    AI Code Reviewer . unresolved

    nit: Blink Style Guide: Naming - Use 'CamelCase' for all function names. Since the bare word 'MainThreadScheduler' collides with the template type name, consider renaming this getter to 'GetMainThreadScheduler()'.

    To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
    **Done** | **OK But Won't Fix**: reason | **Later**: 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)_

    Scott Haseley

    Could you change this? Blink actually uses CamelCase for everything, even simple accessors https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/blink-c++.md#Use-for-all-function-names

    There are a bunch of violations (main_thread_only() etc.) of this in blink/scheduler because the code used to live in //components and was never fully cleaned up, but I'm hoping to get it to conform slowly and not introduce more.

    File third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl_unittest.cc
    Line 132, Patchset 36: WorkerThreadSchedulerForTest* thread_scheduler() { return scheduler_.get(); }
    Scott Haseley . unresolved

    style nit: (Get)ThreadScheduler()

    Line 283, Patchset 36 (Parent): EXPECT_THAT(tasks, ElementsAre(base::TimeTicks() + base::Seconds(1),
    Etienne Pierre-Doray . resolved

    The test fixture starts with TimeTicks() + 5ms, which shifts everything by 1s when aligning timers.
    For simplicity I used aligned start_time_.

    Scott Haseley

    Nice.

    File third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
    Line 162, Patchset 36: WorkerThreadSchedulerForTest* thread_scheduler() { return scheduler_.get(); }
    Scott Haseley . unresolved

    style nit: (Get)ThreadScheduler()

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Etienne Pierre-Doray
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement 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: I8aca1fb6af61effb486bf548a98c31b8a2a99d8a
      Gerrit-Change-Number: 7704132
      Gerrit-PatchSet: 37
      Gerrit-Owner: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
      Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Gerrit-CC: Jacob Hady <jacob...@gmail.com>
      Gerrit-Attention: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Comment-Date: Wed, 01 Apr 2026 23:53:05 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      Comment-In-Reply-To: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Comment-In-Reply-To: Etienne Pierre-Doray <etie...@chromium.org>
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Etienne Pierre-Doray (Gerrit)

      unread,
      10:11 AM (5 hours ago) 10:11 AM
      to Scott Haseley, AI Code Reviewer, Jacob Hady, Chromium LUCI CQ, chromium...@chromium.org, AyeAye, penghuan...@chromium.org, chrome-intelligence-te...@google.com, cblume...@chromium.org, chrome-intell...@chromium.org, devtools...@chromium.org, kinuko...@chromium.org, chikamu...@chromium.org, scheduler-...@chromium.org, blink-...@chromium.org
      Attention needed from Scott Haseley

      Etienne Pierre-Doray added 13 comments

      Patchset-level comments
      File-level comment, Patchset 41 (Latest):
      Etienne Pierre-Doray . resolved

      PTAnL?

      File third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
      Line 761, Patchset 36: void SimulateMainThreadCompositor(base::TimeTicks frame_time,
      Etienne Pierre-Doray . unresolved

      (this is the trickiest bit)
      Previously: RunUntilIdle() (from caller) relies on TestMockTimeTaskRunner that would pump all immediate tasks. SimulateMainThreadCompositorTask does AdvanceClock(), but the TestMockTimeTaskRunner doesn't re-evaluate time.

      TaskEnvironment will re-evaluate time between each task and run tasks that become ready after SimulateMainThreadCompositorTask's AdvanceClock.

      Solution: all relates tests want to interleave MainThreadCompositor with other tasks and see what gets starve. Instead of relying on RunUntilIdle() subtleties, I've made this a PostDelayedTask with the next frame time, so that the scheduler gets a chance to run tasks in between.

      Scott Haseley

      (opening for visibility, but I think this LGTM)

      Yeah quite tricky! Some of the tests are explicitly testing starvation via priority, such that the compositor TQ doesn't get prioritized if rendering takes too long, in which case adding delay could be problematic -- but I think as long as those tests are immediately reposting (because next frame is expected immediately), this should be fine.

      ---

      Aside: Some of these tests might be based on old, removed policies (e.g. IIRC we used to throttle timers based on policy, but now only pause certain queues if touchstart is pending -- everything else is priority), so I'm not sure they _all_ make sense anymore -- but some do.

      Aside 2: I don't know why the related tests call WillBeginMainFrame and DidCommitFrameToCompositor in a separate task -- these are expected to happen in the same task.

      Anyway, thanks for getting these working -- I may audit and clean these up further at some point, some day...

      Etienne Pierre-Doray

      in which case adding delay could be problematic

      To be more precise, what SimulateMainThreadCompositor() now does: it ensures that the next simulated frame is no sooner than delay after the current frame.

      • If the frame interval is 16ms, and the task takes a (simulated) 20ms, then the next frame will be immediate.
      • If the frame interval is 16ms, and the task takes 10ms, then the next frame is posted 6ms later, giving the chance for something else to run in between.

      I don't know why the related tests call WillBeginMainFrame and DidCommitFrameToCompositor in a separate task

      Yeah this is all very fake (and relies on the fact that no task runs in between).
      I could fold WillBeginFrame() into the same task, with some extra plumbing; I suspect DidHandleInputEventOnCompositorThread() should also go into the same task so I'd plumb its arguments as well. Thoughts?

      Line 850, Patchset 36: DoMainFrame();
      Scott Haseley . resolved

      It's a little unfortunate that `DoMainFrame()` and `SimulateMainThreadCompositorTask()` both call `DidCommitFrameToCompositor()`. You could consider making `DoMainFrame()` take a duration (Default=0) and insert the delay between WillBeginFrame() and Commit() ?

      Etienne Pierre-Doray

      Done

      File third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
      Line 261, Patchset 36: std::optional<blink::test::TaskEnvironmentWithMainThreadScheduler>
      Scott Haseley . unresolved

      Why optional? It's set in both c'tors. Can it be instantiated in the c'tor initializer list?

      Etienne Pierre-Doray

      This is the only way to initialize task_environment_ after feature list for now, but I sent https://crrev.com/c/7723407, if that works I'll remove optional here.

      Line 288, Patchset 36: base::test::TaskEnvironment::ThreadingMode::DEFAULT) {}
      Etienne Pierre-Doray . resolved

      Ideally this would be ThreadingMode::MAIN_THREAD_ONLY, but Android uses the thread pool in SelfCompactionManager::OnRunningCompact() (this is true ToT)

      Scott Haseley

      Worth adding a comment here?

      Etienne Pierre-Doray

      Done

      Line 596, Patchset 36: // The global tick clock has not moved, yet we ran a large number of "delayed"
      Scott Haseley . resolved

      Is this somewhat outdated now? This still uses MOCK_TIME, but the IIUC the expectation below is now comparing actual elapsed wall time, so I'm not sure how much this comment applies anymore.

      Etienne Pierre-Doray

      Right, updated comment.

      File third_party/blink/renderer/platform/scheduler/test/task_environment.h
      Line 121, Patchset 37: scheduler::NonMainThreadSchedulerHelper* non_main_thread_scheduler() {
      Scott Haseley . resolved

      Maybe GetNonMainThreadSchedulerHelper() to match the type? That could make some call sites more readable since this isn't actually returning a NonMainThreadSchedulerBase.

      Etienne Pierre-Doray

      Done

      Line 25, Patchset 37:// These classes instantiate specific scheduling environments that's not
      Scott Haseley . resolved

      ```suggestion
      // These classes instantiate specific scheduling environments that are not
      ```

      (or remove "that's")

      Etienne Pierre-Doray

      Done

      Line 121, Patchset 36: scheduler::NonMainThreadSchedulerHelper* non_main_thread_scheduler() {
      AI Code Reviewer . resolved

      nit: Blink Style Guide: Naming - Use 'CamelCase' for all function names. Consider renaming this getter to 'NonMainThreadScheduler()' to adhere to Blink's getter naming conventions.

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

      **Done** | **OK But Won't Fix**: reason | **Later**: 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)_

      Etienne Pierre-Doray

      Done

      Line 105, Patchset 36:class TaskEnvironmentWithNonMainThreadScheduler
      Scott Haseley . resolved

      Should this be `TaskEnvironmentWithNonMainThreadSchedulerHelper`? This isn't really a (full) NonMainThreadScheduler -- it's just part of one for tests that test/need that bit directly.

      Alternatively, and maybe this is overkill, this could create an actual non-main thread scheduler and tests could get the Helper from it?

      (Aside: FWIW I'd love to get rid of SchedulerHelper and merge it with `ThreadSchedulerBase` (crbug.com/40246056))

      Etienne Pierre-Doray

      Done for TaskEnvironmentWithNonMainThreadSchedulerHelper.
      I'd rather not switch to NonMainThreadScheduler though, since that would unnecessarily introduce more setup in tests.

      Line 84, Patchset 36: MainThreadScheduler* main_thread_scheduler() const {
      AI Code Reviewer . resolved

      nit: Blink Style Guide: Naming - Use 'CamelCase' for all function names. Since the bare word 'MainThreadScheduler' collides with the template type name, consider renaming this getter to 'GetMainThreadScheduler()'.

      To keep this interaction as brief and non-intrusive as possible, please consider responding with one of following options:
      **Done** | **OK But Won't Fix**: reason | **Later**: 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)_

      Scott Haseley

      Could you change this? Blink actually uses CamelCase for everything, even simple accessors https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/blink-c++.md#Use-for-all-function-names

      There are a bunch of violations (main_thread_only() etc.) of this in blink/scheduler because the code used to live in //components and was never fully cleaned up, but I'm hoping to get it to conform slowly and not introduce more.

      Etienne Pierre-Doray

      Done

      File third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_impl_unittest.cc
      Line 132, Patchset 36: WorkerThreadSchedulerForTest* thread_scheduler() { return scheduler_.get(); }
      Scott Haseley . resolved

      style nit: (Get)ThreadScheduler()

      Etienne Pierre-Doray

      Done

      File third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
      Line 162, Patchset 36: WorkerThreadSchedulerForTest* thread_scheduler() { return scheduler_.get(); }
      Scott Haseley . resolved

      style nit: (Get)ThreadScheduler()

      Etienne Pierre-Doray

      Done

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Scott Haseley
      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: I8aca1fb6af61effb486bf548a98c31b8a2a99d8a
      Gerrit-Change-Number: 7704132
      Gerrit-PatchSet: 41
      Gerrit-Owner: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
      Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Gerrit-CC: Jacob Hady <jacob...@gmail.com>
      Gerrit-Attention: Scott Haseley <shas...@chromium.org>
      Gerrit-Comment-Date: Thu, 02 Apr 2026 14:11:17 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Scott Haseley <shas...@chromium.org>
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Scott Haseley (Gerrit)

      unread,
      12:14 PM (3 hours ago) 12:14 PM
      to Etienne Pierre-Doray, AI Code Reviewer, Jacob Hady, Chromium LUCI CQ, chromium...@chromium.org, AyeAye, penghuan...@chromium.org, chrome-intelligence-te...@google.com, cblume...@chromium.org, chrome-intell...@chromium.org, devtools...@chromium.org, kinuko...@chromium.org, chikamu...@chromium.org, scheduler-...@chromium.org, blink-...@chromium.org
      Attention needed from Etienne Pierre-Doray

      Scott Haseley voted and added 3 comments

      Votes added by Scott Haseley

      Code-Review+1

      3 comments

      Patchset-level comments
      Scott Haseley . resolved

      LGTM

      File third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
      Line 761, Patchset 36: void SimulateMainThreadCompositor(base::TimeTicks frame_time,
      Etienne Pierre-Doray . unresolved

      (this is the trickiest bit)
      Previously: RunUntilIdle() (from caller) relies on TestMockTimeTaskRunner that would pump all immediate tasks. SimulateMainThreadCompositorTask does AdvanceClock(), but the TestMockTimeTaskRunner doesn't re-evaluate time.

      TaskEnvironment will re-evaluate time between each task and run tasks that become ready after SimulateMainThreadCompositorTask's AdvanceClock.

      Solution: all relates tests want to interleave MainThreadCompositor with other tasks and see what gets starve. Instead of relying on RunUntilIdle() subtleties, I've made this a PostDelayedTask with the next frame time, so that the scheduler gets a chance to run tasks in between.

      Scott Haseley

      (opening for visibility, but I think this LGTM)

      Yeah quite tricky! Some of the tests are explicitly testing starvation via priority, such that the compositor TQ doesn't get prioritized if rendering takes too long, in which case adding delay could be problematic -- but I think as long as those tests are immediately reposting (because next frame is expected immediately), this should be fine.

      ---

      Aside: Some of these tests might be based on old, removed policies (e.g. IIRC we used to throttle timers based on policy, but now only pause certain queues if touchstart is pending -- everything else is priority), so I'm not sure they _all_ make sense anymore -- but some do.

      Aside 2: I don't know why the related tests call WillBeginMainFrame and DidCommitFrameToCompositor in a separate task -- these are expected to happen in the same task.

      Anyway, thanks for getting these working -- I may audit and clean these up further at some point, some day...

      Etienne Pierre-Doray

      in which case adding delay could be problematic

      To be more precise, what SimulateMainThreadCompositor() now does: it ensures that the next simulated frame is no sooner than delay after the current frame.

      • If the frame interval is 16ms, and the task takes a (simulated) 20ms, then the next frame will be immediate.
      • If the frame interval is 16ms, and the task takes 10ms, then the next frame is posted 6ms later, giving the chance for something else to run in between.

      I don't know why the related tests call WillBeginMainFrame and DidCommitFrameToCompositor in a separate task

      Yeah this is all very fake (and relies on the fact that no task runs in between).
      I could fold WillBeginFrame() into the same task, with some extra plumbing; I suspect DidHandleInputEventOnCompositorThread() should also go into the same task so I'd plumb its arguments as well. Thoughts?

      Scott Haseley

      If the frame interval is 16ms, and the task takes 10ms, then the next frame is posted 6ms later, giving the chance for something else to run in between.

      This is the one that I was a bit concerned about because if the test is based purely on priority (i.e. testing that the compositor TQ stays at normal priority, which matches the throttleable queue), then the tests could pass even if the priority does get increased because the high priority task is delayed.

      But looking at the couple tests that use 10ms, this looks fine.

      I suspect DidHandleInputEventOnCompositorThread() should also go into the same task so I'd plumb its arguments as well

      Typically DidHandleInputEventOnCompositorThread would be a different task because in reality this happens on the CC thread.

      ---

      I think just getting these to work any way for now is fine, and this approach LGTM.

      If I have some spare cycles soon I might audit some of these tests. Some other things I don't like is how, e.g. SYNCHRONIZED_GESTURE_ThrottleableTaskThrottling_task_not_expensive, mixes the main frame bits with pausing the scheduler. I think this is a remnant of an older approach where we did more throttling based on use case, and then stuck the Pauser in there -- which is totally different (pause during nested run loops, etc.).

      File third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
      Line 261, Patchset 36: std::optional<blink::test::TaskEnvironmentWithMainThreadScheduler>
      Scott Haseley . unresolved

      Why optional? It's set in both c'tors. Can it be instantiated in the c'tor initializer list?

      Etienne Pierre-Doray

      This is the only way to initialize task_environment_ after feature list for now, but I sent https://crrev.com/c/7723407, if that works I'll remove optional here.

      Scott Haseley

      Ah okay I wondered if that was why. SGTM.

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Etienne Pierre-Doray
      Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement 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: I8aca1fb6af61effb486bf548a98c31b8a2a99d8a
      Gerrit-Change-Number: 7704132
      Gerrit-PatchSet: 41
      Gerrit-Owner: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
      Gerrit-CC: AI Code Reviewer <peep-gen...@system.gserviceaccount.com>
      Gerrit-CC: Jacob Hady <jacob...@gmail.com>
      Gerrit-Attention: Etienne Pierre-Doray <etie...@chromium.org>
      Gerrit-Comment-Date: Thu, 02 Apr 2026 16:14:30 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      Comment-In-Reply-To: Scott Haseley <shas...@chromium.org>
      Comment-In-Reply-To: Etienne Pierre-Doray <etie...@chromium.org>
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy
      Reply all
      Reply to author
      Forward
      0 new messages