• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Copyright (c) International Business Machines Corp., 2001-2004
3  *
4  *   This program is free software;  you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  *   the GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program;  if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #define _LARGEFILE64_SOURCE
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <errno.h>
27 
28 #include "fh.h"
29 #include "util.h"
30 #include "ffsb.h"
31 #include "fileops.h"
32 #include "ffsb_op.h"
33 
do_stats(struct timeval * start,struct timeval * end,ffsb_thread_t * ft,ffsb_fs_t * fs,syscall_t sys)34 static void do_stats(struct timeval *start, struct timeval *end,
35 		     ffsb_thread_t * ft, ffsb_fs_t * fs, syscall_t sys)
36 {
37 	struct timeval diff;
38 	uint32_t value = 0;
39 
40 	if (!ft && !fs)
41 		return;
42 
43 	timersub(end, start, &diff);
44 
45 	value = 1000000 * diff.tv_sec + diff.tv_usec;
46 
47 	if (ft && ft_needs_stats(ft, sys))
48 		ft_add_stat(ft, sys, value);
49 	if (fs && fs_needs_stats(fs, sys))
50 		fs_add_stat(fs, sys, value);
51 }
52 
fop_bench(ffsb_fs_t * fs,unsigned opnum)53 void fop_bench(ffsb_fs_t * fs, unsigned opnum)
54 {
55 	fs_set_opdata(fs, fs_get_datafiles(fs), opnum);
56 }
57 
fop_age(ffsb_fs_t * fs,unsigned opnum)58 void fop_age(ffsb_fs_t * fs, unsigned opnum)
59 {
60 	fs_set_opdata(fs, fs_get_agefiles(fs), opnum);
61 }
62 
readfile_helper(int fd,uint64_t size,uint32_t blocksize,char * buf,ffsb_thread_t * ft,ffsb_fs_t * fs)63 static unsigned readfile_helper(int fd, uint64_t size, uint32_t blocksize,
64 				char *buf, ffsb_thread_t * ft, ffsb_fs_t * fs)
65 {
66 	int iterations, a;
67 	int last;
68 
69 	iterations = size / blocksize;
70 	last = size % blocksize;
71 
72 	for (a = 0; a < iterations; a++)
73 		fhread(fd, buf, blocksize, ft, fs);
74 	if (last)
75 		fhread(fd, buf, last, ft, fs);
76 	return iterations;
77 }
78 
get_random_offset(randdata_t * rd,uint64_t filesize,int aligned)79 static uint64_t get_random_offset(randdata_t * rd, uint64_t filesize,
80 				  int aligned)
81 {
82 	if (!aligned)
83 		return getllrandom(rd, filesize);
84 
85 	filesize /= 4096;
86 	return getllrandom(rd, filesize) * 4096;
87 }
88 
ffsb_readfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)89 void ffsb_readfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
90 {
91 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
92 	struct ffsb_file *curfile = NULL;
93 
94 	int fd;
95 	uint64_t filesize;
96 
97 	char *buf = ft_getbuf(ft);
98 	int read_random = ft_get_read_random(ft);
99 	uint64_t read_size = ft_get_read_size(ft);
100 	uint32_t read_blocksize = ft_get_read_blocksize(ft);
101 	uint32_t read_skipsize = ft_get_read_skipsize(ft);
102 	int skip_reads = ft_get_read_skip(ft);
103 	struct randdata *rd = ft_get_randdata(ft);
104 
105 	uint64_t iterations = 0;
106 
107 	curfile = choose_file_reader(bf, rd);
108 	fd = fhopenread(curfile->name, ft, fs);
109 
110 	filesize = ffsb_get_filesize(curfile->name);
111 
112 	assert(filesize >= read_size);
113 
114 	/* Sequential read, starting at a random point */
115 	if (!read_random) {
116 		uint64_t range = filesize - read_size;
117 		uint64_t offset = 0;
118 		/* Skip or "stride" reads option */
119 		if (skip_reads) {
120 			unsigned i, last;
121 			uint64_t minfilesize;
122 			iterations = read_size / read_blocksize;
123 			last = read_size % read_blocksize;
124 
125 			/* Double check that the user hasn't specified
126 			 * a read_size that is too large when combined
127 			 * with the seeks
128 			 */
129 			if (last)
130 				minfilesize = last + iterations *
131 				    (read_blocksize + read_skipsize);
132 			else
133 				minfilesize = read_blocksize + iterations - 1 *
134 				    (read_blocksize + read_skipsize);
135 
136 			if (minfilesize > filesize) {
137 				printf("Error: read size %llu bytes too big "
138 				       "w/ skipsize %u and blocksize %u,"
139 				       " for file of size %llu bytes\n"
140 				       " aborting\n\n", read_size,
141 				       read_skipsize, read_blocksize, filesize);
142 				printf("minimum file size must be at least "
143 				       " %llu bytes\n", minfilesize);
144 				exit(1);
145 			}
146 
147 			for (i = 0; i < iterations; i++) {
148 				fhread(fd, buf, read_blocksize, ft, fs);
149 				fhseek(fd, (uint64_t) read_skipsize, SEEK_CUR,
150 				       ft, fs);
151 			}
152 			if (last) {
153 				fhread(fd, buf, (uint64_t) last, ft, fs);
154 				iterations++;
155 			}
156 		} else {
157 			/* Regular sequential reads */
158 			if (range) {
159 				offset = get_random_offset(rd, range,
160 							   fs_get_alignio(fs));
161 				fhseek(fd, offset, SEEK_SET, ft, fs);
162 			}
163 			iterations = readfile_helper(fd, read_size,
164 						     read_blocksize, buf,
165 						     ft, fs);
166 		}
167 	} else {
168 		/* Randomized read */
169 		uint64_t range = filesize - read_blocksize;
170 		int i;
171 
172 		iterations = read_size / read_blocksize;
173 
174 		for (i = 0; i < iterations; i++) {
175 			uint64_t offset = get_random_offset(rd, range,
176 							    fs_get_alignio(fs));
177 			fhseek(fd, offset, SEEK_SET, ft, fs);
178 			fhread(fd, buf, read_blocksize, ft, fs);
179 		}
180 	}
181 
182 	unlock_file_reader(curfile);
183 	fhclose(fd, ft, fs);
184 
185 	ft_incr_op(ft, opnum, iterations, read_size);
186 	ft_add_readbytes(ft, read_size);
187 }
188 
189 /* Just like ffsb_readfile but we read the whole file from start to
190  * finish regardless of file size.
191  */
ffsb_readall(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)192 void ffsb_readall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
193 {
194 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
195 	struct ffsb_file *curfile = NULL;
196 	int fd;
197 	uint64_t filesize;
198 
199 	char *buf = ft_getbuf(ft);
200 	uint32_t read_blocksize = ft_get_read_blocksize(ft);
201 	struct randdata *rd = ft_get_randdata(ft);
202 
203 	unsigned iterations = 0;
204 
205 	curfile = choose_file_reader(bf, rd);
206 	fd = fhopenread(curfile->name, ft, fs);
207 
208 	filesize = ffsb_get_filesize(curfile->name);
209 	iterations = readfile_helper(fd, filesize, read_blocksize, buf, ft, fs);
210 
211 	unlock_file_reader(curfile);
212 	fhclose(fd, ft, fs);
213 
214 	ft_incr_op(ft, opnum, iterations, filesize);
215 	ft_add_readbytes(ft, filesize);
216 }
217 
218 /* Shared core between ffsb_writefile and ffsb_writefile_fsync.*/
219 
ffsb_writefile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)220 static unsigned ffsb_writefile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
221 				    unsigned opnum, uint64_t * filesize_ret,
222 				    int fsync_file)
223 {
224 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
225 	struct ffsb_file *curfile = NULL;
226 
227 	int fd;
228 	uint64_t filesize;
229 
230 	char *buf = ft_getbuf(ft);
231 	int write_random = ft_get_write_random(ft);
232 	uint32_t write_size = ft_get_write_size(ft);
233 	uint32_t write_blocksize = ft_get_write_blocksize(ft);
234 	struct randdata *rd = ft_get_randdata(ft);
235 	unsigned iterations = 0;
236 
237 	curfile = choose_file_reader(bf, rd);
238 	fd = fhopenwrite(curfile->name, ft, fs);
239 
240 	filesize = ffsb_get_filesize(curfile->name);
241 
242 	assert(filesize >= write_size);
243 
244 	/* Sequential write, starting at a random point  */
245 	if (!write_random) {
246 		uint64_t range = filesize - write_size;
247 		uint64_t offset = 0;
248 		if (range) {
249 			offset = get_random_offset(rd, range,
250 						   fs_get_alignio(fs));
251 			fhseek(fd, offset, SEEK_SET, ft, fs);
252 		}
253 		iterations = writefile_helper(fd, write_size, write_blocksize,
254 					      buf, ft, fs);
255 	} else {
256 		/* Randomized write */
257 		uint64_t range = filesize - write_blocksize;
258 		int i;
259 		iterations = write_size / write_blocksize;
260 
261 		for (i = 0; i < iterations; i++) {
262 			uint64_t offset = get_random_offset(rd, range,
263 							    fs_get_alignio(fs));
264 			fhseek(fd, offset, SEEK_SET, ft, fs);
265 			fhwrite(fd, buf, write_blocksize, ft, fs);
266 		}
267 	}
268 
269 	if (fsync_file) {
270 		if (fsync(fd)) {
271 			perror("fsync");
272 			printf("aborting\n");
273 			exit(1);
274 		}
275 	}
276 	unlock_file_reader(curfile);
277 	fhclose(fd, ft, fs);
278 	*filesize_ret = filesize;
279 	return iterations;
280 }
281 
ffsb_writefile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)282 void ffsb_writefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
283 {
284 	unsigned iterations;
285 	uint64_t filesize;
286 
287 	iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 0);
288 	ft_incr_op(ft, opnum, iterations, filesize);
289 	ft_add_writebytes(ft, filesize);
290 }
291 
ffsb_writefile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)292 void ffsb_writefile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
293 {
294 	unsigned iterations;
295 	uint64_t filesize;
296 
297 	iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 1);
298 	ft_incr_op(ft, opnum, iterations, filesize);
299 	ft_add_writebytes(ft, filesize);
300 }
301 
302 /* Shared core between ffsb_writeall and ffsb_writeall_fsync.*/
303 
ffsb_writeall_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)304 static unsigned ffsb_writeall_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
305 				   unsigned opnum, uint64_t * filesize_ret,
306 				   int fsync_file)
307 {
308 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
309 	struct ffsb_file *curfile = NULL;
310 	int fd;
311 	uint64_t filesize;
312 
313 	char *buf = ft_getbuf(ft);
314 	uint32_t write_blocksize = ft_get_write_blocksize(ft);
315 	struct randdata *rd = ft_get_randdata(ft);
316 
317 	unsigned iterations = 0;
318 
319 	curfile = choose_file_reader(bf, rd);
320 	fd = fhopenwrite(curfile->name, ft, fs);
321 
322 	filesize = ffsb_get_filesize(curfile->name);
323 	iterations = writefile_helper(fd, filesize, write_blocksize, buf,
324 				      ft, fs);
325 	if (fsync_file)
326 		if (fsync(fd)) {
327 			perror("fsync");
328 			printf("aborting\n");
329 			exit(1);
330 		}
331 
332 	unlock_file_reader(curfile);
333 	fhclose(fd, ft, fs);
334 	*filesize_ret = filesize;
335 	return iterations;
336 }
337 
338 /* Just like ffsb_writefile but we write the whole file from start to
339  * finish regardless of file size
340  */
ffsb_writeall(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)341 void ffsb_writeall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
342 {
343 	unsigned iterations;
344 	uint64_t filesize;
345 
346 	iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 0);
347 	ft_incr_op(ft, opnum, iterations, filesize);
348 	ft_add_writebytes(ft, filesize);
349 }
350 
ffsb_writeall_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)351 void ffsb_writeall_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
352 {
353 	unsigned iterations;
354 	uint64_t filesize;
355 
356 	iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 1);
357 	ft_incr_op(ft, opnum, iterations, filesize);
358 	ft_add_writebytes(ft, filesize);
359 }
360 
ffsb_appendfile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)361 static unsigned ffsb_appendfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
362 				     unsigned opnum, uint64_t * filesize_ret,
363 				     int fsync_file)
364 {
365 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
366 	struct ffsb_file *curfile;
367 
368 	int fd;
369 
370 	char *buf = ft_getbuf(ft);
371 	uint32_t write_size = ft_get_write_size(ft);
372 	uint32_t write_blocksize = ft_get_write_blocksize(ft);
373 	struct randdata *rd = ft_get_randdata(ft);
374 	unsigned iterations = 0;
375 
376 	curfile = choose_file_reader(bf, rd);
377 	fd = fhopenappend(curfile->name, ft, fs);
378 
379 	unlock_file_reader(curfile);
380 
381 	curfile->size += (uint64_t) write_size;
382 
383 	iterations = writefile_helper(fd, write_size, write_blocksize, buf,
384 				      ft, fs);
385 	if (fsync_file)
386 		if (fsync(fd)) {
387 			perror("fsync");
388 			printf("aborting\n");
389 			exit(1);
390 		}
391 
392 	fhclose(fd, ft, fs);
393 	*filesize_ret = write_size;
394 	return iterations;
395 }
396 
ffsb_appendfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)397 void ffsb_appendfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
398 {
399 	unsigned iterations;
400 	uint64_t filesize;
401 
402 	iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 0);
403 	ft_incr_op(ft, opnum, iterations, filesize);
404 	ft_add_writebytes(ft, filesize);
405 }
406 
ffsb_appendfile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)407 void ffsb_appendfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
408 {
409 	unsigned iterations;
410 	uint64_t filesize;
411 
412 	iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 1);
413 	ft_incr_op(ft, opnum, iterations, filesize);
414 	ft_add_writebytes(ft, filesize);
415 }
416 
ffsb_createfile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)417 static unsigned ffsb_createfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
418 				     unsigned opnum, uint64_t * filesize_ret,
419 				     int fsync_file)
420 {
421 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
422 	struct ffsb_file *newfile = NULL;
423 
424 	int fd;
425 	uint64_t size;
426 
427 	char *buf = ft_getbuf(ft);
428 	uint32_t write_blocksize = ft_get_write_blocksize(ft);
429 	struct randdata *rd = ft_get_randdata(ft);
430 	unsigned iterations = 0;
431 
432 	if (fs->num_weights) {
433 		int num = 1 + getrandom(rd, fs->sum_weights);
434 		int curop = 0;
435 
436 		while (fs->size_weights[curop].weight < num) {
437 			num -= fs->size_weights[curop].weight;
438 			curop++;
439 		}
440 		size = fs->size_weights[curop].size;
441 	} else {
442 		uint64_t range =
443 		    fs_get_max_filesize(fs) - fs_get_min_filesize(fs);
444 		size = fs_get_min_filesize(fs);
445 		if (range != 0)
446 			size += getllrandom(rd, range);
447 	}
448 
449 	newfile = add_file(bf, size, rd);
450 	fd = fhopencreate(newfile->name, ft, fs);
451 	iterations = writefile_helper(fd, size, write_blocksize, buf, ft, fs);
452 
453 	if (fsync_file)
454 		if (fsync(fd)) {
455 			perror("fsync");
456 			printf("aborting\n");
457 			exit(1);
458 		}
459 
460 	fhclose(fd, ft, fs);
461 	unlock_file_writer(newfile);
462 	*filesize_ret = size;
463 	return iterations;
464 }
465 
ffsb_createfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)466 void ffsb_createfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
467 {
468 	unsigned iterations;
469 	uint64_t filesize;
470 
471 	iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 0);
472 	ft_incr_op(ft, opnum, iterations, filesize);
473 	ft_add_writebytes(ft, filesize);
474 }
475 
ffsb_createfile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)476 void ffsb_createfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
477 {
478 	unsigned iterations;
479 	uint64_t filesize;
480 
481 	iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 1);
482 	ft_incr_op(ft, opnum, iterations, filesize);
483 	ft_add_writebytes(ft, filesize);
484 }
485 
ffsb_deletefile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)486 void ffsb_deletefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
487 {
488 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
489 	struct ffsb_file *curfile = NULL;
490 	randdata_t *rd = ft_get_randdata(ft);
491 	struct timeval start, end;
492 	int need_stats = ft_needs_stats(ft, SYS_UNLINK) ||
493 	    fs_needs_stats(fs, SYS_UNLINK);
494 
495 	curfile = choose_file_writer(bf, rd);
496 	remove_file(bf, curfile);
497 
498 	if (need_stats)
499 		gettimeofday(&start, NULL);
500 
501 	if (unlink(curfile->name) == -1) {
502 		printf("error deleting %s in deletefile\n", curfile->name);
503 		perror("deletefile");
504 		exit(0);
505 	}
506 
507 	if (need_stats) {
508 		gettimeofday(&end, NULL);
509 		do_stats(&start, &end, ft, fs, SYS_UNLINK);
510 	}
511 
512 	rw_unlock_write(&curfile->lock);
513 
514 	ft_incr_op(ft, opnum, 1, 0);
515 }
516 
ffsb_open_close(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)517 void ffsb_open_close(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
518 {
519 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
520 	struct ffsb_file *curfile = NULL;
521 	randdata_t *rd = ft_get_randdata(ft);
522 	int fd;
523 
524 	curfile = choose_file_reader(bf, rd);
525 	fd = fhopenread(curfile->name, ft, fs);
526 	fhclose(fd, ft, fs);
527 	unlock_file_reader(curfile);
528 	ft_incr_op(ft, opnum, 1, 0);
529 }
530 
ffsb_stat(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)531 void ffsb_stat(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
532 {
533 	struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
534 	struct ffsb_file *curfile = NULL;
535 	randdata_t *rd = ft_get_randdata(ft);
536 
537 	curfile = choose_file_reader(bf, rd);
538 	fhstat(curfile->name, ft, fs);
539 	unlock_file_reader(curfile);
540 
541 	ft_incr_op(ft, opnum, 1, 0);
542 }
543