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