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