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