Running a test comparing the overhead between regular open and what we do in anka:
❯ ./run.sh
Creating sparse APFS image with hdiutil (2048 MiB cap, volume BenchAPFS) → /Users/nathanpierce/apfs-open-repro/disk.dmg
created: /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage
Note: hdiutil wrote /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage (-type SPARSE uses .sparseimage beside the requested name).
Done. Image stats:
-rw-r--r-- 1 nathanpierce staff 10M May 14 13:55 /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage
clonefile(2): /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage → /Users/nathanpierce/apfs-open-repro/disk_clone.dmg
Clone stats:
-rw-r--r-- 1 nathanpierce staff 10M May 14 13:55 /Users/nathanpierce/apfs-open-repro/disk_clone.dmg
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Original sparse image
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
=== Phase 1: bare open(2) / close (baseline) ===
Bench: ./bench_open /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage 12
opening /Users/nathanpierce/apfs-open-repro/disk.dmg.sparseimage for 12 consecutive open/close rounds
iteration 01 open() 0.011 ms (fd=3)
iteration 02 open() 0.009 ms (fd=3)
iteration 03 open() 0.009 ms (fd=3)
iteration 04 open() 0.008 ms (fd=3)
iteration 05 open() 0.008 ms (fd=3)
iteration 06 open() 0.008 ms (fd=3)
iteration 07 open() 0.008 ms (fd=3)
iteration 08 open() 0.008 ms (fd=3)
iteration 09 open() 0.008 ms (fd=3)
iteration 10 open() 0.008 ms (fd=3)
iteration 11 open() 0.008 ms (fd=3)
iteration 12 open() 0.008 ms (fd=3)
Phase 2: attached /dev/disk21 (read-only) — GPT/NXSB use decoded sectors (UDIF-safe).
=== Phase 2: Anka-style stack (vdsk_native fcntls + fstat [+DKIOC] + GPT + NXSB) ===
Bench: ./bench_anka_style_open /dev/disk21 12
iteration 01 anka-style 2.451 ms (open+fcntl 1.332 ms, ioctl yes, gpt+nxsb skip/err)
iteration 02 anka-style 0.554 ms (open+fcntl 0.047 ms, ioctl yes, gpt+nxsb skip/err)
iteration 03 anka-style 0.977 ms (open+fcntl 0.496 ms, ioctl yes, gpt+nxsb skip/err)
iteration 04 anka-style 1.040 ms (open+fcntl 0.364 ms, ioctl yes, gpt+nxsb skip/err)
iteration 05 anka-style 1.485 ms (open+fcntl 1.395 ms, ioctl yes, gpt+nxsb skip/err)
iteration 06 anka-style 1.577 ms (open+fcntl 0.645 ms, ioctl yes, gpt+nxsb skip/err)
iteration 07 anka-style 1.381 ms (open+fcntl 1.020 ms, ioctl yes, gpt+nxsb skip/err)
iteration 08 anka-style 2.357 ms (open+fcntl 1.508 ms, ioctl yes, gpt+nxsb skip/err)
iteration 09 anka-style 0.500 ms (open+fcntl 0.069 ms, ioctl yes, gpt+nxsb skip/err)
iteration 10 anka-style 1.413 ms (open+fcntl 0.722 ms, ioctl yes, gpt+nxsb skip/err)
iteration 11 anka-style 0.195 ms (open+fcntl 0.061 ms, ioctl yes, gpt+nxsb skip/err)
iteration 12 anka-style 0.653 ms (open+fcntl 0.099 ms, ioctl yes, gpt+nxsb skip/err)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
clonefile(2) copy
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
=== Phase 1: bare open(2) / close (baseline) ===
Bench: ./bench_open /Users/nathanpierce/apfs-open-repro/disk_clone.dmg 12
opening /Users/nathanpierce/apfs-open-repro/disk_clone.dmg for 12 consecutive open/close rounds
iteration 01 open() 0.024 ms (fd=3)
iteration 02 open() 0.011 ms (fd=3)
iteration 03 open() 0.009 ms (fd=3)
iteration 04 open() 0.010 ms (fd=3)
iteration 05 open() 0.010 ms (fd=3)
iteration 06 open() 0.009 ms (fd=3)
iteration 07 open() 0.009 ms (fd=3)
iteration 08 open() 0.009 ms (fd=3)
iteration 09 open() 0.009 ms (fd=3)
iteration 10 open() 0.008 ms (fd=3)
iteration 11 open() 0.008 ms (fd=3)
iteration 12 open() 0.008 ms (fd=3)
Phase 2: attached /dev/disk21 (read-only) — GPT/NXSB use decoded sectors (UDIF-safe).
=== Phase 2: Anka-style stack (vdsk_native fcntls + fstat [+DKIOC] + GPT + NXSB) ===
Bench: ./bench_anka_style_open /dev/disk21 12
iteration 01 anka-style 3.146 ms (open+fcntl 1.300 ms, ioctl yes, gpt+nxsb skip/err)
iteration 02 anka-style 1.596 ms (open+fcntl 0.693 ms, ioctl yes, gpt+nxsb skip/err)
iteration 03 anka-style 1.148 ms (open+fcntl 0.607 ms, ioctl yes, gpt+nxsb skip/err)
iteration 04 anka-style 1.357 ms (open+fcntl 0.377 ms, ioctl yes, gpt+nxsb skip/err)
iteration 05 anka-style 0.994 ms (open+fcntl 0.680 ms, ioctl yes, gpt+nxsb skip/err)
iteration 06 anka-style 1.132 ms (open+fcntl 0.669 ms, ioctl yes, gpt+nxsb skip/err)
iteration 07 anka-style 0.087 ms (open+fcntl 0.032 ms, ioctl yes, gpt+nxsb skip/err)
iteration 08 anka-style 2.194 ms (open+fcntl 0.454 ms, ioctl yes, gpt+nxsb skip/err)
iteration 09 anka-style 1.149 ms (open+fcntl 0.334 ms, ioctl yes, gpt+nxsb skip/err)
iteration 10 anka-style 0.087 ms (open+fcntl 0.034 ms, ioctl yes, gpt+nxsb skip/err)
iteration 11 anka-style 1.940 ms (open+fcntl 0.884 ms, ioctl yes, gpt+nxsb skip/err)
iteration 12 anka-style 1.635 ms (open+fcntl 1.567 ms, ioctl yes, gpt+nxsb skip/err)
So we do see that each time we call open it's delayed for some reason, no matter if we're doing anything special.
Interesting that the clonefile() produced image does actually cause a bit more delay