Path: blob/main/sys/contrib/openzfs/module/zfs/ddt_stats.c
48383 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright (c) 2012, 2016 by Delphix. All rights reserved.25* Copyright (c) 2022 by Pawel Jakub Dawidek26* Copyright (c) 2023, Klara Inc.27*/2829#include <sys/zfs_context.h>30#include <sys/spa.h>31#include <sys/spa_impl.h>32#include <sys/ddt.h>33#include <sys/ddt_impl.h>3435static void36ddt_stat_generate(ddt_t *ddt, const ddt_lightweight_entry_t *ddlwe,37ddt_stat_t *dds)38{39spa_t *spa = ddt->ddt_spa;40uint64_t lsize = DDK_GET_LSIZE(&ddlwe->ddlwe_key);41uint64_t psize = DDK_GET_PSIZE(&ddlwe->ddlwe_key);4243memset(dds, 0, sizeof (*dds));4445for (int p = 0; p < DDT_NPHYS(ddt); p++) {46const ddt_univ_phys_t *ddp = &ddlwe->ddlwe_phys;47ddt_phys_variant_t v = DDT_PHYS_VARIANT(ddt, p);4849if (ddt_phys_birth(ddp, v) == 0)50continue;5152int ndvas = ddt_phys_dva_count(ddp, v,53DDK_GET_CRYPT(&ddlwe->ddlwe_key));54const dva_t *dvas = (ddt->ddt_flags & DDT_FLAG_FLAT) ?55ddp->ddp_flat.ddp_dva : ddp->ddp_trad[p].ddp_dva;5657uint64_t dsize = 0;58for (int d = 0; d < ndvas; d++)59dsize += dva_get_dsize_sync(spa, &dvas[d]);6061uint64_t refcnt = ddt_phys_refcnt(ddp, v);6263dds->dds_blocks += 1;64dds->dds_lsize += lsize;65dds->dds_psize += psize;66dds->dds_dsize += dsize;6768dds->dds_ref_blocks += refcnt;69dds->dds_ref_lsize += lsize * refcnt;70dds->dds_ref_psize += psize * refcnt;71dds->dds_ref_dsize += dsize * refcnt;72}73}7475static void76ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src)77{78dst->dds_blocks += src->dds_blocks;79dst->dds_lsize += src->dds_lsize;80dst->dds_psize += src->dds_psize;81dst->dds_dsize += src->dds_dsize;82dst->dds_ref_blocks += src->dds_ref_blocks;83dst->dds_ref_lsize += src->dds_ref_lsize;84dst->dds_ref_psize += src->dds_ref_psize;85dst->dds_ref_dsize += src->dds_ref_dsize;86}8788static void89ddt_stat_sub(ddt_stat_t *dst, const ddt_stat_t *src)90{91/* This caught more during development than you might expect... */92ASSERT3U(dst->dds_blocks, >=, src->dds_blocks);93ASSERT3U(dst->dds_lsize, >=, src->dds_lsize);94ASSERT3U(dst->dds_psize, >=, src->dds_psize);95ASSERT3U(dst->dds_dsize, >=, src->dds_dsize);96ASSERT3U(dst->dds_ref_blocks, >=, src->dds_ref_blocks);97ASSERT3U(dst->dds_ref_lsize, >=, src->dds_ref_lsize);98ASSERT3U(dst->dds_ref_psize, >=, src->dds_ref_psize);99ASSERT3U(dst->dds_ref_dsize, >=, src->dds_ref_dsize);100101dst->dds_blocks -= src->dds_blocks;102dst->dds_lsize -= src->dds_lsize;103dst->dds_psize -= src->dds_psize;104dst->dds_dsize -= src->dds_dsize;105dst->dds_ref_blocks -= src->dds_ref_blocks;106dst->dds_ref_lsize -= src->dds_ref_lsize;107dst->dds_ref_psize -= src->dds_ref_psize;108dst->dds_ref_dsize -= src->dds_ref_dsize;109}110111void112ddt_histogram_add_entry(ddt_t *ddt, ddt_histogram_t *ddh,113const ddt_lightweight_entry_t *ddlwe)114{115ddt_stat_t dds;116int bucket;117118ddt_stat_generate(ddt, ddlwe, &dds);119120bucket = highbit64(dds.dds_ref_blocks) - 1;121if (bucket < 0)122return;123124ddt_stat_add(&ddh->ddh_stat[bucket], &dds);125}126127void128ddt_histogram_sub_entry(ddt_t *ddt, ddt_histogram_t *ddh,129const ddt_lightweight_entry_t *ddlwe)130{131ddt_stat_t dds;132int bucket;133134ddt_stat_generate(ddt, ddlwe, &dds);135136bucket = highbit64(dds.dds_ref_blocks) - 1;137if (bucket < 0)138return;139140ddt_stat_sub(&ddh->ddh_stat[bucket], &dds);141}142143void144ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src)145{146for (int h = 0; h < 64; h++)147ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h]);148}149150void151ddt_histogram_total(ddt_stat_t *dds, const ddt_histogram_t *ddh)152{153memset(dds, 0, sizeof (*dds));154155for (int h = 0; h < 64; h++)156ddt_stat_add(dds, &ddh->ddh_stat[h]);157}158159boolean_t160ddt_histogram_empty(const ddt_histogram_t *ddh)161{162for (int h = 0; h < 64; h++) {163const ddt_stat_t *dds = &ddh->ddh_stat[h];164165if (dds->dds_blocks == 0 &&166dds->dds_lsize == 0 &&167dds->dds_psize == 0 &&168dds->dds_dsize == 0 &&169dds->dds_ref_blocks == 0 &&170dds->dds_ref_lsize == 0 &&171dds->dds_ref_psize == 0 &&172dds->dds_ref_dsize == 0)173continue;174175return (B_FALSE);176}177178return (B_TRUE);179}180181void182ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total)183{184memset(ddo_total, 0, sizeof (*ddo_total));185186for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {187ddt_t *ddt = spa->spa_ddt[c];188if (!ddt)189continue;190191for (ddt_type_t type = 0; type < DDT_TYPES; type++) {192for (ddt_class_t class = 0; class < DDT_CLASSES;193class++) {194dmu_object_info_t doi;195uint64_t cnt;196int err;197198/*199* These stats were originally calculated200* during ddt_object_load().201*/202203err = ddt_object_info(ddt, type, class, &doi);204if (err != 0)205continue;206207err = ddt_object_count(ddt, type, class, &cnt);208if (err != 0)209continue;210211ddt_object_t *ddo =212&ddt->ddt_object_stats[type][class];213214ddo->ddo_count = cnt;215ddo->ddo_dspace =216doi.doi_physical_blocks_512 << 9;217ddo->ddo_mspace = doi.doi_fill_count *218doi.doi_data_block_size;219220ddo_total->ddo_count += ddo->ddo_count;221ddo_total->ddo_dspace += ddo->ddo_dspace;222ddo_total->ddo_mspace += ddo->ddo_mspace;223}224}225226ddt_object_t *ddo = &ddt->ddt_log_stats;227ddo_total->ddo_count += ddo->ddo_count;228ddo_total->ddo_dspace += ddo->ddo_dspace;229ddo_total->ddo_mspace += ddo->ddo_mspace;230}231232/*233* This returns raw counts (not averages). One of the consumers,234* print_dedup_stats(), historically has expected raw counts.235*/236237spa->spa_dedup_dsize = ddo_total->ddo_dspace;238}239240uint64_t241ddt_get_ddt_dsize(spa_t *spa)242{243ddt_object_t ddo_total;244245/* recalculate after each txg sync */246if (spa->spa_dedup_dsize == ~0ULL)247ddt_get_dedup_object_stats(spa, &ddo_total);248249return (spa->spa_dedup_dsize);250}251252void253ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh)254{255for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {256ddt_t *ddt = spa->spa_ddt[c];257if (!ddt)258continue;259260for (ddt_type_t type = 0; type < DDT_TYPES; type++) {261for (ddt_class_t class = 0; class < DDT_CLASSES;262class++) {263ddt_histogram_add(ddh,264&ddt->ddt_histogram_cache[type][class]);265}266}267268ddt_histogram_add(ddh, &ddt->ddt_log_histogram);269}270}271272void273ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total)274{275ddt_histogram_t *ddh_total;276277ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);278ddt_get_dedup_histogram(spa, ddh_total);279ddt_histogram_total(dds_total, ddh_total);280kmem_free(ddh_total, sizeof (ddt_histogram_t));281}282283uint64_t284ddt_get_dedup_dspace(spa_t *spa)285{286ddt_stat_t dds_total;287288if (spa->spa_dedup_dspace != ~0ULL)289return (spa->spa_dedup_dspace);290291memset(&dds_total, 0, sizeof (ddt_stat_t));292293/* Calculate and cache the stats */294ddt_get_dedup_stats(spa, &dds_total);295spa->spa_dedup_dspace = dds_total.dds_ref_dsize - dds_total.dds_dsize;296return (spa->spa_dedup_dspace);297}298299uint64_t300ddt_get_pool_dedup_ratio(spa_t *spa)301{302ddt_stat_t dds_total = { 0 };303304ddt_get_dedup_stats(spa, &dds_total);305if (dds_total.dds_dsize == 0)306return (100);307308return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize);309}310311int312ddt_get_pool_dedup_cached(spa_t *spa, uint64_t *psize)313{314uint64_t l1sz, l1tot, l2sz, l2tot;315int err = 0;316317l1tot = l2tot = 0;318*psize = 0;319for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {320ddt_t *ddt = spa->spa_ddt[c];321if (ddt == NULL)322continue;323for (ddt_type_t type = 0; type < DDT_TYPES; type++) {324for (ddt_class_t class = 0; class < DDT_CLASSES;325class++) {326err = dmu_object_cached_size(ddt->ddt_os,327ddt->ddt_object[type][class], &l1sz, &l2sz);328if (err != 0)329return (err);330l1tot += l1sz;331l2tot += l2sz;332}333}334}335336*psize = l1tot + l2tot;337return (err);338}339340341