Skip to content

Investigate perf gains of LegendList #98994

Open

Description

@roryabraham

This issue is a placeholder to investigate the potential performance gains of LegendList in E/App as opposed to FlashList. Independent metrics suggest it should improve TTI, scroll FPS, and use less memory and CPU.

Issue OwnerCurrent Issue Owner: @dmkt9

Activity

  1. roryabraham commented on Aug 19, 2026

    @roryabraham
    ContributorAuthor

    @chrispader has a draft PR here #98270 and is working on collecting metrics

  2. melvin-bot commented on Aug 24, 2026

    @melvin-bot

    @chrispader Eep! 4 days overdue now. Issues have feelings too...

  3. chrispader commented on Aug 26, 2026

    @chrispader
    Contributor

    We are currently discussing how to handle initial chat loading with LegendList in this Slack thread. The current initial report loading is broken and not working holistically, so this needs a better approach anyway.

    In my proof of concept, i've created different examples of the LegendList implementation using...

    • current behavior (rendering what is stored locally, before rendering full dataset)
    • showing a loading skeleton until fully loaded
    • showing a loading indicator until fully loaded.

    The proof of concept already re-writes all logic in the app that are targeted towards an inverted list, in order to be able to record proper benchmarks with LegendList. There were also issues with the initial scroll that have been fixed now.

    I'm currently recording benchmarks between FlashList and LegendList, measuring FPS drops, CPU/RAM usage. Results should be ready today!

  4. chrispader commented on Aug 31, 2026

    @chrispader
    Contributor

    A quick update on where we're at with the LegendList migration, benchmarks and testing:

    We are currently discussing how to handle initial chat loading with LegendList in this Slack thread.

    We still haven't settled on the final UX design for this, but let's discuss further once the LegendList proposal is out and has been accepted!

    I've collected benchmarks from automated flows navigating a long chat list. On Android the automations were run and the metrics were recorded using Flashlight and on iOS using XCTest.

    Both benchmarks show improvements in CPU/RAM usage and FPS count stays higher than with FlashList.

    I'm currently fixing some remaining issues with scrolling behavior and i'm tweaking the knobs around virtualization and recycling, to achieve the best performance across all chats.

    Here are some screenshots from the Android Flashlight results:

    Image Image

    And from another heavier list flow:

    Image
  5. chrispader commented on Aug 31, 2026

    @chrispader
    Contributor

    Once i've finished the benchmarks and found fixes for the remaining scroll/initial rendering issues, i'm going to post the proposal on Slack 🙌🏼

  6. chrispader commented on Sep 1, 2026

    @chrispader
    Contributor

    Benchmarking flow

    I've finished my benchmarks for this specific chat flow:

    1. Open a heavy chat
    2. Scroll slowly to the start of the chat
    3. Scroll slowly back to the end of the chat
    4. Scroll fast to the start of the chat
    5. Scroll fast to the end of the chat

    In between each of the scrolls, there is a small wait period. Here's an example video of how this flow was tested on the slow Samsung Galaxy S10e:

    FlashList LegendList
    Screen_Recording_20260901_222742_Expensify.flashlist.mp4
    Screen_Recording_20260901_222833_Expensify.legendlist.mp4

    Results

    I've conducted the experiment on a slow (Samsung Galaxy S10e) and fast (Samsung Galaxy S10 5G) Android phone, and on an iPhone 14 Pro. These are the results:

    Android

    LegendList uses less average CPU and RAM on both Android phones. The FPS and memory improvements are much more noticeable on the slower Galaxy S10e.

    Samsung Galaxy S10e (slow)

    Metric FlashList LegendList LegendList change
    Average FPS 45.7 51.9 13.6% higher
    Average CPU 214.9% 180.3% 16.1% lower
    Average RAM 766.1 MB 596.4 MB 22.2% lower
    High-CPU time 38.0 s 33.5 s 11.8% lower

    Flashlight report

    Metric overview FPS Count Total CPU usage RN Thread CPU Usage UI Thread CPU Usage RAM Usage
    Image Image Image Image Image Image

    Samsung Galaxy S10 5g (fast)

    Metric FlashList LegendList LegendList change
    Average FPS 52.8 52.7 Essentially unchanged
    Average CPU 177.2% 156.9% 11.5% lower
    Average RAM 842.2 MB 828.0 MB 1.7% lower
    High-CPU time 33.5 s 26.0 s 22.4% lower

    On the S10e, LegendList saves approximately 170 MB of RAM and delivers 6.2 more FPS on average. Its FPS graph also shows fewer deep drops during scrolling.
    On the S10 5G, the benefit is mainly lower CPU usage. Average FPS is effectively unchanged, and the RAM saving is smaller at approximately 14 MB. The graph includes an early LegendList memory spike, so the improvement is in average RAM, not consistently lower memory at every moment.
    These results show better resource usage, especially on the slower phone. They do not show faster overall test completion. CPU percentages can exceed 100% because they include work across multiple cores.

    Flashlight report

    Metric overview FPS Count Total CPU usage RN Thread CPU Usage UI Thread CPU Usage RAM Usage
    Image Image Image Image Image Image

    iOS

    A similar XCTest automation exercised opening and scrolling a large chat on an iPhone 14 Pro running iOS 26.6.1. Apple Instruments collected CPU, memory, hangs, and hitches while the test ran.
    This setup did not capture FPS. Instead, the Hitches instrument measured delayed frames, and the Hangs instrument recorded brief unresponsiveness lasting more than 100 ms.
    I extracted the following values from the supplied .trace file. It contains one recording per implementation. CPU and RAM averages cover each complete recorded window.

    Metric FlashList LegendList LegendList change
    Average CPU 77.9% 63.8% 18.1% lower
    Average RAM footprint 499.0 MiB 396.7 MiB 20.5% lower
    Peak RAM footprint 587.6 MiB 423.8 MiB 27.9% lower
    Hitch count 35 26 25.7% fewer
    Total hitch duration 958.7 ms 1,017.0 ms 6.1% higher
    Average hitch duration 27.4 ms 39.1 ms 42.8% longer
    Longest hitch 175.0 ms 175.0 ms Unchanged
    Brief hang count 2 2 Unchanged
    Total hang duration 354.8 ms 352.6 ms Essentially unchanged
    Recording length 35.74 s 41.26 s 15.4% longer

    LegendList used approximately 102 MiB less RAM on average, with a 164 MiB lower peak. Average CPU usage was also lower.
    The smoothness result is mixed. LegendList produced fewer hitches, but those hitches lasted longer on average, and their combined duration increased slightly. Both implementations recorded two brief hangs. We should describe this as lower CPU and memory usage with fewer, longer hitches, rather than an improvement in every responsiveness metric.
    The recordings have different lengths and were stopped manually, so recording length is not a reliable measure of test completion speed. These results should also remain separate from the earlier five-run XCTest measurements.


    Conclusion

    These benchmarks support migrating to LegendList: it consistently reduces CPU and memory usage, while improving performance on slower devices and maintaining comparable FPS on faster hardware. The gains are especially valuable for large, complex lists such as ReportActionsList.

  7. roryabraham commented on Sep 1, 2026

    @roryabraham
    ContributorAuthor

    Awesome, great work @chrispader! Let's roll it out 🎉

    Were you able to do it without LegendList patches?

  8. chrispader commented on Sep 3, 2026

    @chrispader
    Contributor

    Were you able to do it without LegendList patches?

    So far i didn't need any patches. I'm going to sort out any remaining issues and edge cases, but i don't think we're going to need to patch the library at all.

  9. 64 remaining items

  10. melvin-bot commented on Oct 29, 2026

    @melvin-bot

    @dmkt9

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.25-2 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

  11. melvin-bot commented on Oct 31, 2026

    @melvin-bot

    @dmkt9

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.26-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

DailyKSv2Skip PaymentSkips all the payment process steps for an issue. Use it for fixed-price projects.

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions