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