1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (C) 2016 Gvozden Nešković. All rights reserved. 25 */ 26 27 #include <sys/zfs_context.h> 28 #include <sys/time.h> 29 #include <sys/wait.h> 30 #include <sys/zio.h> 31 #include <sys/vdev_raidz.h> 32 #include <sys/vdev_raidz_impl.h> 33 #include <stdio.h> 34 35 #include "raidz_test.h" 36 37 #define GEN_BENCH_MEMORY (((uint64_t)1ULL)<<32) 38 #define REC_BENCH_MEMORY (((uint64_t)1ULL)<<29) 39 #define BENCH_ASHIFT 12 40 #define MIN_CS_SHIFT BENCH_ASHIFT 41 #define MAX_CS_SHIFT SPA_MAXBLOCKSHIFT 42 43 static zio_t zio_bench; 44 static raidz_map_t *rm_bench; 45 static size_t max_data_size = SPA_MAXBLOCKSIZE; 46 47 static void 48 bench_init_raidz_map(void) 49 { 50 zio_bench.io_offset = 0; 51 zio_bench.io_size = max_data_size; 52 53 /* 54 * To permit larger column sizes these have to be done 55 * allocated using aligned alloc instead of zio_abd_buf_alloc 56 */ 57 zio_bench.io_abd = raidz_alloc(max_data_size); 58 59 init_zio_abd(&zio_bench); 60 } 61 62 static void 63 bench_fini_raidz_maps(void) 64 { 65 /* tear down golden zio */ 66 raidz_free(zio_bench.io_abd, max_data_size); 67 memset(&zio_bench, 0, sizeof (zio_t)); 68 } 69 70 static inline void 71 run_gen_bench_impl(const char *impl) 72 { 73 int fn, ncols; 74 uint64_t ds, iter_cnt, iter, disksize; 75 hrtime_t start; 76 double elapsed, d_bw; 77 78 /* Benchmark generate functions */ 79 for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) { 80 81 for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) { 82 /* create suitable raidz_map */ 83 ncols = rto_opts.rto_dcols + fn + 1; 84 zio_bench.io_size = 1ULL << ds; 85 86 if (rto_opts.rto_expand) { 87 rm_bench = vdev_raidz_map_alloc_expanded( 88 &zio_bench, 89 rto_opts.rto_ashift, ncols+1, ncols, 90 fn+1, rto_opts.rto_expand_offset, 91 0, B_FALSE); 92 } else { 93 rm_bench = vdev_raidz_map_alloc(&zio_bench, 94 BENCH_ASHIFT, ncols, fn+1); 95 } 96 97 /* estimate iteration count */ 98 iter_cnt = GEN_BENCH_MEMORY; 99 iter_cnt /= zio_bench.io_size; 100 101 start = gethrtime(); 102 for (iter = 0; iter < iter_cnt; iter++) 103 vdev_raidz_generate_parity(rm_bench); 104 elapsed = NSEC2SEC((double)(gethrtime() - start)); 105 106 disksize = (1ULL << ds) / rto_opts.rto_dcols; 107 d_bw = (double)iter_cnt * (double)disksize; 108 d_bw /= (1024.0 * 1024.0 * elapsed); 109 110 LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n", 111 impl, 112 raidz_gen_name[fn], 113 rto_opts.rto_dcols, 114 (1ULL<<ds), 115 d_bw, 116 d_bw * (double)(ncols), 117 (unsigned)iter_cnt); 118 119 vdev_raidz_map_free(rm_bench); 120 } 121 } 122 } 123 124 static void 125 run_gen_bench(void) 126 { 127 char **impl_name; 128 129 LOG(D_INFO, DBLSEP "\nBenchmarking parity generation...\n\n"); 130 LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n"); 131 132 for (impl_name = (char **)raidz_impl_names; *impl_name != NULL; 133 impl_name++) { 134 135 if (vdev_raidz_impl_set(*impl_name) != 0) 136 continue; 137 138 run_gen_bench_impl(*impl_name); 139 } 140 } 141 142 static void 143 run_rec_bench_impl(const char *impl) 144 { 145 int fn, ncols, nbad; 146 uint64_t ds, iter_cnt, iter, disksize; 147 hrtime_t start; 148 double elapsed, d_bw; 149 static const int tgt[7][3] = { 150 {1, 2, 3}, /* rec_p: bad QR & D[0] */ 151 {0, 2, 3}, /* rec_q: bad PR & D[0] */ 152 {0, 1, 3}, /* rec_r: bad PQ & D[0] */ 153 {2, 3, 4}, /* rec_pq: bad R & D[0][1] */ 154 {1, 3, 4}, /* rec_pr: bad Q & D[0][1] */ 155 {0, 3, 4}, /* rec_qr: bad P & D[0][1] */ 156 {3, 4, 5} /* rec_pqr: bad & D[0][1][2] */ 157 }; 158 159 for (fn = 0; fn < RAIDZ_REC_NUM; fn++) { 160 for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) { 161 162 /* create suitable raidz_map */ 163 ncols = rto_opts.rto_dcols + PARITY_PQR; 164 zio_bench.io_size = 1ULL << ds; 165 166 /* 167 * raidz block is too short to test 168 * the requested method 169 */ 170 if (zio_bench.io_size / rto_opts.rto_dcols < 171 (1ULL << BENCH_ASHIFT)) 172 continue; 173 174 if (rto_opts.rto_expand) { 175 rm_bench = vdev_raidz_map_alloc_expanded( 176 &zio_bench, 177 BENCH_ASHIFT, ncols+1, ncols, 178 PARITY_PQR, 179 rto_opts.rto_expand_offset, 0, B_FALSE); 180 } else { 181 rm_bench = vdev_raidz_map_alloc(&zio_bench, 182 BENCH_ASHIFT, ncols, PARITY_PQR); 183 } 184 185 /* estimate iteration count */ 186 iter_cnt = (REC_BENCH_MEMORY); 187 iter_cnt /= zio_bench.io_size; 188 189 /* calculate how many bad columns there are */ 190 nbad = MIN(3, raidz_ncols(rm_bench) - 191 raidz_parity(rm_bench)); 192 193 start = gethrtime(); 194 for (iter = 0; iter < iter_cnt; iter++) 195 vdev_raidz_reconstruct(rm_bench, tgt[fn], nbad); 196 elapsed = NSEC2SEC((double)(gethrtime() - start)); 197 198 disksize = (1ULL << ds) / rto_opts.rto_dcols; 199 d_bw = (double)iter_cnt * (double)(disksize); 200 d_bw /= (1024.0 * 1024.0 * elapsed); 201 202 LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n", 203 impl, 204 raidz_rec_name[fn], 205 rto_opts.rto_dcols, 206 (1ULL<<ds), 207 d_bw, 208 d_bw * (double)ncols, 209 (unsigned)iter_cnt); 210 211 vdev_raidz_map_free(rm_bench); 212 } 213 } 214 } 215 216 static void 217 run_rec_bench(void) 218 { 219 char **impl_name; 220 221 LOG(D_INFO, DBLSEP "\nBenchmarking data reconstruction...\n\n"); 222 LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n"); 223 224 for (impl_name = (char **)raidz_impl_names; *impl_name != NULL; 225 impl_name++) { 226 227 if (vdev_raidz_impl_set(*impl_name) != 0) 228 continue; 229 230 run_rec_bench_impl(*impl_name); 231 } 232 } 233 234 void 235 run_raidz_benchmark(void) 236 { 237 bench_init_raidz_map(); 238 239 run_gen_bench(); 240 run_rec_bench(); 241 242 bench_fini_raidz_maps(); 243 } 244