Skip to content

Commit 84d7d53

Browse files
amotinbehlendorf
authored andcommitted
Improve speculative prefetcher for block cloning
- Issue prescient prefetches for demand indirect blocks after the first one. It should be quite rare for reads/writes, but much more useful for cloning due to much bigger (up to 1022 blocks) accesses. It covers the gap during the first couple accesses when we can not speculate yet, but we know what is needed right now. It reduces dbuf_hold() sync read delays in dmu_buf_hold_array_by_dnode(). - Increase maximum prefetch distance for indirect blocks from 64 to 128MB. It should cover the maximum 1022 blocks of block cloning access size in case of default 128KB recordsize used. In case of bigger recordsize the above prescient prefetch should also help. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes openzfs#16814
1 parent d90042d commit 84d7d53

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

module/zfs/dmu_zfetch.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ static unsigned int zfetch_min_distance = 4 * 1024 * 1024;
6363
/* max bytes to prefetch per stream (default 64MB) */
6464
unsigned int zfetch_max_distance = 64 * 1024 * 1024;
6565
#endif
66-
/* max bytes to prefetch indirects for per stream (default 64MB) */
67-
unsigned int zfetch_max_idistance = 64 * 1024 * 1024;
66+
/* max bytes to prefetch indirects for per stream (default 128MB) */
67+
unsigned int zfetch_max_idistance = 128 * 1024 * 1024;
6868
/* max request reorder distance within a stream (default 16MB) */
6969
unsigned int zfetch_max_reorder = 16 * 1024 * 1024;
7070
/* Max log2 fraction of holes in a stream */
@@ -472,6 +472,7 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
472472
zstream_t *zs;
473473
spa_t *spa = zf->zf_dnode->dn_objset->os_spa;
474474
zfs_prefetch_type_t os_prefetch = zf->zf_dnode->dn_objset->os_prefetch;
475+
int64_t ipf_start, ipf_end;
475476

476477
if (zfs_prefetch_disable || os_prefetch == ZFS_PREFETCH_NONE)
477478
return (NULL);
@@ -571,13 +572,13 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
571572
* This access is not part of any existing stream. Create a new
572573
* stream for it unless we are at the end of file.
573574
*/
575+
ASSERT0P(zs);
574576
if (end_blkid < maxblkid)
575577
dmu_zfetch_stream_create(zf, end_blkid);
576578
mutex_exit(&zf->zf_lock);
577-
if (!have_lock)
578-
rw_exit(&zf->zf_dnode->dn_struct_rwlock);
579579
ZFETCHSTAT_BUMP(zfetchstat_misses);
580-
return (NULL);
580+
ipf_start = 0;
581+
goto prescient;
581582

582583
hit:
583584
nblks = dmu_zfetch_hit(zs, nblks);
@@ -650,6 +651,7 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
650651
pf_nblks = zs->zs_ipf_dist >> dbs;
651652
if (zs->zs_ipf_start < zs->zs_pf_end)
652653
zs->zs_ipf_start = zs->zs_pf_end;
654+
ipf_start = zs->zs_ipf_end;
653655
if (zs->zs_ipf_end < zs->zs_pf_end + pf_nblks)
654656
zs->zs_ipf_end = zs->zs_pf_end + pf_nblks;
655657

@@ -658,8 +660,30 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
658660
zfs_refcount_add(&zs->zs_callers, NULL);
659661
mutex_exit(&zf->zf_lock);
660662

663+
prescient:
664+
/*
665+
* Prefetch the following indirect blocks for this access to reduce
666+
* dbuf_hold() sync read delays in dmu_buf_hold_array_by_dnode().
667+
* This covers the gap during the first couple accesses when we can
668+
* not predict the future yet, but know what is needed right now.
669+
* This should be very rare for reads/writes to need more than one
670+
* indirect, but more useful for cloning due to much bigger accesses.
671+
*/
672+
ipf_start = MAX(ipf_start, blkid + 1);
673+
int epbs = zf->zf_dnode->dn_indblkshift - SPA_BLKPTRSHIFT;
674+
ipf_start = P2ROUNDUP(ipf_start, 1 << epbs) >> epbs;
675+
ipf_end = P2ROUNDUP(end_blkid, 1 << epbs) >> epbs;
676+
677+
int issued = 0;
678+
for (int64_t iblk = ipf_start; iblk < ipf_end; iblk++) {
679+
issued += dbuf_prefetch(zf->zf_dnode, 1, iblk,
680+
ZIO_PRIORITY_SYNC_READ, ARC_FLAG_PRESCIENT_PREFETCH);
681+
}
682+
661683
if (!have_lock)
662684
rw_exit(&zf->zf_dnode->dn_struct_rwlock);
685+
if (issued)
686+
ZFETCHSTAT_ADD(zfetchstat_io_issued, issued);
663687
return (zs);
664688
}
665689

0 commit comments

Comments
 (0)