Stress test that writes a single worksheet populated with N unique string values laid out in a 100-column grid (so N/100 rows). Each cell gets a distinct 'c<i>' string so the sharedStrings table grows linearly with N. Parameterised across N = 100, 10000, 100000 to exercise the sharedStrings allocator at real-world spreadsheet sizes.
Library verdicts: python-xlsx: — xlsxjs: —
| Feature id | xlsx/scale-cells--n100000 |
|---|---|
| Format | xlsx |
| Category | scale |
| Family | xlsx/scale-cells |
| Axis values | size=n100000 |
| Spec | ecma-376-5-part-1 § 18.4.8 sst |
| ID / part | Predicate | XPath | python-xlsx | xlsxjs |
|---|---|---|---|---|
sst-unique-count-n100000xl/sharedStrings.xml | equal = 100000The sharedStrings table's uniqueCount attribute must equal N. | /x:sst/@uniqueCount | — | — |
sst-si-count-n100000xl/sharedStrings.xml | equal = 100000The sharedStrings table must contain exactly N <si> elements. | string(count(/x:sst/x:si)) | — | — |
first-cell-marker-n100000xl/sharedStrings.xml | existThe first <si> entry must be the 'c0' marker string, guarding against head-of-stream reorder / truncation. | /x:sst/x:si[1]/x:t[normalize-space()='c0'] | — | — |
last-cell-marker-n100000xl/sharedStrings.xml | existThe last <si> entry must be the expected 'c<N-1>' marker, guarding against tail truncation or reorder. | /x:sst/x:si[last()]/x:t[normalize-space()='c99999'] | — | — |
No render assertions declared.
scripts/gen_scale_cells.py
#!/usr/bin/env python3
"""Generate ``fixtures/xlsx/scale-cells--<n>.xlsx``.
Parameterised stress fixture for the ``xlsx/scale-cells`` family. Writes
a single-sheet workbook whose active sheet contains ``--count`` cells:
a 100-column grid filled row-by-row. Each cell carries a short
deterministic string so the sharedStrings table grows proportionally.
Assertions target:
- a specific cell value in the first row, exercising the A1 corner
- a specific cell value in the final row, exercising the far corner
past the row-height dimension threshold
The generator writes strings (not numbers) on purpose: this exercises
the sharedStrings table and surfaces any scaling bug in its index
allocator / lookup.
Usage::
python scripts/gen_scale_cells.py \
--count 10000 \
--out fixtures/xlsx/scale-cells--n10000.xlsx
"""
from __future__ import annotations
import argparse
import datetime as _dt
from pathlib import Path
from xlsx import Workbook
_REPRODUCIBLE_DT = (1980, 1, 1, 0, 0, 0)
_REPO_ROOT = Path(__file__).resolve().parent.parent
# Grid width. 100k cells -> 1000 rows x 100 cols, safely inside any
# SpreadsheetML row/column limits.
_COLS = 100
def _write(count: int, out: Path) -> None:
wb = Workbook()
ws = wb.active
for i in range(count):
row = (i // _COLS) + 1
col = (i % _COLS) + 1
# 'c' + decimal index. Cheap, unique, deterministic.
ws.cell(row=row, column=col, value=f"c{i}")
out.parent.mkdir(parents=True, exist_ok=True)
wb.save(out, zip_date_time=_REPRODUCIBLE_DT)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--count", required=True, type=int, help="Number of cells to populate.")
parser.add_argument("--out", required=True, help="Output path for the .xlsx file.")
args = parser.parse_args()
out_path = Path(args.out)
if not out_path.is_absolute():
out_path = _REPO_ROOT / out_path
_write(args.count, out_path)
print(out_path)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "xlsx/scale-cells--n100000",
"kind": "literal",
"title": "Scale: many cells in one sheet",
"format": "xlsx",
"category": "scale",
"summary": "Stress test that writes a single worksheet populated with N unique string values laid out in a 100-column grid (so N/100 rows). Each cell gets a distinct 'c<i>' string so the sharedStrings table grows linearly with N. Parameterised across N = 100, 10000, 100000 to exercise the sharedStrings allocator at real-world spreadsheet sizes.",
"spec": {
"source": "ecma-376-5-part-1",
"clause": "18.4.8",
"element": "sst",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/SpreadsheetML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/sml.xsd",
"notes": "python-xlsx writes string cells as <c t=\"s\"><v>INDEX</v></c> where INDEX references a <si> entry in xl/sharedStrings.xml. Filling 100k unique strings is not unusual in a real workbook and exercises both the sharedStrings allocator (map + list) and the worksheet serialiser. The manifest asserts (a) the first and last cell carry their expected marker strings, (b) the sst uniqueCount attribute matches N, (c) the <si> element count matches N. Taken together these catch reuse-index collisions, uniqueCount/element-count drift, and partial writes."
},
"fixtures": {
"machine": "xlsx/scale-cells--n100000"
},
"generator": {
"python": "scripts/gen_scale_cells.py",
"arg_template": "--count {size.n} --out fixtures/xlsx/scale-cells--{size.id}.xlsx"
},
"meta": {
"performance": {
"recorded_on": "2026-05-05",
"notes": "Save-time scales sub-linearly from 100 to 10k (startup overhead dominates the 100-cell case) and roughly linearly from 10k to 100k. sharedStrings.xml becomes the dominant part past 10k cells (~220KB at 10k, ~2.2MB at 100k).",
"cases": [
{
"id": "n100",
"save_seconds": 0.19,
"file_bytes": 5527,
"shared_strings_bytes": 1985
},
{
"id": "n10000",
"save_seconds": 0.29,
"file_bytes": 60217,
"shared_strings_bytes": 208987
},
{
"id": "n100000",
"save_seconds": 1.3,
"file_bytes": 564068,
"shared_strings_bytes": 2188988
}
]
}
},
"_expansion": {
"parent_id": "xlsx/scale-cells",
"bindings": {
"size": "n100000"
}
},
"assertions": [
{
"id": "sst-unique-count-n100000",
"part": "xl/sharedStrings.xml",
"namespaces": {
"x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "/x:sst/@uniqueCount",
"must": "equal",
"value": "100000",
"description": "The sharedStrings table's uniqueCount attribute must equal N."
},
{
"id": "sst-si-count-n100000",
"part": "xl/sharedStrings.xml",
"namespaces": {
"x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "string(count(/x:sst/x:si))",
"must": "equal",
"value": "100000",
"description": "The sharedStrings table must contain exactly N <si> elements."
},
{
"id": "first-cell-marker-n100000",
"part": "xl/sharedStrings.xml",
"namespaces": {
"x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "/x:sst/x:si[1]/x:t[normalize-space()='c0']",
"must": "exist",
"description": "The first <si> entry must be the 'c0' marker string, guarding against head-of-stream reorder / truncation."
},
{
"id": "last-cell-marker-n100000",
"part": "xl/sharedStrings.xml",
"namespaces": {
"x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "/x:sst/x:si[last()]/x:t[normalize-space()='c99999']",
"must": "exist",
"description": "The last <si> entry must be the expected 'c<N-1>' marker, guarding against tail truncation or reorder."
}
]
}
No rendered reference is available for this case.