| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| |
| /* |
| * Copyright (C) 2016 Gvozden Nešković. All rights reserved. |
| */ |
| |
| #include <sys/zfs_context.h> |
| #include <sys/time.h> |
| #include <sys/wait.h> |
| #include <sys/zio.h> |
| #include <sys/vdev_raidz.h> |
| #include <sys/vdev_raidz_impl.h> |
| #include <stdio.h> |
| |
| #include <sys/time.h> |
| |
| #include "raidz_test.h" |
| |
| #define GEN_BENCH_MEMORY (((uint64_t)1ULL)<<32) |
| #define REC_BENCH_MEMORY (((uint64_t)1ULL)<<29) |
| #define BENCH_ASHIFT 12 |
| #define MIN_CS_SHIFT BENCH_ASHIFT |
| #define MAX_CS_SHIFT SPA_MAXBLOCKSHIFT |
| |
| static zio_t zio_bench; |
| static raidz_map_t *rm_bench; |
| static size_t max_data_size = SPA_MAXBLOCKSIZE; |
| |
| static void |
| bench_init_raidz_map(void) |
| { |
| zio_bench.io_offset = 0; |
| zio_bench.io_size = max_data_size; |
| |
| /* |
| * To permit larger column sizes these have to be done |
| * allocated using aligned alloc instead of zio_abd_buf_alloc |
| */ |
| zio_bench.io_abd = raidz_alloc(max_data_size); |
| |
| init_zio_abd(&zio_bench); |
| } |
| |
| static void |
| bench_fini_raidz_maps(void) |
| { |
| /* tear down golden zio */ |
| raidz_free(zio_bench.io_abd, max_data_size); |
| bzero(&zio_bench, sizeof (zio_t)); |
| } |
| |
| static inline void |
| run_gen_bench_impl(const char *impl) |
| { |
| int fn, ncols; |
| uint64_t ds, iter_cnt, iter, disksize; |
| hrtime_t start; |
| double elapsed, d_bw; |
| |
| /* Benchmark generate functions */ |
| for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) { |
| |
| for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) { |
| /* create suitable raidz_map */ |
| ncols = rto_opts.rto_dcols + fn + 1; |
| zio_bench.io_size = 1ULL << ds; |
| rm_bench = vdev_raidz_map_alloc(&zio_bench, |
| BENCH_ASHIFT, ncols, fn+1); |
| |
| /* estimate iteration count */ |
| iter_cnt = GEN_BENCH_MEMORY; |
| iter_cnt /= zio_bench.io_size; |
| |
| start = gethrtime(); |
| for (iter = 0; iter < iter_cnt; iter++) |
| vdev_raidz_generate_parity(rm_bench); |
| elapsed = NSEC2SEC((double)(gethrtime() - start)); |
| |
| disksize = (1ULL << ds) / rto_opts.rto_dcols; |
| d_bw = (double)iter_cnt * (double)disksize; |
| d_bw /= (1024.0 * 1024.0 * elapsed); |
| |
| LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n", |
| impl, |
| raidz_gen_name[fn], |
| rto_opts.rto_dcols, |
| (1ULL<<ds), |
| d_bw, |
| d_bw * (double)(ncols), |
| (unsigned)iter_cnt); |
| |
| vdev_raidz_map_free(rm_bench); |
| } |
| } |
| } |
| |
| void |
| run_gen_bench(void) |
| { |
| char **impl_name; |
| |
| LOG(D_INFO, DBLSEP "\nBenchmarking parity generation...\n\n"); |
| LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n"); |
| |
| for (impl_name = (char **)raidz_impl_names; *impl_name != NULL; |
| impl_name++) { |
| |
| if (vdev_raidz_impl_set(*impl_name) != 0) |
| continue; |
| |
| run_gen_bench_impl(*impl_name); |
| } |
| } |
| |
| static void |
| run_rec_bench_impl(const char *impl) |
| { |
| int fn, ncols, nbad; |
| uint64_t ds, iter_cnt, iter, disksize; |
| hrtime_t start; |
| double elapsed, d_bw; |
| static const int tgt[7][3] = { |
| {1, 2, 3}, /* rec_p: bad QR & D[0] */ |
| {0, 2, 3}, /* rec_q: bad PR & D[0] */ |
| {0, 1, 3}, /* rec_r: bad PQ & D[0] */ |
| {2, 3, 4}, /* rec_pq: bad R & D[0][1] */ |
| {1, 3, 4}, /* rec_pr: bad Q & D[0][1] */ |
| {0, 3, 4}, /* rec_qr: bad P & D[0][1] */ |
| {3, 4, 5} /* rec_pqr: bad & D[0][1][2] */ |
| }; |
| |
| for (fn = 0; fn < RAIDZ_REC_NUM; fn++) { |
| for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) { |
| |
| /* create suitable raidz_map */ |
| ncols = rto_opts.rto_dcols + PARITY_PQR; |
| zio_bench.io_size = 1ULL << ds; |
| |
| /* |
| * raidz block is too short to test |
| * the requested method |
| */ |
| if (zio_bench.io_size / rto_opts.rto_dcols < |
| (1ULL << BENCH_ASHIFT)) |
| continue; |
| |
| rm_bench = vdev_raidz_map_alloc(&zio_bench, |
| BENCH_ASHIFT, ncols, PARITY_PQR); |
| |
| /* estimate iteration count */ |
| iter_cnt = (REC_BENCH_MEMORY); |
| iter_cnt /= zio_bench.io_size; |
| |
| /* calculate how many bad columns there are */ |
| nbad = MIN(3, raidz_ncols(rm_bench) - |
| raidz_parity(rm_bench)); |
| |
| start = gethrtime(); |
| for (iter = 0; iter < iter_cnt; iter++) |
| vdev_raidz_reconstruct(rm_bench, tgt[fn], nbad); |
| elapsed = NSEC2SEC((double)(gethrtime() - start)); |
| |
| disksize = (1ULL << ds) / rto_opts.rto_dcols; |
| d_bw = (double)iter_cnt * (double)(disksize); |
| d_bw /= (1024.0 * 1024.0 * elapsed); |
| |
| LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n", |
| impl, |
| raidz_rec_name[fn], |
| rto_opts.rto_dcols, |
| (1ULL<<ds), |
| d_bw, |
| d_bw * (double)ncols, |
| (unsigned)iter_cnt); |
| |
| vdev_raidz_map_free(rm_bench); |
| } |
| } |
| } |
| |
| void |
| run_rec_bench(void) |
| { |
| char **impl_name; |
| |
| LOG(D_INFO, DBLSEP "\nBenchmarking data reconstruction...\n\n"); |
| LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n"); |
| |
| for (impl_name = (char **)raidz_impl_names; *impl_name != NULL; |
| impl_name++) { |
| |
| if (vdev_raidz_impl_set(*impl_name) != 0) |
| continue; |
| |
| run_rec_bench_impl(*impl_name); |
| } |
| } |
| |
| void |
| run_raidz_benchmark(void) |
| { |
| bench_init_raidz_map(); |
| |
| run_gen_bench(); |
| run_rec_bench(); |
| |
| bench_fini_raidz_maps(); |
| } |