xref: /freebsd/sys/contrib/openzfs/cmd/raidz_test/raidz_bench.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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