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