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