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
bench_init_raidz_map(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
bench_fini_raidz_maps(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
run_gen_bench_impl(const char * impl)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,
88 rto_opts.rto_ashift, ncols+1, ncols,
89 fn+1, rto_opts.rto_expand_offset,
90 0, B_FALSE);
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
run_gen_bench(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
run_rec_bench_impl(const char * impl)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,
176 BENCH_ASHIFT, ncols+1, ncols,
177 PARITY_PQR,
178 rto_opts.rto_expand_offset, 0, B_FALSE);
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
run_rec_bench(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
run_raidz_benchmark(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