X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fdmu_zfetch.c;h=1763bae5184a6c40f5e72b8da9d9bc52d1998705;hb=refs%2Fheads%2Frertzinger%2Ffeature-zpool-get--p;hp=4d79fe98e17ee6125b9b4522e7ac95c3fbca18e2;hpb=172bb4bd5e4afef721dd4d2972d8680d983f144b;p=zfs.git diff --git a/module/zfs/dmu_zfetch.c b/module/zfs/dmu_zfetch.c index 4d79fe9..1763bae 100644 --- a/module/zfs/dmu_zfetch.c +++ b/module/zfs/dmu_zfetch.c @@ -19,18 +19,17 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include #include #include #include +#include /* * I'm against tune-ables, but these should probably exist as tweakable globals @@ -40,13 +39,13 @@ int zfs_prefetch_disable = 0; /* max # of streams per zfetch */ -uint32_t zfetch_max_streams = 8; +unsigned int zfetch_max_streams = 8; /* min time before stream reclaim */ -uint32_t zfetch_min_sec_reap = 2; +unsigned int zfetch_min_sec_reap = 2; /* max number of blocks to fetch at a time */ -uint32_t zfetch_block_cap = 256; +unsigned int zfetch_block_cap = 256; /* number of bytes in a array_read at which we stop prefetching (1Mb) */ -uint64_t zfetch_array_rd_sz = 1024 * 1024; +unsigned long zfetch_array_rd_sz = 1024 * 1024; /* forward decls for static routines */ static int dmu_zfetch_colinear(zfetch_t *, zstream_t *); @@ -59,6 +58,41 @@ static zstream_t *dmu_zfetch_stream_reclaim(zfetch_t *); static void dmu_zfetch_stream_remove(zfetch_t *, zstream_t *); static int dmu_zfetch_streams_equal(zstream_t *, zstream_t *); +typedef struct zfetch_stats { + kstat_named_t zfetchstat_hits; + kstat_named_t zfetchstat_misses; + kstat_named_t zfetchstat_colinear_hits; + kstat_named_t zfetchstat_colinear_misses; + kstat_named_t zfetchstat_stride_hits; + kstat_named_t zfetchstat_stride_misses; + kstat_named_t zfetchstat_reclaim_successes; + kstat_named_t zfetchstat_reclaim_failures; + kstat_named_t zfetchstat_stream_resets; + kstat_named_t zfetchstat_stream_noresets; + kstat_named_t zfetchstat_bogus_streams; +} zfetch_stats_t; + +static zfetch_stats_t zfetch_stats = { + { "hits", KSTAT_DATA_UINT64 }, + { "misses", KSTAT_DATA_UINT64 }, + { "colinear_hits", KSTAT_DATA_UINT64 }, + { "colinear_misses", KSTAT_DATA_UINT64 }, + { "stride_hits", KSTAT_DATA_UINT64 }, + { "stride_misses", KSTAT_DATA_UINT64 }, + { "reclaim_successes", KSTAT_DATA_UINT64 }, + { "reclaim_failures", KSTAT_DATA_UINT64 }, + { "streams_resets", KSTAT_DATA_UINT64 }, + { "streams_noresets", KSTAT_DATA_UINT64 }, + { "bogus_streams", KSTAT_DATA_UINT64 }, +}; + +#define ZFETCHSTAT_INCR(stat, val) \ + atomic_add_64(&zfetch_stats.stat.value.ui64, (val)); + +#define ZFETCHSTAT_BUMP(stat) ZFETCHSTAT_INCR(stat, 1); + +kstat_t *zfetch_ksp; + /* * Given a zfetch structure and a zstream structure, determine whether the * blocks to be read are part of a co-linear pair of existing prefetch @@ -192,7 +226,30 @@ dmu_zfetch_dofetch(zfetch_t *zf, zstream_t *zs) break; } zs->zst_ph_offset = prefetch_tail; - zs->zst_last = lbolt; + zs->zst_last = ddi_get_lbolt(); +} + +void +zfetch_init(void) +{ + + zfetch_ksp = kstat_create("zfs", 0, "zfetchstats", "misc", + KSTAT_TYPE_NAMED, sizeof (zfetch_stats) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL); + + if (zfetch_ksp != NULL) { + zfetch_ksp->ks_data = &zfetch_stats; + kstat_install(zfetch_ksp); + } +} + +void +zfetch_fini(void) +{ + if (zfetch_ksp != NULL) { + kstat_delete(zfetch_ksp); + zfetch_ksp = NULL; + } } /* @@ -265,7 +322,7 @@ dmu_zfetch_fetchsz(dnode_t *dn, uint64_t blkid, uint64_t nblks) } /* - * given a zfetch and a zsearch structure, see if there is an associated zstream + * given a zfetch and a zstream structure, see if there is an associated zstream * for this block read. If so, it starts a prefetch for the stream it * located and returns true, otherwise it returns false */ @@ -297,6 +354,7 @@ top: */ if (zs->zst_len == 0) { /* bogus stream */ + ZFETCHSTAT_BUMP(zfetchstat_bogus_streams); continue; } @@ -306,9 +364,14 @@ top: */ if (zh->zst_offset >= zs->zst_offset && zh->zst_offset < zs->zst_offset + zs->zst_len) { - /* already fetched */ - rc = 1; - goto out; + if (prefetched) { + /* already fetched */ + ZFETCHSTAT_BUMP(zfetchstat_stride_hits); + rc = 1; + goto out; + } else { + ZFETCHSTAT_BUMP(zfetchstat_stride_misses); + } } /* @@ -413,6 +476,7 @@ top: if (reset) { zstream_t *remove = zs; + ZFETCHSTAT_BUMP(zfetchstat_stream_resets); rc = 0; mutex_exit(&zs->zst_lock); rw_exit(&zf->zf_rwlock); @@ -431,6 +495,7 @@ top: } } } else { + ZFETCHSTAT_BUMP(zfetchstat_stream_noresets); rc = 1; dmu_zfetch_dofetch(zf, zs); mutex_exit(&zs->zst_lock); @@ -487,13 +552,12 @@ dmu_zfetch_stream_insert(zfetch_t *zf, zstream_t *zs) zs_next = list_next(&zf->zf_stream, zs_walk); if (dmu_zfetch_streams_equal(zs_walk, zs)) { - return (0); + return (0); } } list_insert_head(&zf->zf_stream, zs); zf->zf_stream_cnt++; - return (1); } @@ -513,7 +577,7 @@ dmu_zfetch_stream_reclaim(zfetch_t *zf) for (zs = list_head(&zf->zf_stream); zs; zs = list_next(&zf->zf_stream, zs)) { - if (((lbolt - zs->zst_last) / hz) > zfetch_min_sec_reap) + if (((ddi_get_lbolt() - zs->zst_last)/hz) > zfetch_min_sec_reap) break; } @@ -597,8 +661,15 @@ dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) P2ALIGN(offset, blksz)) >> blkshft; fetched = dmu_zfetch_find(zf, &zst, prefetched); - if (!fetched) { - fetched = dmu_zfetch_colinear(zf, &zst); + if (fetched) { + ZFETCHSTAT_BUMP(zfetchstat_hits); + } else { + ZFETCHSTAT_BUMP(zfetchstat_misses); + if ((fetched = dmu_zfetch_colinear(zf, &zst))) { + ZFETCHSTAT_BUMP(zfetchstat_colinear_hits); + } else { + ZFETCHSTAT_BUMP(zfetchstat_colinear_misses); + } } if (!fetched) { @@ -608,11 +679,14 @@ dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) * we still couldn't find a stream, drop the lock, and allocate * one if possible. Otherwise, give up and go home. */ - if (newstream == NULL) { + if (newstream) { + ZFETCHSTAT_BUMP(zfetchstat_reclaim_successes); + } else { uint64_t maxblocks; uint32_t max_streams; uint32_t cur_streams; + ZFETCHSTAT_BUMP(zfetchstat_reclaim_failures); cur_streams = zf->zf_stream_cnt; maxblocks = zf->zf_dnode->dn_maxblkid; @@ -625,8 +699,7 @@ dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) if (cur_streams >= max_streams) { return; } - - newstream = kmem_zalloc(sizeof (zstream_t), KM_SLEEP); + newstream = kmem_zalloc(sizeof (zstream_t), KM_PUSHPAGE); } newstream->zst_offset = zst.zst_offset; @@ -635,7 +708,7 @@ dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) newstream->zst_ph_offset = zst.zst_len + zst.zst_offset; newstream->zst_cap = zst.zst_len; newstream->zst_direction = ZFETCH_FORWARD; - newstream->zst_last = lbolt; + newstream->zst_last = ddi_get_lbolt(); mutex_init(&newstream->zst_lock, NULL, MUTEX_DEFAULT, NULL); @@ -649,3 +722,21 @@ dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) } } } + +#if defined(_KERNEL) && defined(HAVE_SPL) +module_param(zfs_prefetch_disable, int, 0644); +MODULE_PARM_DESC(zfs_prefetch_disable, "Disable all ZFS prefetching"); + +module_param(zfetch_max_streams, uint, 0644); +MODULE_PARM_DESC(zfetch_max_streams, "Max number of streams per zfetch"); + +module_param(zfetch_min_sec_reap, uint, 0644); +MODULE_PARM_DESC(zfetch_min_sec_reap, "Min time before stream reclaim"); + +module_param(zfetch_block_cap, uint, 0644); +MODULE_PARM_DESC(zfetch_block_cap, "Max number of blocks to fetch at a time"); + +module_param(zfetch_array_rd_sz, ulong, 0644); +MODULE_PARM_DESC(zfetch_array_rd_sz, "Number of bytes in a array_read"); +#endif +