Repository navigation
Record the filesystem comparison with s3fs (GH-1318) - #1321
Conversation
Add the history entry of the filesystem and objects suites at 7b20b49 against s3fs on one c8gn.2xlarge Spot host, with a supplementary run of s3fs at its default 50 MiB block size, and list it in RESULTS.md with a recommendation for transfers of many objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| | 2026-10-13 | `437276e1` | 4.1.0 release commit, filesystem suite | `c8gn.2xlarge` (arm64), one host | Spot | small, medium, large, xlarge (objects) | [2026-10-13-437276e1-filesystem](history/2026-10-13-437276e1-filesystem.md) | | ||
| | 2026-10-19 | `9e99caa8` | 4.2.0 (tagged on `baee716c`, which differs only in one test file) | `r7g.2xlarge` (arm64), fleet of 10 | Spot | medium, large, xlarge, xxlarge | [2026-10-19-9e99caa8](history/2026-10-19-9e99caa8.md) | | ||
| | 2026-10-19 | `9e99caa8` | 4.2.0 (tagged on `baee716c`, which differs only in one test file), filesystem suite | `c8gn.2xlarge` (arm64), one host | Spot | small, medium, large, xlarge (objects) | [2026-10-19-9e99caa8-filesystem](history/2026-10-19-9e99caa8-filesystem.md) | | ||
| | 2026-10-23 | `7b20b499` | unreleased (after 4.2.1), filesystem and objects suites against s3fs | `c8gn.2xlarge` (arm64), one host | Spot | small, medium, large, xlarge (objects); medium (1,000 objects) | [2026-10-23-7b20b499-filesystem](history/2026-10-23-7b20b499-filesystem.md) | |
There was a problem hiding this comment.
Self-review round one (implementation behavior: tables, generated numbers, links, structure)
Base 7b20b499bb3c5e28d06e15df38746ebceb9e4b56, head 3bcddf66aa76edd399124aeecc6dfff501ccca29. Covered: benchmarks/history/2026-10-23-7b20b499-filesystem.md (environment, selection, run record, findings, recommendation, limits, four result tables and the 50 MiB table) and benchmarks/RESULTS.md (index row, recommendation intro, new recommendation row).
Checks: every table is generated by script from the 66 + 14 recovered job-summary.csv files (216 + 56 cases, all 5 OK / 0 failed / not unsupported, no notes); the prose ranges were recomputed from the same rows; the README anchors #filesystem-suite and #objects-suite exist; the tree/7b20b499... link is the measured commit; S3FileSystem overrides only copy and get among the batch methods, both calling super(), so the "fsspec's sequential loops" statement holds for cat/put/pipe too.
Result: FINDINGS (1)
benchmarks/RESULTS.md:23: the Scales cell "small, medium, large, xlarge (objects); medium (1,000 objects)" reuses "(objects)" for object sizes, as the earlier filesystem rows do, right next to a set of 1,000 objects, so a reader cannot tell the two apart. Repair: name them "single objects" and "object set".
There was a problem hiding this comment.
Repaired in 047c8e4f: the Scales cell now reads "small, medium, large, xlarge (single objects); medium (object set)". Round-one follow-up over the range-diff 3bcddf66..047c8e4f: only benchmarks/RESULTS.md changed; the row still matches the entry, and markdownlint passes. CLEAN.
| | A Wrangler-like pandas read | PandasCursor | 10 million flat rows in 19.8 seconds through UNLOAD and 84.2 seconds through CSV, against 23.4 and 108.9 seconds for Wrangler | | ||
| | Asynchronous code | The native asyncio cursors, or the synchronous and ThreadPool APIs offloaded with `asyncio.to_thread()` or an executor; synchronous calls block the event loop while they poll | Single-query timings of the three APIs differed by a median of 1.7% in the 4.0.0 run | | ||
| | S3 transfers in asyncio applications | `AioS3FileSystem`; PyAthena keeps `S3FileSystem` registered for fsspec's `s3` and `s3a` protocols, and making `AioS3FileSystem` the default is to be revisited when boto3 supports asyncio natively, because it still runs the blocking boto3 calls in threads | With 40 workers on 8 vCPUs, `AioS3FileSystem` wrote 1 GiB and 6 GiB objects at 0.97 to 1.00 times and copied 6 GiB at 1.01 to 1.05 times the throughput of `S3FileSystem`, and read 1 GiB at 1.00 times; with 8 workers, it copied 6 GiB at 1.36 to 1.49 times (#1159) | | ||
| | Transfers of many objects with one call (`cat`, `get`, `put`, `pipe`, or `copy` with a list of paths) | `AioS3FileSystem` with `batch_size`; the synchronous `S3FileSystem` transfers one object at a time | In the s3fs comparison of `7b20b499`, 1,000 objects of 1 MiB at 286 to 484 objects per second with a batch size of 40, against 6.5 to 20.3 for `S3FileSystem` and 184.7 to 235.4 for s3fs, except copies, at 345.1 against 412.7 for s3fs | |
There was a problem hiding this comment.
Self-review round two (claims, caller/operator/reader perspectives)
Base 7b20b499bb3c5e28d06e15df38746ebceb9e4b56, head 3bcddf66aa76edd399124aeecc6dfff501ccca29. Claims listed from the PR body, the commit message, the entry, and RESULTS.md, each checked against the recovered summaries or the dependency source:
- s3fs defaults (50 MiB
default_block_size,_copy_managed(block=50 * 2**20),chunksize = chunksize or self.default_block_sizein_get_file,calculate_chunksize50 MiB in_put_file,MANAGED_COPY_THRESHOLD150 MiB,readaheadcache): verified in the s3fs 2026.9.0 wheel (the measured version), not only upstream main. - "uploads and copies parts one at a time":
_copy_managedawaits eachupload_part_copyin a list comprehension;S3File._upload_chunkcallsupload_partsynchronously; 768 = 6 GiB / 8 MiB. - "two chunks" for the 64 MiB get with 50 MiB chunks:
content_length > chunksizesplits bychunksize. - Run times, case counts, failures, AZs, AMI, library versions: from
done/,hosts/,environment.json, andinstances.jsonof both queues. - Measure the filesystem suite against s3fs on c8gn.2xlarge #1318's 20-30 minute estimate: quoted from the issue's Cost section.
- "The Sphinx site does not include
benchmarks/" (PR body): Sphinx's source isdocs/; docs only link to GitHub URLs. - Operator: both stacks deleted; no instances, volumes, scratch buckets, or
pyathena_bench_*databases remain; queue records in the CI bucket expire after a day and were recovered.
Result: FINDINGS (2)
benchmarks/RESULTS.md:40: "against 6.5 to 20.3 forS3FileSystem" compares the aiocat/get/put/piperates at batch size 40 with a sync range that includescopy(6.5-6.9) and concurrency 8. The matching sync range for those four operations at 40 is 9.5 to 20.3.- PR body, "its 1 GiB downloads peaked at 0.9-2.1 GiB against 0.3 GiB": true only for
max_concurrency40; with 8, s3fs peaked at 408-410 MiB (8 MiB chunks) and 1,316-1,361 MiB (50 MiB). The entry (line 79 here) already scopes it to 40; the PR body must say so too.
There was a problem hiding this comment.
Repaired in 047c8e4f: (1) the row now compares with 9.5 to 20.3 objects per second, the sync cat/get/put/pipe rates at concurrency 40, rechecked against job-summary.csv; (2) the PR body now scopes the download memory to max_concurrency 40 and names PyAthena as the comparison. Follow-up of both perspectives over the repaired hunks: no other claim in the row or body depended on these values. CLEAN.
|
|
||
| The PyAthena cases ran in the benchmark environment and the s3fs cases in the `s3fs` environment of the same checkout. | ||
|
|
||
| The block size of 8 MiB is the filesystem suite's setting for every API, as in the [4.2.0 run](2026-10-19-9e99caa8-filesystem.md); PyAthena's defaults are 5 MiB for files and 5 GiB parts for multipart copies, and s3fs's is 50 MiB. |
There was a problem hiding this comment.
Independent review (relayed): Codex CLI codex exec -s read-only, model gpt-6-astra (OpenAI), session 01a16bfe-6093-7303-a481-5275d239ce2c. Static review of a detached snapshot at head 047c8e4f4d3a23d9086393e3b1782ad00d459963, base 7b20b499bb3c5e28d06e15df38746ebceb9e4b56, with the literal diff, the 80 recovered job-summary.csv/environment.json files, queue/done/host/instance records, and the s3fs 2026.9.0 source; no PR text, commit messages, or prior findings were given. No edits, builds, tests, or GitHub access.
Coverage reported: the two-file diff, all 1,560 numeric table cells (all match the CSVs at displayed precision), harness and filesystem source, README, and the earlier entry. Not independently established: #1318's estimate, cleanup, and stack deletion (no records supplied); fsspec was reasoned from callers.
Result: FINDINGS (6), all verified against the code and data:
- [P2]
history:40,:100: "PyAthena's default is 5 MiB" conflates file I/O (5 MiB) with multipart copies (S3Coredefault partMULTIPART_UPLOAD_MAX_PART_SIZE, 5 GiB), and the objects suite uses each filesystem's defaults, not 8 MiB. - [P2]
history:65,:76: "its workers do not apply" / "which use no workers": the firstbytes-cache fetch requests two blocks, whichS3File._fetch_rangesplits into two parallel ranges. - [P2]
RESULTS.md:40:pipetakes a dictionary of paths and bytes, not a list of paths. - [P3]
history:76: "Every s3fs process peaked at 13 threads" is false forrm(44, from the harness's 32-thread preparation pool,SETUP_WORKERS). - [P3]
history:41: "s3fs uploads and copies parts one at a time" also coversput_file(), which uploads in batches; the 64 MiB supplementaryputis one PutObject (64 MiB < 2 x 50 MiB). - [P3] rounding: 2.4 -> 2.3 (2.3487), "at or below 5 ms" -> 5.25 ms (find n8), 4.80 -> 4.81, 23.7 -> 23.8, 0.83 -> 0.84.
Repaired in 83a49efb92b2f9f4f490bc7f05fdf56b3aee4b62 (all six); the PR body and the planned #1315 comment were corrected for the same values (2.3, 0.84, threads except deletes).
There was a problem hiding this comment.
Self-review of the repair 047c8e4f..83a49efb (range-diff; both objects present), both perspectives:
- Round one (behavior): only
history/2026-10-23-7b20b499-filesystem.mdandRESULTS.md:40prose changed; tables untouched; markdownlint andjust lintpass. - Round two (claims):
S3Core.MULTIPART_UPLOAD_MAX_PART_SIZE = 5 * 2**30is the copy default when noblock_sizeis given (s3_core.py:517,:1246); the objects suite builds each filesystem without a block size (filesystem.py:239) and copies throughfs.copy/fs._copywithout one (objects.py:122-123), so "each filesystem's defaults" holds and 1 MiB fits in one range or part (5 MiB, 50 MiB).SETUP_WORKERS = 32(objects.py:34) and thermpeaks 43/44 for every API match the CSVs. The 5.25 ms bound is thefindn8 p95 (5.246 ms).S3File._fetch_rangesplits the first two-block fetch into two ranges (s3.py:3289). The new 64 MiB PutObject sentence followssize < min(5 GiB, 2 * chunksize)in s3fs 2026.9.0_put_file.
CLEAN. Independent follow-up requested next.
There was a problem hiding this comment.
Independent follow-up (relayed): Codex CLI codex exec -s read-only, model gpt-6-astra, session 01a16c07-a57b-7383-a9a2-39585464daa9, static review of the snapshot at 83a49efb, given the repair diff 047c8e4f..83a49efb (confirmed identical to the branch), the six findings, and the same evidence. Covered: the changed lines of both files, both runs' configurations and all 272 case summaries, the harness, README, PyAthena filesystem, s3fs 2026.9.0 and fsspec sources. Result: CLEAN; all six findings repaired, no new inaccuracies (unrounded values 2.348712, 5.246169 ms, 4.806528, 23.769719, 0.836232 confirmed).
WHAT
Adds
benchmarks/history/2026-10-23-7b20b499-filesystem.md, the measurement of #1318: the filesystem suite (#1316) and the objects suite (#1317) at7b20b499on onec8gn.2xlargeSpot host, comparing PyAthena'sS3FileSystemandAioS3FileSystemwith s3fs 2026.9.0.A supplementary queue repeated the single-object cases of s3fs with its default block size of 50 MiB, because s3fs uploads and copies parts one at a time and the suite's 8 MiB parts would otherwise understate it.
benchmarks/RESULTS.mdlists the entry and adds one recommendation:AioS3FileSystemwithbatch_sizefor transfers of many objects, since the synchronousS3FileSystemtransfers them one at a time.Main findings:
get_file(): s3fs was 2.2–3.7× faster with 8 MiB chunks and 5–9× with 50 MiB for objects of 256 MiB and larger; PyAthena reads one block at a time.S3FileSystemrancat/get/put/pipe/copyone object at a time, 7–59× slower than s3fs;AioS3FileSystemmatched s3fs at concurrency 8 and was 1.4–2.5× faster at 40, except copies (0.83×) andinfo()(0.69×).max_concurrency40 peaked at 0.9–2.1 GiB against 0.3 GiB for PyAthena.WHY
Closes #1318, step 3 of #1315.
The recommendation for #1315 is in the entry: the throughput advantage meets #1315's first decision criterion, and two gaps (sequential batch operations of
S3FileSystem, sequentialget_file()) are to be filed as improvement issues before a standalone package is designed.TEST
fs-s3fs-1, 66 jobs, 216 cases, five trials each, no failures (2026-10-23 15:46–20:03 UTC); queuefs-s3fs-50m-1, 14 jobs, 56 cases, no failures (2026-10-24 02:00–03:24 UTC). Both stacks were cleaned up withcleanup --executeand deleted; no instances, volumes, buckets, or scratch databases remain.job-summary.csvfiles by script; the tables are generated from them.just lintandjust docs lintpass on the head;markdownlint-cli2also passes on the history entry, which the docs glob does not include.benchmarks/.🤖 Generated with Claude Code