xref: /freebsd/sys/contrib/openzfs/module/zfs/ddt_stats.c (revision ce4dcb97ca433b2a2f03fbae957dae0ff16f6f51)
14fefe1b7SMartin Matuska /*
24fefe1b7SMartin Matuska  * CDDL HEADER START
34fefe1b7SMartin Matuska  *
44fefe1b7SMartin Matuska  * The contents of this file are subject to the terms of the
54fefe1b7SMartin Matuska  * Common Development and Distribution License (the "License").
64fefe1b7SMartin Matuska  * You may not use this file except in compliance with the License.
74fefe1b7SMartin Matuska  *
84fefe1b7SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94fefe1b7SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
104fefe1b7SMartin Matuska  * See the License for the specific language governing permissions
114fefe1b7SMartin Matuska  * and limitations under the License.
124fefe1b7SMartin Matuska  *
134fefe1b7SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
144fefe1b7SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154fefe1b7SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
164fefe1b7SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
174fefe1b7SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
184fefe1b7SMartin Matuska  *
194fefe1b7SMartin Matuska  * CDDL HEADER END
204fefe1b7SMartin Matuska  */
214fefe1b7SMartin Matuska 
224fefe1b7SMartin Matuska /*
234fefe1b7SMartin Matuska  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
244fefe1b7SMartin Matuska  * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
254fefe1b7SMartin Matuska  * Copyright (c) 2022 by Pawel Jakub Dawidek
264fefe1b7SMartin Matuska  * Copyright (c) 2023, Klara Inc.
274fefe1b7SMartin Matuska  */
284fefe1b7SMartin Matuska 
294fefe1b7SMartin Matuska #include <sys/zfs_context.h>
304fefe1b7SMartin Matuska #include <sys/spa.h>
314fefe1b7SMartin Matuska #include <sys/spa_impl.h>
324fefe1b7SMartin Matuska #include <sys/ddt.h>
334fefe1b7SMartin Matuska #include <sys/ddt_impl.h>
344fefe1b7SMartin Matuska 
354fefe1b7SMartin Matuska static void
364fefe1b7SMartin Matuska ddt_stat_generate(ddt_t *ddt, ddt_entry_t *dde, ddt_stat_t *dds)
374fefe1b7SMartin Matuska {
384fefe1b7SMartin Matuska 	spa_t *spa = ddt->ddt_spa;
394fefe1b7SMartin Matuska 	ddt_phys_t *ddp = dde->dde_phys;
404fefe1b7SMartin Matuska 	ddt_key_t *ddk = &dde->dde_key;
414fefe1b7SMartin Matuska 	uint64_t lsize = DDK_GET_LSIZE(ddk);
424fefe1b7SMartin Matuska 	uint64_t psize = DDK_GET_PSIZE(ddk);
434fefe1b7SMartin Matuska 
444fefe1b7SMartin Matuska 	memset(dds, 0, sizeof (*dds));
454fefe1b7SMartin Matuska 
464fefe1b7SMartin Matuska 	for (int p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
474fefe1b7SMartin Matuska 		uint64_t dsize = 0;
484fefe1b7SMartin Matuska 		uint64_t refcnt = ddp->ddp_refcnt;
494fefe1b7SMartin Matuska 
504fefe1b7SMartin Matuska 		if (ddp->ddp_phys_birth == 0)
514fefe1b7SMartin Matuska 			continue;
524fefe1b7SMartin Matuska 
534fefe1b7SMartin Matuska 		int ndvas = DDK_GET_CRYPT(&dde->dde_key) ?
544fefe1b7SMartin Matuska 		    SPA_DVAS_PER_BP - 1 : SPA_DVAS_PER_BP;
554fefe1b7SMartin Matuska 		for (int d = 0; d < ndvas; d++)
564fefe1b7SMartin Matuska 			dsize += dva_get_dsize_sync(spa, &ddp->ddp_dva[d]);
574fefe1b7SMartin Matuska 
584fefe1b7SMartin Matuska 		dds->dds_blocks += 1;
594fefe1b7SMartin Matuska 		dds->dds_lsize += lsize;
604fefe1b7SMartin Matuska 		dds->dds_psize += psize;
614fefe1b7SMartin Matuska 		dds->dds_dsize += dsize;
624fefe1b7SMartin Matuska 
634fefe1b7SMartin Matuska 		dds->dds_ref_blocks += refcnt;
644fefe1b7SMartin Matuska 		dds->dds_ref_lsize += lsize * refcnt;
654fefe1b7SMartin Matuska 		dds->dds_ref_psize += psize * refcnt;
664fefe1b7SMartin Matuska 		dds->dds_ref_dsize += dsize * refcnt;
674fefe1b7SMartin Matuska 	}
684fefe1b7SMartin Matuska }
694fefe1b7SMartin Matuska 
704fefe1b7SMartin Matuska void
714fefe1b7SMartin Matuska ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src, uint64_t neg)
724fefe1b7SMartin Matuska {
734fefe1b7SMartin Matuska 	const uint64_t *s = (const uint64_t *)src;
744fefe1b7SMartin Matuska 	uint64_t *d = (uint64_t *)dst;
754fefe1b7SMartin Matuska 	uint64_t *d_end = (uint64_t *)(dst + 1);
764fefe1b7SMartin Matuska 
774fefe1b7SMartin Matuska 	ASSERT(neg == 0 || neg == -1ULL);	/* add or subtract */
784fefe1b7SMartin Matuska 
794fefe1b7SMartin Matuska 	for (int i = 0; i < d_end - d; i++)
804fefe1b7SMartin Matuska 		d[i] += (s[i] ^ neg) - neg;
814fefe1b7SMartin Matuska }
824fefe1b7SMartin Matuska 
834fefe1b7SMartin Matuska void
844fefe1b7SMartin Matuska ddt_stat_update(ddt_t *ddt, ddt_entry_t *dde, uint64_t neg)
854fefe1b7SMartin Matuska {
864fefe1b7SMartin Matuska 	ddt_stat_t dds;
874fefe1b7SMartin Matuska 	ddt_histogram_t *ddh;
884fefe1b7SMartin Matuska 	int bucket;
894fefe1b7SMartin Matuska 
904fefe1b7SMartin Matuska 	ddt_stat_generate(ddt, dde, &dds);
914fefe1b7SMartin Matuska 
924fefe1b7SMartin Matuska 	bucket = highbit64(dds.dds_ref_blocks) - 1;
934fefe1b7SMartin Matuska 	ASSERT3U(bucket, >=, 0);
944fefe1b7SMartin Matuska 
954fefe1b7SMartin Matuska 	ddh = &ddt->ddt_histogram[dde->dde_type][dde->dde_class];
964fefe1b7SMartin Matuska 
974fefe1b7SMartin Matuska 	ddt_stat_add(&ddh->ddh_stat[bucket], &dds, neg);
984fefe1b7SMartin Matuska }
994fefe1b7SMartin Matuska 
1004fefe1b7SMartin Matuska void
1014fefe1b7SMartin Matuska ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src)
1024fefe1b7SMartin Matuska {
1034fefe1b7SMartin Matuska 	for (int h = 0; h < 64; h++)
1044fefe1b7SMartin Matuska 		ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h], 0);
1054fefe1b7SMartin Matuska }
1064fefe1b7SMartin Matuska 
1074fefe1b7SMartin Matuska void
1084fefe1b7SMartin Matuska ddt_histogram_stat(ddt_stat_t *dds, const ddt_histogram_t *ddh)
1094fefe1b7SMartin Matuska {
1104fefe1b7SMartin Matuska 	memset(dds, 0, sizeof (*dds));
1114fefe1b7SMartin Matuska 
1124fefe1b7SMartin Matuska 	for (int h = 0; h < 64; h++)
1134fefe1b7SMartin Matuska 		ddt_stat_add(dds, &ddh->ddh_stat[h], 0);
1144fefe1b7SMartin Matuska }
1154fefe1b7SMartin Matuska 
1164fefe1b7SMartin Matuska boolean_t
1174fefe1b7SMartin Matuska ddt_histogram_empty(const ddt_histogram_t *ddh)
1184fefe1b7SMartin Matuska {
1194fefe1b7SMartin Matuska 	const uint64_t *s = (const uint64_t *)ddh;
1204fefe1b7SMartin Matuska 	const uint64_t *s_end = (const uint64_t *)(ddh + 1);
1214fefe1b7SMartin Matuska 
1224fefe1b7SMartin Matuska 	while (s < s_end)
1234fefe1b7SMartin Matuska 		if (*s++ != 0)
1244fefe1b7SMartin Matuska 			return (B_FALSE);
1254fefe1b7SMartin Matuska 
1264fefe1b7SMartin Matuska 	return (B_TRUE);
1274fefe1b7SMartin Matuska }
1284fefe1b7SMartin Matuska 
1294fefe1b7SMartin Matuska void
1304fefe1b7SMartin Matuska ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total)
1314fefe1b7SMartin Matuska {
132*ce4dcb97SMartin Matuska 	memset(ddo_total, 0, sizeof (*ddo_total));
133*ce4dcb97SMartin Matuska 
1344fefe1b7SMartin Matuska 	for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
1354fefe1b7SMartin Matuska 		ddt_t *ddt = spa->spa_ddt[c];
1364fefe1b7SMartin Matuska 		if (!ddt)
1374fefe1b7SMartin Matuska 			continue;
1384fefe1b7SMartin Matuska 
1394fefe1b7SMartin Matuska 		for (ddt_type_t type = 0; type < DDT_TYPES; type++) {
1404fefe1b7SMartin Matuska 			for (ddt_class_t class = 0; class < DDT_CLASSES;
1414fefe1b7SMartin Matuska 			    class++) {
142*ce4dcb97SMartin Matuska 				dmu_object_info_t doi;
143*ce4dcb97SMartin Matuska 				uint64_t cnt;
144*ce4dcb97SMartin Matuska 				int err;
145*ce4dcb97SMartin Matuska 
146*ce4dcb97SMartin Matuska 				/*
147*ce4dcb97SMartin Matuska 				 * These stats were originally calculated
148*ce4dcb97SMartin Matuska 				 * during ddt_object_load().
149*ce4dcb97SMartin Matuska 				 */
150*ce4dcb97SMartin Matuska 
151*ce4dcb97SMartin Matuska 				err = ddt_object_info(ddt, type, class, &doi);
152*ce4dcb97SMartin Matuska 				if (err != 0)
153*ce4dcb97SMartin Matuska 					continue;
154*ce4dcb97SMartin Matuska 
155*ce4dcb97SMartin Matuska 				err = ddt_object_count(ddt, type, class, &cnt);
156*ce4dcb97SMartin Matuska 				if (err != 0)
157*ce4dcb97SMartin Matuska 					continue;
158*ce4dcb97SMartin Matuska 
1594fefe1b7SMartin Matuska 				ddt_object_t *ddo =
1604fefe1b7SMartin Matuska 				    &ddt->ddt_object_stats[type][class];
161*ce4dcb97SMartin Matuska 
162*ce4dcb97SMartin Matuska 				ddo->ddo_count = cnt;
163*ce4dcb97SMartin Matuska 				ddo->ddo_dspace =
164*ce4dcb97SMartin Matuska 				    doi.doi_physical_blocks_512 << 9;
165*ce4dcb97SMartin Matuska 				ddo->ddo_mspace = doi.doi_fill_count *
166*ce4dcb97SMartin Matuska 				    doi.doi_data_block_size;
167*ce4dcb97SMartin Matuska 
1684fefe1b7SMartin Matuska 				ddo_total->ddo_count += ddo->ddo_count;
1694fefe1b7SMartin Matuska 				ddo_total->ddo_dspace += ddo->ddo_dspace;
1704fefe1b7SMartin Matuska 				ddo_total->ddo_mspace += ddo->ddo_mspace;
1714fefe1b7SMartin Matuska 			}
1724fefe1b7SMartin Matuska 		}
1734fefe1b7SMartin Matuska 	}
1744fefe1b7SMartin Matuska 
175*ce4dcb97SMartin Matuska 	/*
176*ce4dcb97SMartin Matuska 	 * This returns raw counts (not averages). One of the consumers,
177*ce4dcb97SMartin Matuska 	 * print_dedup_stats(), historically has expected raw counts.
178*ce4dcb97SMartin Matuska 	 */
179*ce4dcb97SMartin Matuska 
180*ce4dcb97SMartin Matuska 	spa->spa_dedup_dsize = ddo_total->ddo_dspace;
1814fefe1b7SMartin Matuska }
182*ce4dcb97SMartin Matuska 
183*ce4dcb97SMartin Matuska uint64_t
184*ce4dcb97SMartin Matuska ddt_get_ddt_dsize(spa_t *spa)
185*ce4dcb97SMartin Matuska {
186*ce4dcb97SMartin Matuska 	ddt_object_t ddo_total;
187*ce4dcb97SMartin Matuska 
188*ce4dcb97SMartin Matuska 	/* recalculate after each txg sync */
189*ce4dcb97SMartin Matuska 	if (spa->spa_dedup_dsize == ~0ULL)
190*ce4dcb97SMartin Matuska 		ddt_get_dedup_object_stats(spa, &ddo_total);
191*ce4dcb97SMartin Matuska 
192*ce4dcb97SMartin Matuska 	return (spa->spa_dedup_dsize);
1934fefe1b7SMartin Matuska }
1944fefe1b7SMartin Matuska 
1954fefe1b7SMartin Matuska void
1964fefe1b7SMartin Matuska ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh)
1974fefe1b7SMartin Matuska {
1984fefe1b7SMartin Matuska 	for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
1994fefe1b7SMartin Matuska 		ddt_t *ddt = spa->spa_ddt[c];
2004fefe1b7SMartin Matuska 		if (!ddt)
2014fefe1b7SMartin Matuska 			continue;
2024fefe1b7SMartin Matuska 
2034fefe1b7SMartin Matuska 		for (ddt_type_t type = 0; type < DDT_TYPES; type++) {
2044fefe1b7SMartin Matuska 			for (ddt_class_t class = 0; class < DDT_CLASSES;
2054fefe1b7SMartin Matuska 			    class++) {
2064fefe1b7SMartin Matuska 				ddt_histogram_add(ddh,
2074fefe1b7SMartin Matuska 				    &ddt->ddt_histogram_cache[type][class]);
2084fefe1b7SMartin Matuska 			}
2094fefe1b7SMartin Matuska 		}
2104fefe1b7SMartin Matuska 	}
2114fefe1b7SMartin Matuska }
2124fefe1b7SMartin Matuska 
2134fefe1b7SMartin Matuska void
2144fefe1b7SMartin Matuska ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total)
2154fefe1b7SMartin Matuska {
2164fefe1b7SMartin Matuska 	ddt_histogram_t *ddh_total;
2174fefe1b7SMartin Matuska 
2184fefe1b7SMartin Matuska 	ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
2194fefe1b7SMartin Matuska 	ddt_get_dedup_histogram(spa, ddh_total);
2204fefe1b7SMartin Matuska 	ddt_histogram_stat(dds_total, ddh_total);
2214fefe1b7SMartin Matuska 	kmem_free(ddh_total, sizeof (ddt_histogram_t));
2224fefe1b7SMartin Matuska }
2234fefe1b7SMartin Matuska 
2244fefe1b7SMartin Matuska uint64_t
2254fefe1b7SMartin Matuska ddt_get_dedup_dspace(spa_t *spa)
2264fefe1b7SMartin Matuska {
2274fefe1b7SMartin Matuska 	ddt_stat_t dds_total;
2284fefe1b7SMartin Matuska 
2294fefe1b7SMartin Matuska 	if (spa->spa_dedup_dspace != ~0ULL)
2304fefe1b7SMartin Matuska 		return (spa->spa_dedup_dspace);
2314fefe1b7SMartin Matuska 
2324fefe1b7SMartin Matuska 	memset(&dds_total, 0, sizeof (ddt_stat_t));
2334fefe1b7SMartin Matuska 
2344fefe1b7SMartin Matuska 	/* Calculate and cache the stats */
2354fefe1b7SMartin Matuska 	ddt_get_dedup_stats(spa, &dds_total);
2364fefe1b7SMartin Matuska 	spa->spa_dedup_dspace = dds_total.dds_ref_dsize - dds_total.dds_dsize;
2374fefe1b7SMartin Matuska 	return (spa->spa_dedup_dspace);
2384fefe1b7SMartin Matuska }
2394fefe1b7SMartin Matuska 
2404fefe1b7SMartin Matuska uint64_t
2414fefe1b7SMartin Matuska ddt_get_pool_dedup_ratio(spa_t *spa)
2424fefe1b7SMartin Matuska {
2434fefe1b7SMartin Matuska 	ddt_stat_t dds_total = { 0 };
2444fefe1b7SMartin Matuska 
2454fefe1b7SMartin Matuska 	ddt_get_dedup_stats(spa, &dds_total);
2464fefe1b7SMartin Matuska 	if (dds_total.dds_dsize == 0)
2474fefe1b7SMartin Matuska 		return (100);
2484fefe1b7SMartin Matuska 
2494fefe1b7SMartin Matuska 	return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize);
2504fefe1b7SMartin Matuska }
251*ce4dcb97SMartin Matuska 
252*ce4dcb97SMartin Matuska int
253*ce4dcb97SMartin Matuska ddt_get_pool_dedup_cached(spa_t *spa, uint64_t *psize)
254*ce4dcb97SMartin Matuska {
255*ce4dcb97SMartin Matuska 	uint64_t l1sz, l1tot, l2sz, l2tot;
256*ce4dcb97SMartin Matuska 	int err = 0;
257*ce4dcb97SMartin Matuska 
258*ce4dcb97SMartin Matuska 	l1tot = l2tot = 0;
259*ce4dcb97SMartin Matuska 	*psize = 0;
260*ce4dcb97SMartin Matuska 	for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
261*ce4dcb97SMartin Matuska 		ddt_t *ddt = spa->spa_ddt[c];
262*ce4dcb97SMartin Matuska 		if (ddt == NULL)
263*ce4dcb97SMartin Matuska 			continue;
264*ce4dcb97SMartin Matuska 		for (ddt_type_t type = 0; type < DDT_TYPES; type++) {
265*ce4dcb97SMartin Matuska 			for (ddt_class_t class = 0; class < DDT_CLASSES;
266*ce4dcb97SMartin Matuska 			    class++) {
267*ce4dcb97SMartin Matuska 				err = dmu_object_cached_size(ddt->ddt_os,
268*ce4dcb97SMartin Matuska 				    ddt->ddt_object[type][class], &l1sz, &l2sz);
269*ce4dcb97SMartin Matuska 				if (err != 0)
270*ce4dcb97SMartin Matuska 					return (err);
271*ce4dcb97SMartin Matuska 				l1tot += l1sz;
272*ce4dcb97SMartin Matuska 				l2tot += l2sz;
273*ce4dcb97SMartin Matuska 			}
274*ce4dcb97SMartin Matuska 		}
275*ce4dcb97SMartin Matuska 	}
276*ce4dcb97SMartin Matuska 
277*ce4dcb97SMartin Matuska 	*psize = l1tot + l2tot;
278*ce4dcb97SMartin Matuska 	return (err);
279*ce4dcb97SMartin Matuska }
280