Hi Kevin,
Thank you for the deep dive into DART (IOMMU) mapping overhead. To address your question regarding the "typical I/O sizes" the system dispatches, we performed an A/B comparison to observe the behavior of the macOS Storage Stack under different kIOMaximumSegmentByteCount configurations.
Testing Methodology:
We instrumented UserProcessBundledParallelTasks_Impl to log the exact fRequestedTransferCount for every incoming task. While the documentation refers to this field as a "count," the values received (e.g., 16,384) confirm it represents the total byte count. To stimulate the kernel's merging logic, we used fio with a mixed workload ranging from 4KB to 64KB (bsrange=4k-64k).
The following distribution was captured during a 10-second high-load test:
I/O Size (Bytes) | Case A (16K Limit) | Case A % | Case B (64K Limit) | Case B %
------------------|--------------------|----------|--------------------|---------
16,384 (16K) | 3,174 | 81.2% | 2,906 | 82.9%
524,288 (512K) | 526 | 13.5% | 430 | 12.3%
262,144 (256K) | 210 | 5.3% | 167 | 4.8%
4,096 (4K) | 0 | 0% | 2 | 0.06%
(Note: The 512K and 256K requests are large composite tasks consisting of multiple segments, respecting our 512KB hardware limit set via HBA constraints.)
Observations and Conclusions:
Validation of Intuition: The data perfectly aligns with your intuition. Even in Case B, where we allowed up to 64KB segments, over 82% of the requests remained exactly 16KB. macOS on Apple Silicon clearly has an inherent preference for 16KB alignment, likely matching the native page size.
Merging Efficiency: Tiny 4KB fragments were almost entirely non-existent. Even though fio issued 4KB requests, the Storage Stack merged them into 16KB blocks before they reached the DEXT.
The 2.8x Performance Secret: This explains why the 16KB segment limit provided such a massive boost. Since 16KB is already the "natural" size the system prefers to send, explicitly locking kIOMaximumSegmentByteCount to 16KB removes the calculation cost for the DART to handle cross-page boundaries without forcing the system to send smaller or more fragmented I/O.
By setting the driver's constraints to match the kernel's native behavior, we’ve effectively put the I/O path on the "fast track" by simplifying the mapping logic.
Best regards,
Charles
Topic:
App & System Services
SubTopic:
Drivers
Tags: