LCP: Use largest painted image for web-exposed entry [chromium/src : main]

0 views
Skip to first unread message

Scott Haseley (Gerrit)

unread,
Dec 17, 2025, 7:19:57 PM12/17/25
to Michal Mocny, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
Attention needed from Michal Mocny

Scott Haseley added 1 comment

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

PTAL (not expecting to land this before the holidays, just want to send it out!). Not sure if we should go "experimental" or just enable this.

Open in Gerrit

Related details

Attention is currently required from:
  • Michal Mocny
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: I5275906769b07aca6c671c846756070333f2b09c
Gerrit-Change-Number: 7269039
Gerrit-PatchSet: 1
Gerrit-Owner: Scott Haseley <shas...@chromium.org>
Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
Gerrit-Attention: Michal Mocny <mmo...@chromium.org>
Gerrit-Comment-Date: Thu, 18 Dec 2025 00:19:48 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Michal Mocny (Gerrit)

unread,
Dec 18, 2025, 2:48:51 PM12/18/25
to Scott Haseley, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
Attention needed from Scott Haseley

Michal Mocny voted and added 4 comments

Votes added by Michal Mocny

Code-Review+1

4 comments

Patchset-level comments
Michal Mocny . resolved

Huzzah!

File third_party/blink/web_tests/external/wpt/largest-contentful-paint/performance-entry-sequence.html
Line 3, Patchset 1 (Latest):<title>Largest Contentful Paint: performance entries are emitted in the expected sequence</title>
Michal Mocny . unresolved

Just FYI that Firefox will not pass this, and landing this into the LCP repo will make it automatically part of the interop work... you can untag it, but I dont know the full process.

(It could also start tentative until we merge in spec changes? Though I can prob get that in alongside this...)

Line 31, Patchset 1 (Latest): container.appendChild(createDivWithText('text1', 'AB'));
Michal Mocny . unresolved

Nit: could you consider adding a third div, which is als smaller, that comes last (after the largest)?

That way, regardless of arbitrary paint order for any implementation (well not guaranteed but higher odds...) you can test that only one (largest) candidate is emitted per paint.

Otherwise you could just be accidentally measuring largest before smaller...

Line 44, Patchset 1 (Latest): // a LargestContentfulPaint entry for image1.
Michal Mocny . unresolved

Is this 100% guaranteed? Is the random appended to ensure no cache?

Open in Gerrit

Related details

Attention is currently required from:
  • Scott Haseley
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: I5275906769b07aca6c671c846756070333f2b09c
    Gerrit-Change-Number: 7269039
    Gerrit-PatchSet: 1
    Gerrit-Owner: Scott Haseley <shas...@chromium.org>
    Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
    Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
    Gerrit-Attention: Scott Haseley <shas...@chromium.org>
    Gerrit-Comment-Date: Thu, 18 Dec 2025 19:48:42 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Scott Haseley (Gerrit)

    unread,
    Jan 7, 2026, 9:20:40 PM (7 days ago) Jan 7
    to Michal Mocny, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
    Attention needed from Michal Mocny

    Scott Haseley added 3 comments

    File third_party/blink/web_tests/external/wpt/largest-contentful-paint/performance-entry-sequence.html
    Line 3, Patchset 1:<title>Largest Contentful Paint: performance entries are emitted in the expected sequence</title>
    Michal Mocny . unresolved

    Just FYI that Firefox will not pass this, and landing this into the LCP repo will make it automatically part of the interop work... you can untag it, but I dont know the full process.

    (It could also start tentative until we merge in spec changes? Though I can prob get that in alongside this...)

    Scott Haseley

    Yeah maybe making it .tentative for now makes sense. I thought there was a predefined list of tests for the interop effort that will trip up edits, but I'm not fully sure how that works.

    Line 31, Patchset 1: container.appendChild(createDivWithText('text1', 'AB'));
    Michal Mocny . unresolved

    Nit: could you consider adding a third div, which is als smaller, that comes last (after the largest)?

    That way, regardless of arbitrary paint order for any implementation (well not guaranteed but higher odds...) you can test that only one (largest) candidate is emitted per paint.

    Otherwise you could just be accidentally measuring largest before smaller...

    Scott Haseley

    Yeah good idea, I'll update this shortly... And yeah this is tricky since paint order _could_ be anything.

    Line 44, Patchset 1: // a LargestContentfulPaint entry for image1.
    Michal Mocny . unresolved

    Is this 100% guaranteed? Is the random appended to ensure no cache?

    Scott Haseley

    It should be. The key here is we don't want the image to load synchronously, otherwise it'll be in this frame. The only time that's _supposed_ to happen is when the image is in the list of "list of available images" [1] (used for de-duping during loading, and I think for reloads), but that's keyed off of absolute URL, so this should prevent reuse there.

    Chrome loads data URIs synchronously, which IIUC is a (maybe willful) spec violation, but this doesn't apply here.

    Preloads and HTTP cache hits are still supposed to have an async hop since it calls out to Fetch, but I haven't tested this in all browsers (I think I have a test showing this is the case in Chrome) -- but regardless, the random query param should prevent a cached/preloaded resource from being used, so I think this is sound.

    [1]https://html.spec.whatwg.org/#list-of-available-images

    ---

    BUT, I'm finding this is flaky locally for another reason: sometimes the feedback for frame N arrives _after_ N+1, so we give everything the timestamp for N+1 :(. So I'm seeing all of the text nodes getting the same timestamp in some cases.

    It looks mostly confined to non-threaded compositing (I've seen weirdness with this mode before wrt presentation callbacks), but it timed out at least once with threaded compositing (although I can't get it to fail now..). Looks like it could be related to the jitter we add or something, as these are delayed tasks.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Michal Mocny
    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: I5275906769b07aca6c671c846756070333f2b09c
    Gerrit-Change-Number: 7269039
    Gerrit-PatchSet: 2
    Gerrit-Owner: Scott Haseley <shas...@chromium.org>
    Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
    Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
    Gerrit-Attention: Michal Mocny <mmo...@chromium.org>
    Gerrit-Comment-Date: Thu, 08 Jan 2026 02:20:19 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Michal Mocny <mmo...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Scott Haseley (Gerrit)

    unread,
    Jan 9, 2026, 7:27:51 PM (5 days ago) Jan 9
    to Michal Mocny, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
    Attention needed from Michal Mocny

    Scott Haseley added 1 comment

    File third_party/blink/web_tests/external/wpt/largest-contentful-paint/performance-entry-sequence.html
    Line 44, Patchset 1: // a LargestContentfulPaint entry for image1.
    Michal Mocny . unresolved

    Is this 100% guaranteed? Is the random appended to ensure no cache?

    Scott Haseley

    It should be. The key here is we don't want the image to load synchronously, otherwise it'll be in this frame. The only time that's _supposed_ to happen is when the image is in the list of "list of available images" [1] (used for de-duping during loading, and I think for reloads), but that's keyed off of absolute URL, so this should prevent reuse there.

    Chrome loads data URIs synchronously, which IIUC is a (maybe willful) spec violation, but this doesn't apply here.

    Preloads and HTTP cache hits are still supposed to have an async hop since it calls out to Fetch, but I haven't tested this in all browsers (I think I have a test showing this is the case in Chrome) -- but regardless, the random query param should prevent a cached/preloaded resource from being used, so I think this is sound.

    [1]https://html.spec.whatwg.org/#list-of-available-images

    ---

    BUT, I'm finding this is flaky locally for another reason: sometimes the feedback for frame N arrives _after_ N+1, so we give everything the timestamp for N+1 :(. So I'm seeing all of the text nodes getting the same timestamp in some cases.

    It looks mostly confined to non-threaded compositing (I've seen weirdness with this mode before wrt presentation callbacks), but it timed out at least once with threaded compositing (although I can't get it to fail now..). Looks like it could be related to the jitter we add or something, as these are delayed tasks.

    Scott Haseley
    Re: out-of-order presentation time:
    - When coarsening, we round up to nearest multiple of 4ms and use that as the presentation time. We then post a delayed task with delay = origin + presentation_time - now.
    - But we sometimes get the same presentation timestamp for consecutive frames. This happens a lot more without threaded compositing, but can also happen with threaded compositing, e.g. with dropped frames (which is what I'm seeing)
    - The flakiness results from computing the delay: the target_time (origin + pres_time) is the same, but there's some margin for error since we compute now() and then add that delay back to now() in the scheduling layer

    The new-ish `PostDelayedTaskAt()` should fix this since that would use the target_time directly `SequenceManager` rather than doing more math, and the tie would be broken based on sequence number (posting order). But, it's guarded by a PassKey, so I'll need to get this blessed.

    One alternative is to use a Timer and maintain a list of callbacks, ordered by target_time, and have a single outstanding task (earliest presentation time). But that's basically duplicating the `SequenceManager` logic.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Michal Mocny
    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: I5275906769b07aca6c671c846756070333f2b09c
    Gerrit-Change-Number: 7269039
    Gerrit-PatchSet: 2
    Gerrit-Owner: Scott Haseley <shas...@chromium.org>
    Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
    Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
    Gerrit-Attention: Michal Mocny <mmo...@chromium.org>
    Gerrit-Comment-Date: Sat, 10 Jan 2026 00:27:37 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Scott Haseley <shas...@chromium.org>
    Comment-In-Reply-To: Michal Mocny <mmo...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Scott Haseley (Gerrit)

    unread,
    Jan 12, 2026, 4:32:00 PM (2 days ago) Jan 12
    to Michal Mocny, Chromium LUCI CQ, chromium...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
    Attention needed from Michal Mocny

    Scott Haseley added 3 comments

    File third_party/blink/web_tests/external/wpt/largest-contentful-paint/performance-entry-sequence.html
    Line 3, Patchset 1:<title>Largest Contentful Paint: performance entries are emitted in the expected sequence</title>
    Michal Mocny . resolved

    Just FYI that Firefox will not pass this, and landing this into the LCP repo will make it automatically part of the interop work... you can untag it, but I dont know the full process.

    (It could also start tentative until we merge in spec changes? Though I can prob get that in alongside this...)

    Scott Haseley

    Yeah maybe making it .tentative for now makes sense. I thought there was a predefined list of tests for the interop effort that will trip up edits, but I'm not fully sure how that works.

    Scott Haseley

    Done

    Line 31, Patchset 1: container.appendChild(createDivWithText('text1', 'AB'));
    Michal Mocny . resolved

    Nit: could you consider adding a third div, which is als smaller, that comes last (after the largest)?

    That way, regardless of arbitrary paint order for any implementation (well not guaranteed but higher odds...) you can test that only one (largest) candidate is emitted per paint.

    Otherwise you could just be accidentally measuring largest before smaller...

    Scott Haseley

    Yeah good idea, I'll update this shortly... And yeah this is tricky since paint order _could_ be anything.

    Scott Haseley

    Done

    Line 44, Patchset 1: // a LargestContentfulPaint entry for image1.
    Michal Mocny . resolved

    Is this 100% guaranteed? Is the random appended to ensure no cache?

    Scott Haseley

    It should be. The key here is we don't want the image to load synchronously, otherwise it'll be in this frame. The only time that's _supposed_ to happen is when the image is in the list of "list of available images" [1] (used for de-duping during loading, and I think for reloads), but that's keyed off of absolute URL, so this should prevent reuse there.

    Chrome loads data URIs synchronously, which IIUC is a (maybe willful) spec violation, but this doesn't apply here.

    Preloads and HTTP cache hits are still supposed to have an async hop since it calls out to Fetch, but I haven't tested this in all browsers (I think I have a test showing this is the case in Chrome) -- but regardless, the random query param should prevent a cached/preloaded resource from being used, so I think this is sound.

    [1]https://html.spec.whatwg.org/#list-of-available-images

    ---

    BUT, I'm finding this is flaky locally for another reason: sometimes the feedback for frame N arrives _after_ N+1, so we give everything the timestamp for N+1 :(. So I'm seeing all of the text nodes getting the same timestamp in some cases.

    It looks mostly confined to non-threaded compositing (I've seen weirdness with this mode before wrt presentation callbacks), but it timed out at least once with threaded compositing (although I can't get it to fail now..). Looks like it could be related to the jitter we add or something, as these are delayed tasks.

    Scott Haseley
    Re: out-of-order presentation time:
    - When coarsening, we round up to nearest multiple of 4ms and use that as the presentation time. We then post a delayed task with delay = origin + presentation_time - now.
    - But we sometimes get the same presentation timestamp for consecutive frames. This happens a lot more without threaded compositing, but can also happen with threaded compositing, e.g. with dropped frames (which is what I'm seeing)
    - The flakiness results from computing the delay: the target_time (origin + pres_time) is the same, but there's some margin for error since we compute now() and then add that delay back to now() in the scheduling layer

    The new-ish `PostDelayedTaskAt()` should fix this since that would use the target_time directly `SequenceManager` rather than doing more math, and the tie would be broken based on sequence number (posting order). But, it's guarded by a PassKey, so I'll need to get this blessed.

    One alternative is to use a Timer and maintain a list of callbacks, ordered by target_time, and have a single outstanding task (earliest presentation time). But that's basically duplicating the `SequenceManager` logic.

    Scott Haseley

    Update: I reparented this on a change to use `PostDelayedTaskAt()` which fixes the ordering issue.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Michal Mocny
    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: I5275906769b07aca6c671c846756070333f2b09c
      Gerrit-Change-Number: 7269039
      Gerrit-PatchSet: 4
      Gerrit-Owner: Scott Haseley <shas...@chromium.org>
      Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
      Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
      Gerrit-Attention: Michal Mocny <mmo...@chromium.org>
      Gerrit-Comment-Date: Mon, 12 Jan 2026 21:31:44 +0000
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Michal Mocny (Gerrit)

      unread,
      7:44 PM (4 hours ago) 7:44 PM
      to Scott Haseley, AyeAye, Chromium LUCI CQ, chromium...@chromium.org, scheduler...@chromium.org, blink-rev...@chromium.org, blink-revie...@chromium.org, blink-...@chromium.org, jmedle...@chromium.org, kinuko...@chromium.org, lighthouse-eng-extern...@google.com, speed-metrics...@chromium.org
      Attention needed from Scott Haseley

      Michal Mocny voted and added 2 comments

      Votes added by Michal Mocny

      Code-Review+1

      2 comments

      Commit Message
      Line 23, Patchset 6 (Latest):painted image instead of largest pending image. This does not affect
      UKM/metrics. This matches the behavior agreed upon by the WebPerf
      Michal Mocny . resolved

      Is this meant to be "yet" or "by design"? IIUC because UKM only reports the final largest, and because we don't report if we still have a pending, it might not matter for UKM?

      (Though I still would like to see more eager reporting.)

      File third_party/blink/web_tests/external/wpt/largest-contentful-paint/performance-entry-sequence.tentative.html
      Line 29, Patchset 6 (Latest): // Frame 1: paint three divs, with one being the largerst . This should produce
      Michal Mocny . unresolved

      nit: largest

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Scott Haseley
      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: I5275906769b07aca6c671c846756070333f2b09c
        Gerrit-Change-Number: 7269039
        Gerrit-PatchSet: 6
        Gerrit-Owner: Scott Haseley <shas...@chromium.org>
        Gerrit-Reviewer: Michal Mocny <mmo...@chromium.org>
        Gerrit-Reviewer: Scott Haseley <shas...@chromium.org>
        Gerrit-Attention: Scott Haseley <shas...@chromium.org>
        Gerrit-Comment-Date: Thu, 15 Jan 2026 00:44:00 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy
        Reply all
        Reply to author
        Forward
        0 new messages