ddt: compare keys 64-bits at a time, trying to match ZAP order

This yields substantial performance improvements when we only write out
some small % of entries at a time, as it will cause entries that will go
into "nearby" ZAP leaf nodes to be grouped closer together in the AVL, and
so touch fewer blocks. Without this, the distribution is an even spread,
so we touch a lot more ZAP leaf nodes for any given number of entries.

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Co-authored-by: Allan Jude <allan@klarasystems.com>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Sponsored-by: Klara, Inc.
Sponsored-by: iXsystems, Inc.
Closes #15895
This commit is contained in:
Rob Norris 2023-10-11 12:46:55 +11:00 committed by Brian Behlendorf
parent 27e9cb5f80
commit 592f38900d
1 changed files with 13 additions and 17 deletions

View File

@ -1038,29 +1038,25 @@ ddt_prefetch(spa_t *spa, const blkptr_t *bp)
} }
/* /*
* Key comparison. Any struct wanting to make use of this function must have * ddt_key_t comparison. Any struct wanting to make use of this function must
* the key as the first element. * have the key as the first element. Casts it to N uint64_ts, and checks until
* we find there's a difference. This is intended to match how ddt_zap.c drives
* the ZAPs (first uint64_t as the key prehash), which will minimise the number
* of ZAP blocks touched when flushing logged entries from an AVL walk. This is
* not an invariant for this function though, should you wish to change it.
*/ */
#define DDT_KEY_CMP_LEN (sizeof (ddt_key_t) / sizeof (uint16_t))
typedef struct ddt_key_cmp {
uint16_t u16[DDT_KEY_CMP_LEN];
} ddt_key_cmp_t;
int int
ddt_key_compare(const void *x1, const void *x2) ddt_key_compare(const void *x1, const void *x2)
{ {
const ddt_key_cmp_t *k1 = (const ddt_key_cmp_t *)x1; const uint64_t *k1 = (const uint64_t *)x1;
const ddt_key_cmp_t *k2 = (const ddt_key_cmp_t *)x2; const uint64_t *k2 = (const uint64_t *)x2;
int32_t cmp = 0;
for (int i = 0; i < DDT_KEY_CMP_LEN; i++) { int cmp;
cmp = (int32_t)k1->u16[i] - (int32_t)k2->u16[i]; for (int i = 0; i < (sizeof (ddt_key_t) / sizeof (uint64_t)); i++)
if (likely(cmp)) if (likely((cmp = TREE_CMP(k1[i], k2[i])) != 0))
break; return (cmp);
}
return (TREE_ISIGN(cmp)); return (0);
} }
/* Create the containing dir for this DDT and bump the feature count */ /* Create the containing dir for this DDT and bump the feature count */