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
bench_init_raidz_map(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
bench_fini_raidz_maps(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
run_gen_bench_impl(const char * impl)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
run_gen_bench(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
run_rec_bench_impl(const char * impl)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
run_rec_bench(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
run_raidz_benchmark(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