xref: /freebsd/sys/contrib/openzfs/cmd/raidz_test/raidz_bench.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy  * CDDL HEADER START
4eda14cbcSMatt Macy  *
5eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy  *
9eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy  * See the License for the specific language governing permissions
12eda14cbcSMatt Macy  * and limitations under the License.
13eda14cbcSMatt Macy  *
14eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy  *
20eda14cbcSMatt Macy  * CDDL HEADER END
21eda14cbcSMatt Macy  */
22eda14cbcSMatt Macy 
23eda14cbcSMatt Macy /*
24eda14cbcSMatt Macy  * Copyright (C) 2016 Gvozden Nešković. All rights reserved.
25eda14cbcSMatt Macy  */
26eda14cbcSMatt Macy 
27eda14cbcSMatt Macy #include <sys/zfs_context.h>
28eda14cbcSMatt Macy #include <sys/time.h>
29eda14cbcSMatt Macy #include <sys/wait.h>
30eda14cbcSMatt Macy #include <sys/zio.h>
31eda14cbcSMatt Macy #include <sys/vdev_raidz.h>
32eda14cbcSMatt Macy #include <sys/vdev_raidz_impl.h>
33eda14cbcSMatt Macy #include <stdio.h>
34eda14cbcSMatt Macy 
35eda14cbcSMatt Macy #include "raidz_test.h"
36eda14cbcSMatt Macy 
37eda14cbcSMatt Macy #define	GEN_BENCH_MEMORY	(((uint64_t)1ULL)<<32)
38eda14cbcSMatt Macy #define	REC_BENCH_MEMORY	(((uint64_t)1ULL)<<29)
39eda14cbcSMatt Macy #define	BENCH_ASHIFT		12
40eda14cbcSMatt Macy #define	MIN_CS_SHIFT		BENCH_ASHIFT
41eda14cbcSMatt Macy #define	MAX_CS_SHIFT		SPA_MAXBLOCKSHIFT
42eda14cbcSMatt Macy 
43eda14cbcSMatt Macy static zio_t zio_bench;
44eda14cbcSMatt Macy static raidz_map_t *rm_bench;
45eda14cbcSMatt Macy static size_t max_data_size = SPA_MAXBLOCKSIZE;
46eda14cbcSMatt Macy 
47eda14cbcSMatt Macy static void
bench_init_raidz_map(void)48eda14cbcSMatt Macy bench_init_raidz_map(void)
49eda14cbcSMatt Macy {
50eda14cbcSMatt Macy 	zio_bench.io_offset = 0;
51eda14cbcSMatt Macy 	zio_bench.io_size = max_data_size;
52eda14cbcSMatt Macy 
53eda14cbcSMatt Macy 	/*
54eda14cbcSMatt Macy 	 * To permit larger column sizes these have to be done
55eda14cbcSMatt Macy 	 * allocated using aligned alloc instead of zio_abd_buf_alloc
56eda14cbcSMatt Macy 	 */
57eda14cbcSMatt Macy 	zio_bench.io_abd = raidz_alloc(max_data_size);
58eda14cbcSMatt Macy 
59eda14cbcSMatt Macy 	init_zio_abd(&zio_bench);
60eda14cbcSMatt Macy }
61eda14cbcSMatt Macy 
62eda14cbcSMatt Macy static void
bench_fini_raidz_maps(void)63eda14cbcSMatt Macy bench_fini_raidz_maps(void)
64eda14cbcSMatt Macy {
65eda14cbcSMatt Macy 	/* tear down golden zio */
66eda14cbcSMatt Macy 	raidz_free(zio_bench.io_abd, max_data_size);
67da5137abSMartin Matuska 	memset(&zio_bench, 0, sizeof (zio_t));
68eda14cbcSMatt Macy }
69eda14cbcSMatt Macy 
70eda14cbcSMatt Macy static inline void
run_gen_bench_impl(const char * impl)71eda14cbcSMatt Macy run_gen_bench_impl(const char *impl)
72eda14cbcSMatt Macy {
73eda14cbcSMatt Macy 	int fn, ncols;
74eda14cbcSMatt Macy 	uint64_t ds, iter_cnt, iter, disksize;
75eda14cbcSMatt Macy 	hrtime_t start;
76eda14cbcSMatt Macy 	double elapsed, d_bw;
77eda14cbcSMatt Macy 
78eda14cbcSMatt Macy 	/* Benchmark generate functions */
79eda14cbcSMatt Macy 	for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {
80eda14cbcSMatt Macy 
81eda14cbcSMatt Macy 		for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) {
82eda14cbcSMatt Macy 			/* create suitable raidz_map */
83eda14cbcSMatt Macy 			ncols = rto_opts.rto_dcols + fn + 1;
84eda14cbcSMatt Macy 			zio_bench.io_size = 1ULL << ds;
857877fdebSMatt Macy 
867877fdebSMatt Macy 			if (rto_opts.rto_expand) {
877877fdebSMatt Macy 				rm_bench = vdev_raidz_map_alloc_expanded(
88e716630dSMartin Matuska 				    &zio_bench,
897877fdebSMatt Macy 				    rto_opts.rto_ashift, ncols+1, ncols,
90e716630dSMartin Matuska 				    fn+1, rto_opts.rto_expand_offset,
91e716630dSMartin Matuska 				    0, B_FALSE);
927877fdebSMatt Macy 			} else {
93eda14cbcSMatt Macy 				rm_bench = vdev_raidz_map_alloc(&zio_bench,
94eda14cbcSMatt Macy 				    BENCH_ASHIFT, ncols, fn+1);
957877fdebSMatt Macy 			}
96eda14cbcSMatt Macy 
97eda14cbcSMatt Macy 			/* estimate iteration count */
98eda14cbcSMatt Macy 			iter_cnt = GEN_BENCH_MEMORY;
99eda14cbcSMatt Macy 			iter_cnt /= zio_bench.io_size;
100eda14cbcSMatt Macy 
101eda14cbcSMatt Macy 			start = gethrtime();
102eda14cbcSMatt Macy 			for (iter = 0; iter < iter_cnt; iter++)
103eda14cbcSMatt Macy 				vdev_raidz_generate_parity(rm_bench);
104eda14cbcSMatt Macy 			elapsed = NSEC2SEC((double)(gethrtime() - start));
105eda14cbcSMatt Macy 
106eda14cbcSMatt Macy 			disksize = (1ULL << ds) / rto_opts.rto_dcols;
107eda14cbcSMatt Macy 			d_bw = (double)iter_cnt * (double)disksize;
108eda14cbcSMatt Macy 			d_bw /= (1024.0 * 1024.0 * elapsed);
109eda14cbcSMatt Macy 
110eda14cbcSMatt Macy 			LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n",
111eda14cbcSMatt Macy 			    impl,
112eda14cbcSMatt Macy 			    raidz_gen_name[fn],
113eda14cbcSMatt Macy 			    rto_opts.rto_dcols,
114eda14cbcSMatt Macy 			    (1ULL<<ds),
115eda14cbcSMatt Macy 			    d_bw,
116eda14cbcSMatt Macy 			    d_bw * (double)(ncols),
117eda14cbcSMatt Macy 			    (unsigned)iter_cnt);
118eda14cbcSMatt Macy 
119eda14cbcSMatt Macy 			vdev_raidz_map_free(rm_bench);
120eda14cbcSMatt Macy 		}
121eda14cbcSMatt Macy 	}
122eda14cbcSMatt Macy }
123eda14cbcSMatt Macy 
124eda14cbcSMatt Macy static void
run_gen_bench(void)125eda14cbcSMatt Macy run_gen_bench(void)
126eda14cbcSMatt Macy {
127eda14cbcSMatt Macy 	char **impl_name;
128eda14cbcSMatt Macy 
129eda14cbcSMatt Macy 	LOG(D_INFO, DBLSEP "\nBenchmarking parity generation...\n\n");
130eda14cbcSMatt Macy 	LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n");
131eda14cbcSMatt Macy 
132eda14cbcSMatt Macy 	for (impl_name = (char **)raidz_impl_names; *impl_name != NULL;
133eda14cbcSMatt Macy 	    impl_name++) {
134eda14cbcSMatt Macy 
135eda14cbcSMatt Macy 		if (vdev_raidz_impl_set(*impl_name) != 0)
136eda14cbcSMatt Macy 			continue;
137eda14cbcSMatt Macy 
138eda14cbcSMatt Macy 		run_gen_bench_impl(*impl_name);
139eda14cbcSMatt Macy 	}
140eda14cbcSMatt Macy }
141eda14cbcSMatt Macy 
142eda14cbcSMatt Macy static void
run_rec_bench_impl(const char * impl)143eda14cbcSMatt Macy run_rec_bench_impl(const char *impl)
144eda14cbcSMatt Macy {
145eda14cbcSMatt Macy 	int fn, ncols, nbad;
146eda14cbcSMatt Macy 	uint64_t ds, iter_cnt, iter, disksize;
147eda14cbcSMatt Macy 	hrtime_t start;
148eda14cbcSMatt Macy 	double elapsed, d_bw;
149eda14cbcSMatt Macy 	static const int tgt[7][3] = {
150eda14cbcSMatt Macy 		{1, 2, 3},	/* rec_p:   bad QR & D[0]	*/
151eda14cbcSMatt Macy 		{0, 2, 3},	/* rec_q:   bad PR & D[0]	*/
152eda14cbcSMatt Macy 		{0, 1, 3},	/* rec_r:   bad PQ & D[0]	*/
153eda14cbcSMatt Macy 		{2, 3, 4},	/* rec_pq:  bad R  & D[0][1]	*/
154eda14cbcSMatt Macy 		{1, 3, 4},	/* rec_pr:  bad Q  & D[0][1]	*/
155eda14cbcSMatt Macy 		{0, 3, 4},	/* rec_qr:  bad P  & D[0][1]	*/
156eda14cbcSMatt Macy 		{3, 4, 5}	/* rec_pqr: bad    & D[0][1][2] */
157eda14cbcSMatt Macy 	};
158eda14cbcSMatt Macy 
159eda14cbcSMatt Macy 	for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {
160eda14cbcSMatt Macy 		for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) {
161eda14cbcSMatt Macy 
162eda14cbcSMatt Macy 			/* create suitable raidz_map */
163eda14cbcSMatt Macy 			ncols = rto_opts.rto_dcols + PARITY_PQR;
164eda14cbcSMatt Macy 			zio_bench.io_size = 1ULL << ds;
165eda14cbcSMatt Macy 
166eda14cbcSMatt Macy 			/*
167eda14cbcSMatt Macy 			 * raidz block is too short to test
168eda14cbcSMatt Macy 			 * the requested method
169eda14cbcSMatt Macy 			 */
170eda14cbcSMatt Macy 			if (zio_bench.io_size / rto_opts.rto_dcols <
171eda14cbcSMatt Macy 			    (1ULL << BENCH_ASHIFT))
172eda14cbcSMatt Macy 				continue;
173eda14cbcSMatt Macy 
1747877fdebSMatt Macy 			if (rto_opts.rto_expand) {
1757877fdebSMatt Macy 				rm_bench = vdev_raidz_map_alloc_expanded(
176e716630dSMartin Matuska 				    &zio_bench,
1777877fdebSMatt Macy 				    BENCH_ASHIFT, ncols+1, ncols,
178e716630dSMartin Matuska 				    PARITY_PQR,
179e716630dSMartin Matuska 				    rto_opts.rto_expand_offset, 0, B_FALSE);
1807877fdebSMatt Macy 			} else {
181eda14cbcSMatt Macy 				rm_bench = vdev_raidz_map_alloc(&zio_bench,
182eda14cbcSMatt Macy 				    BENCH_ASHIFT, ncols, PARITY_PQR);
1837877fdebSMatt Macy 			}
184eda14cbcSMatt Macy 
185eda14cbcSMatt Macy 			/* estimate iteration count */
186eda14cbcSMatt Macy 			iter_cnt = (REC_BENCH_MEMORY);
187eda14cbcSMatt Macy 			iter_cnt /= zio_bench.io_size;
188eda14cbcSMatt Macy 
189eda14cbcSMatt Macy 			/* calculate how many bad columns there are */
190eda14cbcSMatt Macy 			nbad = MIN(3, raidz_ncols(rm_bench) -
191eda14cbcSMatt Macy 			    raidz_parity(rm_bench));
192eda14cbcSMatt Macy 
193eda14cbcSMatt Macy 			start = gethrtime();
194eda14cbcSMatt Macy 			for (iter = 0; iter < iter_cnt; iter++)
195eda14cbcSMatt Macy 				vdev_raidz_reconstruct(rm_bench, tgt[fn], nbad);
196eda14cbcSMatt Macy 			elapsed = NSEC2SEC((double)(gethrtime() - start));
197eda14cbcSMatt Macy 
198eda14cbcSMatt Macy 			disksize = (1ULL << ds) / rto_opts.rto_dcols;
199eda14cbcSMatt Macy 			d_bw = (double)iter_cnt * (double)(disksize);
200eda14cbcSMatt Macy 			d_bw /= (1024.0 * 1024.0 * elapsed);
201eda14cbcSMatt Macy 
202eda14cbcSMatt Macy 			LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n",
203eda14cbcSMatt Macy 			    impl,
204eda14cbcSMatt Macy 			    raidz_rec_name[fn],
205eda14cbcSMatt Macy 			    rto_opts.rto_dcols,
206eda14cbcSMatt Macy 			    (1ULL<<ds),
207eda14cbcSMatt Macy 			    d_bw,
208eda14cbcSMatt Macy 			    d_bw * (double)ncols,
209eda14cbcSMatt Macy 			    (unsigned)iter_cnt);
210eda14cbcSMatt Macy 
211eda14cbcSMatt Macy 			vdev_raidz_map_free(rm_bench);
212eda14cbcSMatt Macy 		}
213eda14cbcSMatt Macy 	}
214eda14cbcSMatt Macy }
215eda14cbcSMatt Macy 
216eda14cbcSMatt Macy static void
run_rec_bench(void)217eda14cbcSMatt Macy run_rec_bench(void)
218eda14cbcSMatt Macy {
219eda14cbcSMatt Macy 	char **impl_name;
220eda14cbcSMatt Macy 
221eda14cbcSMatt Macy 	LOG(D_INFO, DBLSEP "\nBenchmarking data reconstruction...\n\n");
222eda14cbcSMatt Macy 	LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n");
223eda14cbcSMatt Macy 
224eda14cbcSMatt Macy 	for (impl_name = (char **)raidz_impl_names; *impl_name != NULL;
225eda14cbcSMatt Macy 	    impl_name++) {
226eda14cbcSMatt Macy 
227eda14cbcSMatt Macy 		if (vdev_raidz_impl_set(*impl_name) != 0)
228eda14cbcSMatt Macy 			continue;
229eda14cbcSMatt Macy 
230eda14cbcSMatt Macy 		run_rec_bench_impl(*impl_name);
231eda14cbcSMatt Macy 	}
232eda14cbcSMatt Macy }
233eda14cbcSMatt Macy 
234eda14cbcSMatt Macy void
run_raidz_benchmark(void)235eda14cbcSMatt Macy run_raidz_benchmark(void)
236eda14cbcSMatt Macy {
237eda14cbcSMatt Macy 	bench_init_raidz_map();
238eda14cbcSMatt Macy 
239eda14cbcSMatt Macy 	run_gen_bench();
240eda14cbcSMatt Macy 	run_rec_bench();
241eda14cbcSMatt Macy 
242eda14cbcSMatt Macy 	bench_fini_raidz_maps();
243eda14cbcSMatt Macy }
244