1*4fefe1b7SMartin Matuska /* 2*4fefe1b7SMartin Matuska * CDDL HEADER START 3*4fefe1b7SMartin Matuska * 4*4fefe1b7SMartin Matuska * The contents of this file are subject to the terms of the 5*4fefe1b7SMartin Matuska * Common Development and Distribution License (the "License"). 6*4fefe1b7SMartin Matuska * You may not use this file except in compliance with the License. 7*4fefe1b7SMartin Matuska * 8*4fefe1b7SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4fefe1b7SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10*4fefe1b7SMartin Matuska * See the License for the specific language governing permissions 11*4fefe1b7SMartin Matuska * and limitations under the License. 12*4fefe1b7SMartin Matuska * 13*4fefe1b7SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 14*4fefe1b7SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4fefe1b7SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 16*4fefe1b7SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 17*4fefe1b7SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 18*4fefe1b7SMartin Matuska * 19*4fefe1b7SMartin Matuska * CDDL HEADER END 20*4fefe1b7SMartin Matuska */ 21*4fefe1b7SMartin Matuska 22*4fefe1b7SMartin Matuska /* 23*4fefe1b7SMartin Matuska * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24*4fefe1b7SMartin Matuska * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 25*4fefe1b7SMartin Matuska * Copyright (c) 2022 by Pawel Jakub Dawidek 26*4fefe1b7SMartin Matuska * Copyright (c) 2023, Klara Inc. 27*4fefe1b7SMartin Matuska */ 28*4fefe1b7SMartin Matuska 29*4fefe1b7SMartin Matuska #include <sys/zfs_context.h> 30*4fefe1b7SMartin Matuska #include <sys/spa.h> 31*4fefe1b7SMartin Matuska #include <sys/spa_impl.h> 32*4fefe1b7SMartin Matuska #include <sys/ddt.h> 33*4fefe1b7SMartin Matuska #include <sys/ddt_impl.h> 34*4fefe1b7SMartin Matuska 35*4fefe1b7SMartin Matuska static void 36*4fefe1b7SMartin Matuska ddt_stat_generate(ddt_t *ddt, ddt_entry_t *dde, ddt_stat_t *dds) 37*4fefe1b7SMartin Matuska { 38*4fefe1b7SMartin Matuska spa_t *spa = ddt->ddt_spa; 39*4fefe1b7SMartin Matuska ddt_phys_t *ddp = dde->dde_phys; 40*4fefe1b7SMartin Matuska ddt_key_t *ddk = &dde->dde_key; 41*4fefe1b7SMartin Matuska uint64_t lsize = DDK_GET_LSIZE(ddk); 42*4fefe1b7SMartin Matuska uint64_t psize = DDK_GET_PSIZE(ddk); 43*4fefe1b7SMartin Matuska 44*4fefe1b7SMartin Matuska memset(dds, 0, sizeof (*dds)); 45*4fefe1b7SMartin Matuska 46*4fefe1b7SMartin Matuska for (int p = 0; p < DDT_PHYS_TYPES; p++, ddp++) { 47*4fefe1b7SMartin Matuska uint64_t dsize = 0; 48*4fefe1b7SMartin Matuska uint64_t refcnt = ddp->ddp_refcnt; 49*4fefe1b7SMartin Matuska 50*4fefe1b7SMartin Matuska if (ddp->ddp_phys_birth == 0) 51*4fefe1b7SMartin Matuska continue; 52*4fefe1b7SMartin Matuska 53*4fefe1b7SMartin Matuska int ndvas = DDK_GET_CRYPT(&dde->dde_key) ? 54*4fefe1b7SMartin Matuska SPA_DVAS_PER_BP - 1 : SPA_DVAS_PER_BP; 55*4fefe1b7SMartin Matuska for (int d = 0; d < ndvas; d++) 56*4fefe1b7SMartin Matuska dsize += dva_get_dsize_sync(spa, &ddp->ddp_dva[d]); 57*4fefe1b7SMartin Matuska 58*4fefe1b7SMartin Matuska dds->dds_blocks += 1; 59*4fefe1b7SMartin Matuska dds->dds_lsize += lsize; 60*4fefe1b7SMartin Matuska dds->dds_psize += psize; 61*4fefe1b7SMartin Matuska dds->dds_dsize += dsize; 62*4fefe1b7SMartin Matuska 63*4fefe1b7SMartin Matuska dds->dds_ref_blocks += refcnt; 64*4fefe1b7SMartin Matuska dds->dds_ref_lsize += lsize * refcnt; 65*4fefe1b7SMartin Matuska dds->dds_ref_psize += psize * refcnt; 66*4fefe1b7SMartin Matuska dds->dds_ref_dsize += dsize * refcnt; 67*4fefe1b7SMartin Matuska } 68*4fefe1b7SMartin Matuska } 69*4fefe1b7SMartin Matuska 70*4fefe1b7SMartin Matuska void 71*4fefe1b7SMartin Matuska ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src, uint64_t neg) 72*4fefe1b7SMartin Matuska { 73*4fefe1b7SMartin Matuska const uint64_t *s = (const uint64_t *)src; 74*4fefe1b7SMartin Matuska uint64_t *d = (uint64_t *)dst; 75*4fefe1b7SMartin Matuska uint64_t *d_end = (uint64_t *)(dst + 1); 76*4fefe1b7SMartin Matuska 77*4fefe1b7SMartin Matuska ASSERT(neg == 0 || neg == -1ULL); /* add or subtract */ 78*4fefe1b7SMartin Matuska 79*4fefe1b7SMartin Matuska for (int i = 0; i < d_end - d; i++) 80*4fefe1b7SMartin Matuska d[i] += (s[i] ^ neg) - neg; 81*4fefe1b7SMartin Matuska } 82*4fefe1b7SMartin Matuska 83*4fefe1b7SMartin Matuska void 84*4fefe1b7SMartin Matuska ddt_stat_update(ddt_t *ddt, ddt_entry_t *dde, uint64_t neg) 85*4fefe1b7SMartin Matuska { 86*4fefe1b7SMartin Matuska ddt_stat_t dds; 87*4fefe1b7SMartin Matuska ddt_histogram_t *ddh; 88*4fefe1b7SMartin Matuska int bucket; 89*4fefe1b7SMartin Matuska 90*4fefe1b7SMartin Matuska ddt_stat_generate(ddt, dde, &dds); 91*4fefe1b7SMartin Matuska 92*4fefe1b7SMartin Matuska bucket = highbit64(dds.dds_ref_blocks) - 1; 93*4fefe1b7SMartin Matuska ASSERT3U(bucket, >=, 0); 94*4fefe1b7SMartin Matuska 95*4fefe1b7SMartin Matuska ddh = &ddt->ddt_histogram[dde->dde_type][dde->dde_class]; 96*4fefe1b7SMartin Matuska 97*4fefe1b7SMartin Matuska ddt_stat_add(&ddh->ddh_stat[bucket], &dds, neg); 98*4fefe1b7SMartin Matuska } 99*4fefe1b7SMartin Matuska 100*4fefe1b7SMartin Matuska void 101*4fefe1b7SMartin Matuska ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src) 102*4fefe1b7SMartin Matuska { 103*4fefe1b7SMartin Matuska for (int h = 0; h < 64; h++) 104*4fefe1b7SMartin Matuska ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h], 0); 105*4fefe1b7SMartin Matuska } 106*4fefe1b7SMartin Matuska 107*4fefe1b7SMartin Matuska void 108*4fefe1b7SMartin Matuska ddt_histogram_stat(ddt_stat_t *dds, const ddt_histogram_t *ddh) 109*4fefe1b7SMartin Matuska { 110*4fefe1b7SMartin Matuska memset(dds, 0, sizeof (*dds)); 111*4fefe1b7SMartin Matuska 112*4fefe1b7SMartin Matuska for (int h = 0; h < 64; h++) 113*4fefe1b7SMartin Matuska ddt_stat_add(dds, &ddh->ddh_stat[h], 0); 114*4fefe1b7SMartin Matuska } 115*4fefe1b7SMartin Matuska 116*4fefe1b7SMartin Matuska boolean_t 117*4fefe1b7SMartin Matuska ddt_histogram_empty(const ddt_histogram_t *ddh) 118*4fefe1b7SMartin Matuska { 119*4fefe1b7SMartin Matuska const uint64_t *s = (const uint64_t *)ddh; 120*4fefe1b7SMartin Matuska const uint64_t *s_end = (const uint64_t *)(ddh + 1); 121*4fefe1b7SMartin Matuska 122*4fefe1b7SMartin Matuska while (s < s_end) 123*4fefe1b7SMartin Matuska if (*s++ != 0) 124*4fefe1b7SMartin Matuska return (B_FALSE); 125*4fefe1b7SMartin Matuska 126*4fefe1b7SMartin Matuska return (B_TRUE); 127*4fefe1b7SMartin Matuska } 128*4fefe1b7SMartin Matuska 129*4fefe1b7SMartin Matuska void 130*4fefe1b7SMartin Matuska ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total) 131*4fefe1b7SMartin Matuska { 132*4fefe1b7SMartin Matuska /* Sum the statistics we cached in ddt_object_sync(). */ 133*4fefe1b7SMartin Matuska for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 134*4fefe1b7SMartin Matuska ddt_t *ddt = spa->spa_ddt[c]; 135*4fefe1b7SMartin Matuska if (!ddt) 136*4fefe1b7SMartin Matuska continue; 137*4fefe1b7SMartin Matuska 138*4fefe1b7SMartin Matuska for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 139*4fefe1b7SMartin Matuska for (ddt_class_t class = 0; class < DDT_CLASSES; 140*4fefe1b7SMartin Matuska class++) { 141*4fefe1b7SMartin Matuska ddt_object_t *ddo = 142*4fefe1b7SMartin Matuska &ddt->ddt_object_stats[type][class]; 143*4fefe1b7SMartin Matuska ddo_total->ddo_count += ddo->ddo_count; 144*4fefe1b7SMartin Matuska ddo_total->ddo_dspace += ddo->ddo_dspace; 145*4fefe1b7SMartin Matuska ddo_total->ddo_mspace += ddo->ddo_mspace; 146*4fefe1b7SMartin Matuska } 147*4fefe1b7SMartin Matuska } 148*4fefe1b7SMartin Matuska } 149*4fefe1b7SMartin Matuska 150*4fefe1b7SMartin Matuska /* ... and compute the averages. */ 151*4fefe1b7SMartin Matuska if (ddo_total->ddo_count != 0) { 152*4fefe1b7SMartin Matuska ddo_total->ddo_dspace /= ddo_total->ddo_count; 153*4fefe1b7SMartin Matuska ddo_total->ddo_mspace /= ddo_total->ddo_count; 154*4fefe1b7SMartin Matuska } 155*4fefe1b7SMartin Matuska } 156*4fefe1b7SMartin Matuska 157*4fefe1b7SMartin Matuska void 158*4fefe1b7SMartin Matuska ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh) 159*4fefe1b7SMartin Matuska { 160*4fefe1b7SMartin Matuska for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) { 161*4fefe1b7SMartin Matuska ddt_t *ddt = spa->spa_ddt[c]; 162*4fefe1b7SMartin Matuska if (!ddt) 163*4fefe1b7SMartin Matuska continue; 164*4fefe1b7SMartin Matuska 165*4fefe1b7SMartin Matuska for (ddt_type_t type = 0; type < DDT_TYPES; type++) { 166*4fefe1b7SMartin Matuska for (ddt_class_t class = 0; class < DDT_CLASSES; 167*4fefe1b7SMartin Matuska class++) { 168*4fefe1b7SMartin Matuska ddt_histogram_add(ddh, 169*4fefe1b7SMartin Matuska &ddt->ddt_histogram_cache[type][class]); 170*4fefe1b7SMartin Matuska } 171*4fefe1b7SMartin Matuska } 172*4fefe1b7SMartin Matuska } 173*4fefe1b7SMartin Matuska } 174*4fefe1b7SMartin Matuska 175*4fefe1b7SMartin Matuska void 176*4fefe1b7SMartin Matuska ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total) 177*4fefe1b7SMartin Matuska { 178*4fefe1b7SMartin Matuska ddt_histogram_t *ddh_total; 179*4fefe1b7SMartin Matuska 180*4fefe1b7SMartin Matuska ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP); 181*4fefe1b7SMartin Matuska ddt_get_dedup_histogram(spa, ddh_total); 182*4fefe1b7SMartin Matuska ddt_histogram_stat(dds_total, ddh_total); 183*4fefe1b7SMartin Matuska kmem_free(ddh_total, sizeof (ddt_histogram_t)); 184*4fefe1b7SMartin Matuska } 185*4fefe1b7SMartin Matuska 186*4fefe1b7SMartin Matuska uint64_t 187*4fefe1b7SMartin Matuska ddt_get_dedup_dspace(spa_t *spa) 188*4fefe1b7SMartin Matuska { 189*4fefe1b7SMartin Matuska ddt_stat_t dds_total; 190*4fefe1b7SMartin Matuska 191*4fefe1b7SMartin Matuska if (spa->spa_dedup_dspace != ~0ULL) 192*4fefe1b7SMartin Matuska return (spa->spa_dedup_dspace); 193*4fefe1b7SMartin Matuska 194*4fefe1b7SMartin Matuska memset(&dds_total, 0, sizeof (ddt_stat_t)); 195*4fefe1b7SMartin Matuska 196*4fefe1b7SMartin Matuska /* Calculate and cache the stats */ 197*4fefe1b7SMartin Matuska ddt_get_dedup_stats(spa, &dds_total); 198*4fefe1b7SMartin Matuska spa->spa_dedup_dspace = dds_total.dds_ref_dsize - dds_total.dds_dsize; 199*4fefe1b7SMartin Matuska return (spa->spa_dedup_dspace); 200*4fefe1b7SMartin Matuska } 201*4fefe1b7SMartin Matuska 202*4fefe1b7SMartin Matuska uint64_t 203*4fefe1b7SMartin Matuska ddt_get_pool_dedup_ratio(spa_t *spa) 204*4fefe1b7SMartin Matuska { 205*4fefe1b7SMartin Matuska ddt_stat_t dds_total = { 0 }; 206*4fefe1b7SMartin Matuska 207*4fefe1b7SMartin Matuska ddt_get_dedup_stats(spa, &dds_total); 208*4fefe1b7SMartin Matuska if (dds_total.dds_dsize == 0) 209*4fefe1b7SMartin Matuska return (100); 210*4fefe1b7SMartin Matuska 211*4fefe1b7SMartin Matuska return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize); 212*4fefe1b7SMartin Matuska } 213