Skip to content

DLIO local_changes: Make skip_head=True the default for large-record object-storage training (unet3d) #668

Description

@bissantz

Summary.
_s3_stream_s3dlio() hardcodes skip_head=False for records ≥ 16 MiB
(dlio_benchmark/reader/_s3_iterable_mixin.py#L407). The HEAD supplies the object size
that activates s3dlio's concurrent range-split engine (own threshold: 32 MiB, S3DLIO_RANGE_THRESHOLD_MB), so every unet3d sample (139.8 MiB) becomes 1 HEAD + ~4–5 concurrent range-GETs instead of one whole-object GET.

Impact.
For the same configuration (same read_threads,prefetch_window, dataset), the forced HEAD+range path costs ~20 AU points vs whole-object GETs — the difference between unet3d passing and failing its 90% AU bar.

Actual finding
The comment above the heuristic justifies the HEAD as enabling range-split from epoch 1 instead of epoch 2+ (via s3dlio's size cache). Per-epoch AU shows otherwise: with skip_head=True both epochs run at identical AU (no automatic epoch-2 range-split — the per-process size cache does not survive DLIO's per-epoch DataLoader worker re-spawn), and with skip_head=False both epochs pay the full penalty. In practice the flag selects range-split always vs never, not epoch-1 vs epoch-2+. DLIO already parallelizes across objects (read_threads × prefetch_window); intra-object range parallelism only multiplies the request count ~5× in the case for unet3d and contends with the pipeline's own in-flight window. Since skip_head is not user-tunable and is in neither CLOSED nor OPEN allowed params, this default alone determines what every object-storage submission measures.
My suspicion is that the clearing caches call in between epochs the mlpstorage executable reverts the DLIO optimization and therefore the caches stay cold.

Proposed change.
In dlio_benchmark/reader/_s3_iterable_mixin.py, line 407 (mlcommons/DLIO_local_changes @ f6796ed): default to whole-object GETs for all record sizes; keep HEAD+range-split as an opt-in for stores where per-stream bandwidth is the bottleneck.

-        # skip_head controls whether s3dlio issues a HEAD before each GET.
-        # Default (True): skip HEAD, do plain GET, cache the size — epoch 2+
-        # will range-split correctly for large objects automatically.
-        # False: issue HEAD first so range splitting can fire from epoch 1.
-        # We override to False only when we know objects are >= 16 MiB, since
-        # those benefit most from parallel range GETs on the very first epoch.
-        record_bytes = getattr(args, "record_length", 0) or 0
-        skip_head = not (record_bytes >= 16 * 1024 * 1024)
+        skip_head = True

Metadata

Metadata

Assignees

Labels

No labels
No labels

Fields

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions