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