Measured while answering OpenDocument.droid#637 ("say when a spreadsheet was cut, and offer to
reload it with the cut relaxed"). The answer there turned out to be that the app cannot offer to
relax anything, because the browser cannot hold what the current limits already produce. The
cost is concentrated in one place, and it looks addressable here.
What a rendered cell costs a browser
Measured with the android app, one document per process, sampling every process it owns —
including com.google.android.webview:sandboxed_process0, which is where the page actually
lives. Two emulators: 2 GB / API 31 and 8 GB / API 36.
odr-public/ods/file_example_ODS_*.ods, the same 8-column sheet at three lengths, translated with
editable=false and the app's limits (spreadsheet_limit 100000x500, spreadsheet_cell_limit
500000, spreadsheet_limit_by_content):
| sheet |
html |
renderer process, peak RSS |
| 100 rows |
0.2 MB |
195 MB (this is the floor) |
| 1000 rows |
1.4 MB |
342 MB |
| 5000 rows |
6.9 MB |
949 MB (817 MB PSS by dumpsys meminfo, settling to 339 MB) |
So roughly 10-20 KB of browser memory per rendered cell, against ~226 bytes of html per cell —
a multiplier of 40-90x on the bytes.
At the top of that curve, odr-public/ods/Supervised_Business_Register_300425.ods (4.5 MB,
one sheet of 66,523 x 21) renders 23,809 x 21 = 500,000 cells as 113 MB of html, and the renderer
process climbs to 4.7 GB laying it out — with the system UI going unresponsive on the way.
The same page cannot be displayed at all on the 2 GB device: the load dies mid-stream after ~80
seconds. Rendering the whole sheet (1.4 M cells, 316 MB of html) translates fine on the big device
— peak 1.33 GB, so Html::translate is in good shape after #776/#780 — but there is no browser
that can then show it.
Where the bytes go
The html of one non-empty cell, read-only:
<td style="vertical-align:top;">
<x-p style="display:block;text-align:left;margin-left:0cm;font-family:Calibri;font-size:12pt;"
><x-s style="font-family:Calibri;font-size:12pt;color:#000000;">01/04/2022</x-s><wbr></x-p>
</td>
Over test/data/reference-output/.../Supervised_Business_Register_300425.ods/sheet0.html:
- 259,957
style="…" attributes, 14.78 MB of the 26.66 MB file — 55%, and about 72% of what
is left once that file's contenteditable/data-odr-path attributes (6.18 MB, absent in a
read-only render) are discounted.
- 26 distinct style strings in the whole sheet. Three of them account for 251,937 of the
259,957 attributes: vertical-align:top;,
display:block;text-align:left;margin-left:0cm;font-family:Calibri;font-size:12pt; and
font-family:Calibri;font-size:12pt;color:#000000;.
A sheet is the case where a document's styles are most repetitive and most repeated, and inline
style is the one shape a browser cannot share: every attribute is parsed into its own declaration
block, and every element gets its own ComputedStyle.
What would help
- Emit repeated styles as classes rather than inline attributes, at least for sheets. 26
classes in a <style> block would remove over half the html bytes and, more importantly, let
the engine share style objects across cells instead of building a quarter-million of them.
- Do not spend three elements and a
<wbr> on a cell holding one plain string. td > x-p > x-s > text is four nodes per cell before any content; a plain cell could be td > text with
the paragraph's style on the td.
Either one moves the ceiling for every embedder that shows a sheet in a browser engine, which is
what the html limits are really budgeting for. #781 is the same shape one layer down (three
registry elements per non-empty cell before any html limit applies).
Numbers above are from emulators, so treat the absolute megabytes as indicative; the ratios
repeated across runs and devices, and the failure modes (lmkd kill, a load dying mid-stream, an
unresponsive system UI) were the real ones.
Measured while answering OpenDocument.droid#637 ("say when a spreadsheet was cut, and offer to
reload it with the cut relaxed"). The answer there turned out to be that the app cannot offer to
relax anything, because the browser cannot hold what the current limits already produce. The
cost is concentrated in one place, and it looks addressable here.
What a rendered cell costs a browser
Measured with the android app, one document per process, sampling every process it owns —
including
com.google.android.webview:sandboxed_process0, which is where the page actuallylives. Two emulators: 2 GB / API 31 and 8 GB / API 36.
odr-public/ods/file_example_ODS_*.ods, the same 8-column sheet at three lengths, translated witheditable=falseand the app's limits (spreadsheet_limit100000x500,spreadsheet_cell_limit500000,
spreadsheet_limit_by_content):dumpsys meminfo, settling to 339 MB)So roughly 10-20 KB of browser memory per rendered cell, against ~226 bytes of html per cell —
a multiplier of 40-90x on the bytes.
At the top of that curve,
odr-public/ods/Supervised_Business_Register_300425.ods(4.5 MB,one sheet of 66,523 x 21) renders 23,809 x 21 = 500,000 cells as 113 MB of html, and the renderer
process climbs to 4.7 GB laying it out — with the system UI going unresponsive on the way.
The same page cannot be displayed at all on the 2 GB device: the load dies mid-stream after ~80
seconds. Rendering the whole sheet (1.4 M cells, 316 MB of html) translates fine on the big device
— peak 1.33 GB, so
Html::translateis in good shape after #776/#780 — but there is no browserthat can then show it.
Where the bytes go
The html of one non-empty cell, read-only:
Over
test/data/reference-output/.../Supervised_Business_Register_300425.ods/sheet0.html:style="…"attributes, 14.78 MB of the 26.66 MB file — 55%, and about 72% of whatis left once that file's
contenteditable/data-odr-pathattributes (6.18 MB, absent in aread-only render) are discounted.
259,957 attributes:
vertical-align:top;,display:block;text-align:left;margin-left:0cm;font-family:Calibri;font-size:12pt;andfont-family:Calibri;font-size:12pt;color:#000000;.A sheet is the case where a document's styles are most repetitive and most repeated, and inline
styleis the one shape a browser cannot share: every attribute is parsed into its own declarationblock, and every element gets its own
ComputedStyle.What would help
classes in a
<style>block would remove over half the html bytes and, more importantly, letthe engine share style objects across cells instead of building a quarter-million of them.
<wbr>on a cell holding one plain string.td > x-p > x-s > textis four nodes per cell before any content; a plain cell could betd > textwiththe paragraph's style on the
td.Either one moves the ceiling for every embedder that shows a sheet in a browser engine, which is
what the html limits are really budgeting for. #781 is the same shape one layer down (three
registry elements per non-empty cell before any html limit applies).
Numbers above are from emulators, so treat the absolute megabytes as indicative; the ratios
repeated across runs and devices, and the failure modes (lmkd kill, a load dying mid-stream, an
unresponsive system UI) were the real ones.