xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/cmd/file/randwritecomp.c (revision 716fd348e01c5f2ba125f878a634a753436c2994)
1*716fd348SMartin Matuska /*
2*716fd348SMartin Matuska  * This file and its contents are supplied under the terms of the
3*716fd348SMartin Matuska  * Common Development and Distribution License ("CDDL"), version 1.0.
4*716fd348SMartin Matuska  * You may only use this file in accordance with the terms of version
5*716fd348SMartin Matuska  * 1.0 of the CDDL.
6*716fd348SMartin Matuska  *
7*716fd348SMartin Matuska  * A full copy of the text of the CDDL should have accompanied this
8*716fd348SMartin Matuska  * source.  A copy of the CDDL is also available via the Internet at
9*716fd348SMartin Matuska  * http://www.illumos.org/license/CDDL.
10*716fd348SMartin Matuska  */
11*716fd348SMartin Matuska 
12*716fd348SMartin Matuska /*
13*716fd348SMartin Matuska  * Copyright (c) 2017 by Delphix. All rights reserved.
14*716fd348SMartin Matuska  */
15*716fd348SMartin Matuska 
16*716fd348SMartin Matuska #include <stdint.h>
17*716fd348SMartin Matuska #include <string.h>
18*716fd348SMartin Matuska #include "file_common.h"
19*716fd348SMartin Matuska 
20*716fd348SMartin Matuska /*
21*716fd348SMartin Matuska  * The following sample was derived from real-world data
22*716fd348SMartin Matuska  * of a production Oracle database.
23*716fd348SMartin Matuska  */
24*716fd348SMartin Matuska static const uint64_t size_distribution[] = {
25*716fd348SMartin Matuska 	0,
26*716fd348SMartin Matuska 	1499018,
27*716fd348SMartin Matuska 	352084,
28*716fd348SMartin Matuska 	1503485,
29*716fd348SMartin Matuska 	4206227,
30*716fd348SMartin Matuska 	5626657,
31*716fd348SMartin Matuska 	5387001,
32*716fd348SMartin Matuska 	3733756,
33*716fd348SMartin Matuska 	2233094,
34*716fd348SMartin Matuska 	874652,
35*716fd348SMartin Matuska 	238635,
36*716fd348SMartin Matuska 	81434,
37*716fd348SMartin Matuska 	33357,
38*716fd348SMartin Matuska 	13106,
39*716fd348SMartin Matuska 	2009,
40*716fd348SMartin Matuska 	1,
41*716fd348SMartin Matuska 	23660,
42*716fd348SMartin Matuska };
43*716fd348SMartin Matuska 
44*716fd348SMartin Matuska 
45*716fd348SMartin Matuska static uint64_t distribution_n;
46*716fd348SMartin Matuska 
47*716fd348SMartin Matuska static uint8_t randbuf[BLOCKSZ];
48*716fd348SMartin Matuska 
49*716fd348SMartin Matuska static void
50*716fd348SMartin Matuska rwc_pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
51*716fd348SMartin Matuska {
52*716fd348SMartin Matuska 	size_t nleft = nbytes;
53*716fd348SMartin Matuska 	ssize_t nwrite = 0;
54*716fd348SMartin Matuska 
55*716fd348SMartin Matuska 	nwrite = pwrite(fd, buf, nbytes, offset);
56*716fd348SMartin Matuska 	if (nwrite < 0) {
57*716fd348SMartin Matuska 		perror("pwrite");
58*716fd348SMartin Matuska 		exit(EXIT_FAILURE);
59*716fd348SMartin Matuska 	}
60*716fd348SMartin Matuska 
61*716fd348SMartin Matuska 	nleft -= nwrite;
62*716fd348SMartin Matuska 	if (nleft != 0) {
63*716fd348SMartin Matuska 		(void) fprintf(stderr, "warning: pwrite: "
64*716fd348SMartin Matuska 		    "wrote %zu out of %zu bytes\n",
65*716fd348SMartin Matuska 		    (nbytes - nleft), nbytes);
66*716fd348SMartin Matuska 	}
67*716fd348SMartin Matuska }
68*716fd348SMartin Matuska 
69*716fd348SMartin Matuska static void
70*716fd348SMartin Matuska fillbuf(char *buf)
71*716fd348SMartin Matuska {
72*716fd348SMartin Matuska 	uint64_t rv = lrand48() % distribution_n;
73*716fd348SMartin Matuska 	uint64_t sum = 0;
74*716fd348SMartin Matuska 
75*716fd348SMartin Matuska 	uint64_t i;
76*716fd348SMartin Matuska 	for (i = 0;
77*716fd348SMartin Matuska 	    i < sizeof (size_distribution) / sizeof (size_distribution[0]);
78*716fd348SMartin Matuska 	    i++) {
79*716fd348SMartin Matuska 		sum += size_distribution[i];
80*716fd348SMartin Matuska 		if (rv < sum)
81*716fd348SMartin Matuska 			break;
82*716fd348SMartin Matuska 	}
83*716fd348SMartin Matuska 
84*716fd348SMartin Matuska 	memcpy(buf, randbuf, BLOCKSZ);
85*716fd348SMartin Matuska 	if (i == 0)
86*716fd348SMartin Matuska 		memset(buf, 0, BLOCKSZ - 10);
87*716fd348SMartin Matuska 	else if (i < 16)
88*716fd348SMartin Matuska 		memset(buf, 0, BLOCKSZ - i * 512 + 256);
89*716fd348SMartin Matuska 	/*LINTED: E_BAD_PTR_CAST_ALIGN*/
90*716fd348SMartin Matuska 	((uint32_t *)buf)[0] = lrand48();
91*716fd348SMartin Matuska }
92*716fd348SMartin Matuska 
93*716fd348SMartin Matuska static void
94*716fd348SMartin Matuska exit_usage(void)
95*716fd348SMartin Matuska {
96*716fd348SMartin Matuska 	(void) puts("usage: randwritecomp [-s] file [nwrites]");
97*716fd348SMartin Matuska 	exit(EXIT_FAILURE);
98*716fd348SMartin Matuska }
99*716fd348SMartin Matuska 
100*716fd348SMartin Matuska static void
101*716fd348SMartin Matuska sequential_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
102*716fd348SMartin Matuska {
103*716fd348SMartin Matuska 	for (int64_t i = 0; n == -1 || i < n; i++) {
104*716fd348SMartin Matuska 		fillbuf(buf);
105*716fd348SMartin Matuska 
106*716fd348SMartin Matuska 		static uint64_t j = 0;
107*716fd348SMartin Matuska 		if (j == 0)
108*716fd348SMartin Matuska 			j = lrand48() % nblocks;
109*716fd348SMartin Matuska 		rwc_pwrite(fd, buf, BLOCKSZ, j * BLOCKSZ);
110*716fd348SMartin Matuska 		j++;
111*716fd348SMartin Matuska 		if (j >= nblocks)
112*716fd348SMartin Matuska 			j = 0;
113*716fd348SMartin Matuska 	}
114*716fd348SMartin Matuska }
115*716fd348SMartin Matuska 
116*716fd348SMartin Matuska static void
117*716fd348SMartin Matuska random_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
118*716fd348SMartin Matuska {
119*716fd348SMartin Matuska 	for (int64_t i = 0; n == -1 || i < n; i++) {
120*716fd348SMartin Matuska 		fillbuf(buf);
121*716fd348SMartin Matuska 		rwc_pwrite(fd, buf, BLOCKSZ, (lrand48() % nblocks) * BLOCKSZ);
122*716fd348SMartin Matuska 	}
123*716fd348SMartin Matuska }
124*716fd348SMartin Matuska 
125*716fd348SMartin Matuska int
126*716fd348SMartin Matuska main(int argc, char *argv[])
127*716fd348SMartin Matuska {
128*716fd348SMartin Matuska 	int fd, err;
129*716fd348SMartin Matuska 	char *filename = NULL;
130*716fd348SMartin Matuska 	char buf[BLOCKSZ];
131*716fd348SMartin Matuska 	struct stat ss;
132*716fd348SMartin Matuska 	uint64_t nblocks;
133*716fd348SMartin Matuska 	int64_t n = -1;
134*716fd348SMartin Matuska 	int sequential = 0;
135*716fd348SMartin Matuska 
136*716fd348SMartin Matuska 	if (argc < 2)
137*716fd348SMartin Matuska 		exit_usage();
138*716fd348SMartin Matuska 
139*716fd348SMartin Matuska 	argv++;
140*716fd348SMartin Matuska 	if (strcmp("-s", argv[0]) == 0) {
141*716fd348SMartin Matuska 		sequential = 1;
142*716fd348SMartin Matuska 		argv++;
143*716fd348SMartin Matuska 	}
144*716fd348SMartin Matuska 
145*716fd348SMartin Matuska 	if (argv[0] == NULL)
146*716fd348SMartin Matuska 		exit_usage();
147*716fd348SMartin Matuska 	else
148*716fd348SMartin Matuska 		filename = argv[0];
149*716fd348SMartin Matuska 
150*716fd348SMartin Matuska 	argv++;
151*716fd348SMartin Matuska 	if (argv[0] != NULL)
152*716fd348SMartin Matuska 		n = strtoull(argv[0], NULL, 0);
153*716fd348SMartin Matuska 
154*716fd348SMartin Matuska 	fd = open(filename, O_RDWR|O_CREAT, 0666);
155*716fd348SMartin Matuska 	err = fstat(fd, &ss);
156*716fd348SMartin Matuska 	if (err != 0) {
157*716fd348SMartin Matuska 		(void) fprintf(stderr,
158*716fd348SMartin Matuska 		    "error: fstat returned error code %d\n", err);
159*716fd348SMartin Matuska 		exit(EXIT_FAILURE);
160*716fd348SMartin Matuska 	}
161*716fd348SMartin Matuska 
162*716fd348SMartin Matuska 	nblocks = ss.st_size / BLOCKSZ;
163*716fd348SMartin Matuska 	if (nblocks == 0) {
164*716fd348SMartin Matuska 		(void) fprintf(stderr, "error: "
165*716fd348SMartin Matuska 		    "file is too small (min allowed size is %d bytes)\n",
166*716fd348SMartin Matuska 		    BLOCKSZ);
167*716fd348SMartin Matuska 		exit(EXIT_FAILURE);
168*716fd348SMartin Matuska 	}
169*716fd348SMartin Matuska 
170*716fd348SMartin Matuska 	srand48(getpid());
171*716fd348SMartin Matuska 	for (int i = 0; i < BLOCKSZ; i++)
172*716fd348SMartin Matuska 		randbuf[i] = lrand48();
173*716fd348SMartin Matuska 
174*716fd348SMartin Matuska 	distribution_n = 0;
175*716fd348SMartin Matuska 	for (uint64_t i = 0;
176*716fd348SMartin Matuska 	    i < sizeof (size_distribution) / sizeof (size_distribution[0]);
177*716fd348SMartin Matuska 	    i++) {
178*716fd348SMartin Matuska 		distribution_n += size_distribution[i];
179*716fd348SMartin Matuska 	}
180*716fd348SMartin Matuska 
181*716fd348SMartin Matuska 	if (sequential)
182*716fd348SMartin Matuska 		sequential_writes(fd, buf, nblocks, n);
183*716fd348SMartin Matuska 	else
184*716fd348SMartin Matuska 		random_writes(fd, buf, nblocks, n);
185*716fd348SMartin Matuska 
186*716fd348SMartin Matuska 	return (0);
187*716fd348SMartin Matuska }
188