xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/file/randwritecomp.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2716fd348SMartin Matuska /*
3716fd348SMartin Matuska  * This file and its contents are supplied under the terms of the
4716fd348SMartin Matuska  * Common Development and Distribution License ("CDDL"), version 1.0.
5716fd348SMartin Matuska  * You may only use this file in accordance with the terms of version
6716fd348SMartin Matuska  * 1.0 of the CDDL.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * A full copy of the text of the CDDL should have accompanied this
9716fd348SMartin Matuska  * source.  A copy of the CDDL is also available via the Internet at
10716fd348SMartin Matuska  * http://www.illumos.org/license/CDDL.
11716fd348SMartin Matuska  */
12716fd348SMartin Matuska 
13716fd348SMartin Matuska /*
14716fd348SMartin Matuska  * Copyright (c) 2017 by Delphix. All rights reserved.
15716fd348SMartin Matuska  */
16716fd348SMartin Matuska 
17716fd348SMartin Matuska #include <stdint.h>
18716fd348SMartin Matuska #include <string.h>
19716fd348SMartin Matuska #include "file_common.h"
20716fd348SMartin Matuska 
21716fd348SMartin Matuska /*
22716fd348SMartin Matuska  * The following sample was derived from real-world data
23716fd348SMartin Matuska  * of a production Oracle database.
24716fd348SMartin Matuska  */
25716fd348SMartin Matuska static const uint64_t size_distribution[] = {
26716fd348SMartin Matuska 	0,
27716fd348SMartin Matuska 	1499018,
28716fd348SMartin Matuska 	352084,
29716fd348SMartin Matuska 	1503485,
30716fd348SMartin Matuska 	4206227,
31716fd348SMartin Matuska 	5626657,
32716fd348SMartin Matuska 	5387001,
33716fd348SMartin Matuska 	3733756,
34716fd348SMartin Matuska 	2233094,
35716fd348SMartin Matuska 	874652,
36716fd348SMartin Matuska 	238635,
37716fd348SMartin Matuska 	81434,
38716fd348SMartin Matuska 	33357,
39716fd348SMartin Matuska 	13106,
40716fd348SMartin Matuska 	2009,
41716fd348SMartin Matuska 	1,
42716fd348SMartin Matuska 	23660,
43716fd348SMartin Matuska };
44716fd348SMartin Matuska 
45716fd348SMartin Matuska 
46716fd348SMartin Matuska static uint64_t distribution_n;
47716fd348SMartin Matuska 
48716fd348SMartin Matuska static uint8_t randbuf[BLOCKSZ];
49716fd348SMartin Matuska 
50716fd348SMartin Matuska static void
rwc_pwrite(int fd,const void * buf,size_t nbytes,off_t offset)51716fd348SMartin Matuska rwc_pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
52716fd348SMartin Matuska {
53716fd348SMartin Matuska 	size_t nleft = nbytes;
54716fd348SMartin Matuska 	ssize_t nwrite = 0;
55716fd348SMartin Matuska 
56716fd348SMartin Matuska 	nwrite = pwrite(fd, buf, nbytes, offset);
57716fd348SMartin Matuska 	if (nwrite < 0) {
58716fd348SMartin Matuska 		perror("pwrite");
59716fd348SMartin Matuska 		exit(EXIT_FAILURE);
60716fd348SMartin Matuska 	}
61716fd348SMartin Matuska 
62716fd348SMartin Matuska 	nleft -= nwrite;
63716fd348SMartin Matuska 	if (nleft != 0) {
64716fd348SMartin Matuska 		(void) fprintf(stderr, "warning: pwrite: "
65716fd348SMartin Matuska 		    "wrote %zu out of %zu bytes\n",
66716fd348SMartin Matuska 		    (nbytes - nleft), nbytes);
67716fd348SMartin Matuska 	}
68716fd348SMartin Matuska }
69716fd348SMartin Matuska 
70716fd348SMartin Matuska static void
fillbuf(char * buf)71716fd348SMartin Matuska fillbuf(char *buf)
72716fd348SMartin Matuska {
73716fd348SMartin Matuska 	uint64_t rv = lrand48() % distribution_n;
74716fd348SMartin Matuska 	uint64_t sum = 0;
75716fd348SMartin Matuska 
76716fd348SMartin Matuska 	uint64_t i;
77716fd348SMartin Matuska 	for (i = 0;
78716fd348SMartin Matuska 	    i < sizeof (size_distribution) / sizeof (size_distribution[0]);
79716fd348SMartin Matuska 	    i++) {
80716fd348SMartin Matuska 		sum += size_distribution[i];
81716fd348SMartin Matuska 		if (rv < sum)
82716fd348SMartin Matuska 			break;
83716fd348SMartin Matuska 	}
84716fd348SMartin Matuska 
85716fd348SMartin Matuska 	memcpy(buf, randbuf, BLOCKSZ);
86716fd348SMartin Matuska 	if (i == 0)
87716fd348SMartin Matuska 		memset(buf, 0, BLOCKSZ - 10);
88716fd348SMartin Matuska 	else if (i < 16)
89716fd348SMartin Matuska 		memset(buf, 0, BLOCKSZ - i * 512 + 256);
90716fd348SMartin Matuska 	/*LINTED: E_BAD_PTR_CAST_ALIGN*/
91716fd348SMartin Matuska 	((uint32_t *)buf)[0] = lrand48();
92716fd348SMartin Matuska }
93716fd348SMartin Matuska 
94716fd348SMartin Matuska static void
exit_usage(void)95716fd348SMartin Matuska exit_usage(void)
96716fd348SMartin Matuska {
97716fd348SMartin Matuska 	(void) puts("usage: randwritecomp [-s] file [nwrites]");
98716fd348SMartin Matuska 	exit(EXIT_FAILURE);
99716fd348SMartin Matuska }
100716fd348SMartin Matuska 
101716fd348SMartin Matuska static void
sequential_writes(int fd,char * buf,uint64_t nblocks,int64_t n)102716fd348SMartin Matuska sequential_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
103716fd348SMartin Matuska {
104716fd348SMartin Matuska 	for (int64_t i = 0; n == -1 || i < n; i++) {
105716fd348SMartin Matuska 		fillbuf(buf);
106716fd348SMartin Matuska 
107716fd348SMartin Matuska 		static uint64_t j = 0;
108716fd348SMartin Matuska 		if (j == 0)
109716fd348SMartin Matuska 			j = lrand48() % nblocks;
110716fd348SMartin Matuska 		rwc_pwrite(fd, buf, BLOCKSZ, j * BLOCKSZ);
111716fd348SMartin Matuska 		j++;
112716fd348SMartin Matuska 		if (j >= nblocks)
113716fd348SMartin Matuska 			j = 0;
114716fd348SMartin Matuska 	}
115716fd348SMartin Matuska }
116716fd348SMartin Matuska 
117716fd348SMartin Matuska static void
random_writes(int fd,char * buf,uint64_t nblocks,int64_t n)118716fd348SMartin Matuska random_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
119716fd348SMartin Matuska {
120716fd348SMartin Matuska 	for (int64_t i = 0; n == -1 || i < n; i++) {
121716fd348SMartin Matuska 		fillbuf(buf);
122716fd348SMartin Matuska 		rwc_pwrite(fd, buf, BLOCKSZ, (lrand48() % nblocks) * BLOCKSZ);
123716fd348SMartin Matuska 	}
124716fd348SMartin Matuska }
125716fd348SMartin Matuska 
126716fd348SMartin Matuska int
main(int argc,char * argv[])127716fd348SMartin Matuska main(int argc, char *argv[])
128716fd348SMartin Matuska {
129716fd348SMartin Matuska 	int fd, err;
130716fd348SMartin Matuska 	char *filename = NULL;
131716fd348SMartin Matuska 	char buf[BLOCKSZ];
132716fd348SMartin Matuska 	struct stat ss;
133716fd348SMartin Matuska 	uint64_t nblocks;
134716fd348SMartin Matuska 	int64_t n = -1;
135716fd348SMartin Matuska 	int sequential = 0;
136716fd348SMartin Matuska 
137716fd348SMartin Matuska 	if (argc < 2)
138716fd348SMartin Matuska 		exit_usage();
139716fd348SMartin Matuska 
140716fd348SMartin Matuska 	argv++;
141716fd348SMartin Matuska 	if (strcmp("-s", argv[0]) == 0) {
142716fd348SMartin Matuska 		sequential = 1;
143716fd348SMartin Matuska 		argv++;
144716fd348SMartin Matuska 	}
145716fd348SMartin Matuska 
146716fd348SMartin Matuska 	if (argv[0] == NULL)
147716fd348SMartin Matuska 		exit_usage();
148716fd348SMartin Matuska 	else
149716fd348SMartin Matuska 		filename = argv[0];
150716fd348SMartin Matuska 
151716fd348SMartin Matuska 	argv++;
152716fd348SMartin Matuska 	if (argv[0] != NULL)
153716fd348SMartin Matuska 		n = strtoull(argv[0], NULL, 0);
154716fd348SMartin Matuska 
155716fd348SMartin Matuska 	fd = open(filename, O_RDWR|O_CREAT, 0666);
156be181ee2SMartin Matuska 	if (fd == -1) {
157be181ee2SMartin Matuska 		(void) fprintf(stderr, "open(%s) failed: %s\n", filename,
158be181ee2SMartin Matuska 		    strerror(errno));
159be181ee2SMartin Matuska 		exit(EXIT_FAILURE);
160be181ee2SMartin Matuska 	}
161716fd348SMartin Matuska 	err = fstat(fd, &ss);
162716fd348SMartin Matuska 	if (err != 0) {
163716fd348SMartin Matuska 		(void) fprintf(stderr,
164716fd348SMartin Matuska 		    "error: fstat returned error code %d\n", err);
165716fd348SMartin Matuska 		exit(EXIT_FAILURE);
166716fd348SMartin Matuska 	}
167716fd348SMartin Matuska 
168716fd348SMartin Matuska 	nblocks = ss.st_size / BLOCKSZ;
169716fd348SMartin Matuska 	if (nblocks == 0) {
170716fd348SMartin Matuska 		(void) fprintf(stderr, "error: "
171716fd348SMartin Matuska 		    "file is too small (min allowed size is %d bytes)\n",
172716fd348SMartin Matuska 		    BLOCKSZ);
173716fd348SMartin Matuska 		exit(EXIT_FAILURE);
174716fd348SMartin Matuska 	}
175716fd348SMartin Matuska 
176716fd348SMartin Matuska 	srand48(getpid());
177716fd348SMartin Matuska 	for (int i = 0; i < BLOCKSZ; i++)
178716fd348SMartin Matuska 		randbuf[i] = lrand48();
179716fd348SMartin Matuska 
180716fd348SMartin Matuska 	distribution_n = 0;
181716fd348SMartin Matuska 	for (uint64_t i = 0;
182716fd348SMartin Matuska 	    i < sizeof (size_distribution) / sizeof (size_distribution[0]);
183716fd348SMartin Matuska 	    i++) {
184716fd348SMartin Matuska 		distribution_n += size_distribution[i];
185716fd348SMartin Matuska 	}
186716fd348SMartin Matuska 
187716fd348SMartin Matuska 	if (sequential)
188716fd348SMartin Matuska 		sequential_writes(fd, buf, nblocks, n);
189716fd348SMartin Matuska 	else
190716fd348SMartin Matuska 		random_writes(fd, buf, nblocks, n);
191716fd348SMartin Matuska 
192716fd348SMartin Matuska 	return (0);
193716fd348SMartin Matuska }
194