1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* 2009-07-30 Paul McCullagh
36
#include <sys/types.h>
48
* Define this if I/O should pause.
50
//#define SHOULD_PAUSE
51
//#define PERIODIC_FLUSH
53
#define SIM_RECORD_SIZE 221
55
#define SIM_FILE_SIZE (256*1024*1024)
56
#define SIM_WRITE_AMOUNT (1*1024*1024)
57
//#define SIM_WRITE_AMOUNT (221 * 100)
59
#define SIM_FILE_SIZE ((off_t) (2L*1024L*1024L*1024L))
60
#define SIM_WRITE_AMOUNT (8*1024*1024)
62
#define SIM_FLUSH_THRESHOLD (2*1024*1024)
63
#define SIM_PAUSE_THRESHOLD (10*1024*1024)
66
#undef SIM_PAUSE_THRESHOLD
67
#define SIM_PAUSE_THRESHOLD 0
70
#ifndef PERIODIC_FLUSH
71
#undef SIM_FLUSH_THRESHOLD
72
#define SIM_FLUSH_THRESHOLD 0
75
#define my_time unsigned long long
76
#define u_long unsigned long
80
typedef struct SortedRec {
86
#define SORTED_MAX_RECORDS 10000
87
#define SORTED_DATA_SIZE (SORTED_MAX_RECORDS * SIM_RECORD_SIZE)
88
#define SORTED_BUFFER_SIZE (256*1024)
90
typedef struct RewriteRec {
95
#define REWRITE_MAX_RECORDS 1000
96
/* This is the maximum distance between to blocks that
97
* will cause the blocks to be combined and written
101
#define REWRITE_BLOCK_DISTANCE (64*1024)
103
#define REWRITE_BLOCK_DISTANCE (1024*1024)
106
#define REWRITE_RECORD_LIMIT 256
108
typedef struct File {
111
int fi_monitor_index;
112
char fi_file_path[200];
113
char fi_test_name[200];
114
char fi_monitor_name[10];
115
int fi_monitor_active;
123
my_time last_flush_time;
124
u_long last_flush_count;
130
off_t last_block_offset;
131
size_t last_block_size;
132
u_long block_write_count;
134
my_time last_write_time;
135
u_long last_write_count;
141
my_time last_read_time;
142
u_long last_read_count;
144
/* Sorted file I/O */
146
SortedRec sf_records[SORTED_MAX_RECORDS];
149
char sf_data[SORTED_DATA_SIZE];
150
char sf_buffer[SORTED_BUFFER_SIZE];
153
off_t rs_min_block_offset;
154
off_t rs_max_block_offset;
155
size_t rs_flush_block_total;
157
RewriteRec rs_records[REWRITE_MAX_RECORDS];
159
void (*fi_write)(struct File *f, void *block, size_t size, off_t start);
160
void (*fi_sync)(struct File *f);
161
void (*fi_write_all)(struct File *f);
164
/* ------------------- TIMING ------------------- */
166
static my_time my_clock(void)
168
static my_time my_start_clock = 0;
172
gettimeofday(&tv, NULL);
173
now = (my_time) tv.tv_sec * (my_time) 1000000 + tv.tv_usec;
175
return now - my_start_clock;
176
my_start_clock = now;
180
/* ------------------- ERRORS ------------------- */
182
static void print_error(char *file, int err)
184
printf("ERROR %s: %s\n", file, strerror(err));
187
static void error_exit(char *file, int err)
189
print_error(file, err);
193
static void fatal_error(char *message)
195
printf("%s", message);
199
/* ------------------- ERRORS ------------------- */
201
static void *my_bsearch(void *key, register const void *base, size_t count, size_t size, size_t *idx, int (*compare)(void *key, void *rec))
204
register size_t guess;
209
guess = (i + count - 1) >> 1;
210
r = compare(key, ((char *) base) + guess * size);
213
return ((char *) base) + guess * size;
225
/* ------------------- MONITORING THREAD ------------------- */
227
/* Monitor file types: */
230
static int monitor_file_count;
231
static int monitor_files_in_use;
232
static int monitor_running;
233
static File *monitor_files[MAX_FILES];
235
static void monitor_file(File *f, const char *test_name, const char *monitor_name)
237
if (monitor_file_count == MAX_FILES)
238
fatal_error("Too many files to monitor");
239
monitor_files[monitor_file_count] = f;
240
f->fi_monitor_index = monitor_file_count;
241
sprintf(f->fi_file_path, "test-data-%d", (int) monitor_file_count);
242
strcpy(f->fi_test_name, test_name);
243
strcpy(f->fi_monitor_name, monitor_name);
244
monitor_file_count++;
245
f->fi_monitor_active = TRUE;
246
monitor_files_in_use++;
249
static void unmonitor_file(File *f)
251
/* Wait for the last activity to be reported! */
252
while (monitor_running && f->fi_monitor_active) {
255
monitor_files_in_use--;
256
monitor_files[f->fi_monitor_index] = NULL;
259
static void print_header()
265
for (i=0; i<MAX_FILES; i++) {
266
if ((f = monitor_files[i])) {
267
printf("%7s %5s %9s %5s %9s %5s ", f->fi_monitor_name, f->fi_monitor_name, f->fi_monitor_name, f->fi_monitor_name, f->fi_monitor_name, f->fi_monitor_name);
272
for (i=0; i<MAX_FILES; i++) {
273
if ((f = monitor_files[i])) {
274
printf("%7s %5s %9s %5s %9s %5s ", "flush", "ftime", "write", "wtime", "read", "rtime");
280
static void *iotest_monitor(void *data)
286
my_time now, fstart, wstart, rstart;
290
my_time curr_flush_time;
291
u_long curr_flush_count;
292
my_time curr_write_time;
293
u_long curr_write_count;
294
my_time curr_read_time;
295
u_long curr_read_count;
304
monitor_running = TRUE;
309
if (!monitor_files_in_use)
312
if ((row % 20) == 0 || version != monitor_file_count) {
313
version = monitor_file_count;
317
printf("%4.0f ", ((double) curr - (double) last) / (double) 1000);
319
for (i=0; i<MAX_FILES; i++) {
320
if ((f = monitor_files[i])) {
321
curr_flush_time = f->flush_time;
322
fstart = f->flush_start;
323
curr_write_time = f->write_time;
324
wstart = f->write_start;
325
curr_read_time = f->read_time;
326
rstart = f->read_start;
330
curr_flush_time += now - fstart;
331
flush_time = curr_flush_time - f->last_flush_time;
332
f->last_flush_time = curr_flush_time;
334
curr_flush_count = f->flush_count;
335
flush_count = curr_flush_count - f->last_flush_count;
336
f->last_flush_count = curr_flush_count;
339
curr_write_time += now - wstart;
340
write_time = curr_write_time - f->last_write_time;
341
f->last_write_time = curr_write_time;
343
curr_write_count = f->write_count;
344
write_count = curr_write_count - f->last_write_count;
345
f->last_write_count = curr_write_count;
348
curr_read_time += now - rstart;
349
read_time = curr_read_time - f->last_read_time;
350
f->last_read_time = curr_read_time;
352
curr_read_count = f->read_count;
353
read_count = curr_read_count - f->last_read_count;
354
f->last_read_count = curr_read_count;
356
printf("%7lu %5.0f %9.2f %5.0f %9.2f %5.0f ", flush_count, (double) flush_time / (double) 1000,
357
(double) write_count / (double) 1024, (double) write_time / (double) 1000,
358
(double) read_count / (double) 1024, (double) read_time / (double) 1000);
359
if (flush_count || flush_time || write_count || write_time || read_count || read_time) {
360
f->fi_monitor_active = TRUE;
364
f->fi_monitor_active = FALSE;
372
/* Leave the loop, only when there is no more activity. */
373
if (!monitor_running && !activity)
378
} while (my_clock() - curr < 1000000);
385
/* ------------------- BASIC FILE I/O ------------------- */
391
#define XT_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
393
static void create_file(File *f, size_t size, int type)
402
if (!(block = (char *) malloc(512)))
403
error_exit(f->fi_file_path, errno);
404
for (i=0; i<512; i++)
407
fd = open(f->fi_file_path, O_CREAT | O_RDWR, XT_MASK);
409
error_exit(f->fi_file_path, errno);
411
eof = lseek(fd, 0, SEEK_END);
412
if (type == PREFILL && size == eof)
415
if (ftruncate(fd, 0) == -1)
416
error_exit(f->fi_file_path, errno);
418
if (type == SET_EOF) {
423
if (pwrite(fd, block, 512, offset) != 512)
424
error_exit(f->fi_file_path, errno);
432
if (pwrite(fd, block, tfer, offset) != tfer)
433
error_exit(f->fi_file_path, errno);
440
error_exit(f->fi_file_path, errno);
448
static void delete_file(char *file)
454
static void write_file(File *f, void *block, size_t size, off_t offset)
460
if (pwrite(f->file_fh, block, size, offset) != size)
461
error_exit(f->fi_file_path, errno);
464
f->write_time += (t - s);
465
f->write_count += size;
467
/* Does this block touch the previous block? */
468
if (f->last_block_offset == -1 ||
469
offset < f->last_block_offset ||
470
offset > f->last_block_offset + f->last_block_size)
471
/* If not, it is a new block (with a gap): */
472
f->block_write_count++;
473
f->last_block_offset = offset;
474
f->last_block_size = size;
477
static void read_file(File *f, void *block, size_t size, off_t start)
483
if (pread(f->file_fh, block, size, start) != size)
484
error_exit(f->fi_file_path, errno);
487
f->read_time += (t - s);
488
f->read_count += size;
491
static void sync_file(File *f)
497
if (fsync(f->file_fh) == -1)
498
error_exit(f->fi_file_path, errno);
501
f->flush_time += t - s;
505
static void new_file(File **ret_f, const char *test_name, const char *monitor_name)
509
f = malloc(sizeof(File));
510
memset(f, 0, sizeof(File));
511
f->last_block_offset = (off_t) -1;
512
f->rs_min_block_offset = (off_t) -1;
514
monitor_file(f, test_name, monitor_name);
515
f->fi_write = write_file;
516
f->fi_sync = sync_file;
521
static void open_file(File *f)
523
f->file_fh = open(f->fi_file_path, O_RDWR, 0);
524
if (f->file_fh == -1)
525
error_exit(f->fi_file_path, errno);
527
f->total_time = my_clock();
530
static void close_file(File *f)
533
f->total_time = my_clock() - f->total_time;
534
if (f->file_fh != -1)
539
printf("\n=* TEST: %s (%s) *=\n", f->fi_test_name, f->fi_monitor_name);
540
printf("Written K: %.2f\n", (double) f->write_count / (double) 1024);
541
printf("Run time: %.2f ms\n", (double) f->total_time / (double) 1000);
542
if (f->rs_flush_block_total > 0)
543
printf("Flush blks: %lu\n", f->rs_flush_block_total);
544
if (f->write_count > 0) {
545
printf("Tot blocks: %lu\n", f->block_write_count);
546
printf("Seek time: %.3f ms\n", (double) f->flush_time / (double) f->block_write_count / (double) 1000);
550
printf("Write K/s: %.2f\n", (double) f->write_count * (double) 1000000 / (double) 1024 / (double) f->write_time);
552
printf("Read K/s: %.2f\n", (double) f->read_count * (double) 1000000 / (double) 1024 / (double) f->read_time);
554
printf("Flush K/s: %.2f\n", (double) f->write_count * (double) 1000000 / (double) 1024 / (double) f->flush_time);
555
if (f->write_time + f->read_time + f->flush_time)
556
printf("Total K/s: %.2f\n", (double) f->write_count * (double) 1000000 / (double) 1024 / ((double) f->write_time + (double) f->read_time + (double) f->flush_time));
560
/* ------------------- SORTED I/O ------------------- */
562
/* Sort records before they are writing.
563
* Options are also added to write records,
564
* in large blocks. This requires reading the block
568
static int compare_rec(const void *a, const void *b)
570
SortedRec *ra = (SortedRec *) a;
571
SortedRec *rb = (SortedRec *) b;
573
if (ra->sr_offset == rb->sr_offset) {
574
if (ra->sr_order == rb->sr_order)
576
if (ra->sr_order < rb->sr_order)
580
if (ra->sr_offset < rb->sr_offset)
585
static void sorted_write_all(File *f)
590
qsort(f->sf_records, f->sf_rec_count, sizeof(SortedRec), compare_rec);
592
for (i=0; i<f->sf_rec_count; i++) {
593
write_file(f, rec->sr_data, SIM_RECORD_SIZE, rec->sr_offset);
602
static void sorted_write_rw_all(File *f)
609
qsort(f->sf_records, f->sf_rec_count, sizeof(SortedRec), compare_rec);
611
for (i=0; i<f->sf_rec_count; i++) {
614
offset = (rec->sr_offset / 1024) * 1024;
615
size = SORTED_BUFFER_SIZE;
616
if (offset+(off_t)size > SIM_FILE_SIZE)
617
size = (size_t) (SIM_FILE_SIZE - offset);
618
read_file(f, f->sf_buffer, size, offset);
621
if (rec->sr_offset >= offset && rec->sr_offset+SIM_RECORD_SIZE <= offset+size)
622
memcpy(&f->sf_buffer[rec->sr_offset - offset], rec->sr_data, SIM_RECORD_SIZE);
624
write_file(f, f->sf_buffer, size, offset);
636
static void sorted_write_rw_no_gaps_all(File *f)
643
qsort(f->sf_records, f->sf_rec_count, sizeof(SortedRec), compare_rec);
645
if (!f->sf_rec_count)
648
offset = (rec->sr_offset / 1024) * 1024;
649
for (i=0; i<f->sf_rec_count; i++) {
652
size = SORTED_BUFFER_SIZE;
653
if (offset+size > SIM_FILE_SIZE)
654
size = SIM_FILE_SIZE - offset;
655
read_file(f, f->sf_buffer, size, offset);
658
if (rec->sr_offset >= offset && rec->sr_offset+SIM_RECORD_SIZE <= offset+size)
659
memcpy(&f->sf_buffer[rec->sr_offset - offset], rec->sr_data, SIM_RECORD_SIZE);
661
write_file(f, f->sf_buffer, size, offset);
663
if (rec->sr_offset < offset)
664
offset = (rec->sr_offset / 1024) * 1024;
677
static void sorted_sync_file(File *f)
683
static void sorted_write_file(File *f, void *block, size_t size, off_t offset)
687
if (size != SIM_RECORD_SIZE)
690
if (f->sf_rec_count == SORTED_MAX_RECORDS ||
691
f->sf_alloc_pos + size > SORTED_DATA_SIZE) {
695
rec = &f->sf_records[f->sf_rec_count];
696
rec->sr_offset = offset;
697
rec->sr_order = f->sf_order;
698
rec->sr_data = &f->sf_data[f->sf_alloc_pos];
699
memcpy(rec->sr_data, block, size);
700
f->sf_alloc_pos += size;
705
/* ------------------- RE-WRITE FLUSH ------------------- */
707
/* The idea is that it is better to re-write the file
708
* sequentially, then allow the FS to write scattered
711
* This comes from the fact that seeking is a lot more
712
* expensive than sequential write.
715
static void rewrite_all_sync_file(File *f)
720
while (offset < SIM_FILE_SIZE) {
721
size = SORTED_BUFFER_SIZE;
722
if (offset + size > SIM_FILE_SIZE)
723
size = SIM_FILE_SIZE - offset;
724
read_file(f, f->sf_buffer, size, offset);
725
write_file(f, f->sf_buffer, size, offset);
732
static void rewrite_min_max_sync_file(File *f)
736
off_t eof = SIM_FILE_SIZE;
738
if (f->rs_min_block_offset != (off_t) -1)
739
offset = f->rs_min_block_offset / 1024 * 1024;
740
eof = (f->rs_max_block_offset + 1023) / 1024 * 1024;
741
if (eof > SIM_FILE_SIZE)
743
while (offset < eof) {
744
size = SORTED_BUFFER_SIZE;
745
if (offset + size > eof)
747
read_file(f, f->sf_buffer, size, offset);
748
write_file(f, f->sf_buffer, size, offset);
755
static void rewrite_min_max_write_file(File *f, void *block, size_t size, off_t offset)
759
write_file(f, block, size, offset);
761
/* Round up and down by 1K */
762
top_offset = offset + size;
763
offset = offset / 1024 * 1024;
764
top_offset = (top_offset + 1023) / 1024 * 1024;
765
size = (size_t) (top_offset - offset);
767
/* Calculate max and min and max offset: */
768
if (f->rs_min_block_offset == (off_t) -1 || offset < f->rs_min_block_offset)
769
f->rs_min_block_offset = offset;
770
if (offset + size > f->rs_max_block_offset)
771
f->rs_max_block_offset = offset + size;
774
static void rewrite_opt_rewrite_file(File *f)
782
/* Re-write all areas written: */
784
for (i=0; i<f->rs_rec_count; i++) {
786
offset = rec->rr_offset;
788
tfer = SORTED_BUFFER_SIZE;
789
if ((off_t) tfer > size)
791
read_file(f, f->sf_buffer, tfer, offset);
792
write_file(f, f->sf_buffer, tfer, offset);
799
f->rs_flush_block_total += f->rs_rec_count;
803
static int rewrite_opt_comp(void *k, void *r)
805
register off_t *key = (off_t *) k;
806
register RewriteRec *rec = (RewriteRec *) r;
808
if (*key == rec->rr_offset)
810
if (*key < rec->rr_offset)
815
static void rewrite_opt_sync_file(File *f)
817
rewrite_opt_rewrite_file(f);
821
static void rewrite_opt_write_file(File *f, void *block, size_t size, off_t offset)
827
write_file(f, block, size, offset);
829
/* Round up and down by 1K */
830
top_offset = offset + size;
831
offset = offset / 1024 * 1024;
832
top_offset = (top_offset + 1023) / 1024 * 1024;
833
size = (size_t) (top_offset - offset);
835
if ((rec = my_bsearch(&offset, f->rs_records, f->rs_rec_count, sizeof(RewriteRec), &idx, rewrite_opt_comp))) {
836
if ((off_t) size > rec->rr_size)
842
/* The offset is before the first entry. */
843
if (idx < f->rs_rec_count) {
844
/* There is a first entry: */
846
if (rec->rr_offset - (offset + size) < REWRITE_BLOCK_DISTANCE)
850
/* Add the first entry: */
854
/* Not the first entry: */
856
rec = f->rs_records + idx;
858
if (offset - (rec->rr_offset + rec->rr_size) < REWRITE_BLOCK_DISTANCE) {
859
/* Add to block on left: */
860
size = (offset + size) - rec->rr_offset;
861
if (size > rec->rr_size)
867
rec = f->rs_records + idx;
869
if (idx < f->rs_rec_count && rec->rr_offset - (offset + size) < REWRITE_BLOCK_DISTANCE)
873
if (f->rs_rec_count == REWRITE_MAX_RECORDS) {
874
rewrite_opt_rewrite_file(f);
877
rec = f->rs_records + idx;
878
memmove(rec+1, rec, (f->rs_rec_count - idx) * sizeof(RewriteRec));
879
rec->rr_offset = offset;
880
rec->rr_size = (off_t) size;
885
rec->rr_size += rec->rr_offset - offset;
886
if (size > rec->rr_size)
888
rec->rr_offset = offset;
891
if (idx+1 < f->rs_rec_count) {
892
/* There is a record right: */
893
if (rec->rr_offset + rec->rr_size + REWRITE_BLOCK_DISTANCE > (rec+1)->rr_offset) {
894
/* Merge and remove! */
895
size = (rec+1)->rr_size + ((rec+1)->rr_offset - rec->rr_offset);
896
if (size > rec->rr_size)
899
assert(f->rs_rec_count > idx);
900
memmove(rec+1, rec+2, (f->rs_rec_count - idx - 1) * sizeof(RewriteRec));
907
static void rewrite_limit_sync_file(File *f)
909
rewrite_opt_rewrite_file(f);
914
* This options is like opt but it limits the number of
915
* blocks that can be written.
917
static void rewrite_limit_write_file(File *f, void *block, size_t size, off_t offset)
921
/* There must always be room for one more: */
922
assert(f->rs_rec_count < REWRITE_RECORD_LIMIT);
923
rewrite_opt_write_file(f, block, size, offset);
924
if (f->rs_rec_count == REWRITE_RECORD_LIMIT) {
925
/* Consolidate 2 blocks that are closest to each other in other to
926
* make space for another block:
930
off_t min_gap = (off_t) -1;
933
for (i=0; i<f->rs_rec_count-1; i++) {
934
gap = (rec+1)->rr_offset - (rec->rr_offset + rec->rr_size);
935
if (min_gap == (off_t) -1 || gap < min_gap) {
942
/* Merge this with the next: */
943
rec = f->rs_records + idx;
944
size = (rec+1)->rr_size + ((rec+1)->rr_offset - rec->rr_offset);
945
if (size > rec->rr_size)
948
assert(f->rs_rec_count > idx);
949
memmove(rec+1, rec+2, (f->rs_rec_count - idx - 1) * sizeof(RewriteRec));
953
/* ------------------- SIMULATION I/O ------------------- */
956
static void random_read_bytes(File *f, off_t file_size, size_t size, size_t count, int print)
961
long x = (long) (file_size / (off_t) size), y;
963
block = (char *) malloc(size);
965
for (i=0; i<count; i++) {
967
offset = (off_t) y * (off_t) size;
968
if (offset+size > file_size) {
972
read_file(f, block, size, offset);
975
printf("%ld\n", (long) i);
982
static void read_write_bytes(File *f, off_t file_size)
987
while (file_size > 0) {
988
tfer = SORTED_BUFFER_SIZE;
989
if ((off_t) tfer > file_size)
990
tfer = (size_t) file_size;
991
read_file(f, f->sf_buffer, tfer, offset);
992
f->fi_write(f, f->sf_buffer, tfer, offset);
998
static void random_write_bytes(File *f, off_t file_size, size_t size, off_t amount_to_write, int sync_after, int pause_after)
1002
long x = (long) (file_size / (off_t) size), y;
1003
long pbytes_written = 0;
1004
long sbytes_written = 0;
1005
off_t total_written = 0;
1008
block = (char *) malloc(size);
1009
for (i=0; i<size; i++)
1010
block[i] = (char) i;
1016
while (total_written < amount_to_write) {
1019
offset = (off_t) y * (off_t) size;
1021
while (offset+size > file_size);
1022
f->fi_write(f, block, size, offset);
1023
sbytes_written += size;
1024
pbytes_written += size;
1025
total_written += size;
1026
if (sync_after && sbytes_written > sync_after) {
1030
if (pause_after && pbytes_written > pause_after) {
1038
static void seq_write_bytes(File *f, off_t file_size, size_t size, off_t amount_to_write, int sync_after, int pause_after)
1042
long pbytes_written = 0;
1043
long sbytes_written = 0;
1044
off_t total_written = 0;
1047
block = (char *) malloc(size);
1048
for (i=0; i<size; i++)
1049
block[i] = (char) i;
1056
while (total_written < amount_to_write) {
1057
if (offset+size > file_size)
1059
f->fi_write(f, block, size, offset);
1060
sbytes_written += size;
1061
pbytes_written += size;
1062
total_written += size;
1064
if (sync_after && sbytes_written > sync_after) {
1068
if (pause_after && pbytes_written > pause_after) {
1076
static void simulate_xlog_write(File *f, off_t eof, off_t start_point, size_t size, off_t amount_to_write)
1079
off_t start = start_point;
1082
off_t total_written = 0;
1085
block = (char *) malloc(1024*16);
1086
for (i=0; i<1024*16; i++)
1087
block[i] = (char) i;
1089
while (total_written < amount_to_write) {
1090
/* Write 512 byte boundary block around random data we wish to write. */
1091
offset = (start / 512) * 512;
1092
tfer = (((start + size) / 512) * 512 + 512) - offset;
1093
f->fi_write(f, block, tfer, offset);
1094
total_written += tfer;
1097
if (start + size > eof)
1098
start = start_point;
1104
static void seq_write_blocks_aligned(File *f, off_t file_size, size_t block_size, off_t amount_to_write)
1107
off_t i, no_of_writes;
1110
/* Blocks, 1 K in size: */
1111
block_size = block_size / 1024 * 1024;
1113
block = (char *) malloc(block_size);
1114
for (i=0; i<block_size; i++)
1115
block[i] = (char) i;
1117
no_of_writes = amount_to_write / block_size;
1119
/* Calculate and round increment: */
1120
inc = (file_size / no_of_writes) / 1024 * 1024;
1122
/* This is required if we want a gap: */
1123
assert(inc > block_size);
1126
for (i=0; i<no_of_writes; i++) {
1127
f->fi_write(f, block, block_size, offset);
1132
/* ------------------- TESTS ------------------- */
1134
static void *test_xlog_write_prealloc(void *data)
1138
new_file(&f, __FUNCTION__, "xlog");
1139
create_file(f, SIM_FILE_SIZE, PREFILL);
1141
simulate_xlog_write(f, SIM_FILE_SIZE, 0, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT);
1146
static void *test_xlog_write_no_prealloc(void *data)
1150
new_file(&f, __FUNCTION__, "xlog");
1151
create_file(f, 512, TRUNCATE);
1153
simulate_xlog_write(f, SIM_FILE_SIZE, 0, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT);
1158
static void *test_xlog_write_set_eof(void *data)
1162
new_file(&f, __FUNCTION__, "xlog");
1163
create_file(f, SIM_FILE_SIZE, SET_EOF);
1165
simulate_xlog_write(f, SIM_FILE_SIZE, 0, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT);
1170
static void *test_rnd_write_prealloc(void *data)
1174
new_file(&f, __FUNCTION__, "rndw");
1175
create_file(f, SIM_FILE_SIZE, PREFILL);
1177
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1182
static void *test_rnd_write_no_prealloc(void *data)
1186
new_file(&f, __FUNCTION__, "rndw");
1187
create_file(f, 0, TRUNCATE);
1189
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1194
static void *test_rnd_write_rewrite_all_sync_prealloc(void *data)
1198
new_file(&f, __FUNCTION__, "rndw");
1199
create_file(f, SIM_FILE_SIZE, PREFILL);
1201
f->fi_sync = rewrite_all_sync_file;
1202
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1207
static void *test_rnd_write_rewrite_min_max_sync_prealloc(void *data)
1211
new_file(&f, __FUNCTION__, "rndw");
1212
create_file(f, SIM_FILE_SIZE, PREFILL);
1214
f->fi_write = rewrite_min_max_write_file;
1215
f->fi_sync = rewrite_min_max_sync_file;
1216
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1221
static void *test_rnd_write_rewrite_opt_sync_prealloc(void *data)
1225
new_file(&f, __FUNCTION__, "rndw");
1226
create_file(f, SIM_FILE_SIZE, PREFILL);
1228
f->fi_write = rewrite_opt_write_file;
1229
f->fi_sync = rewrite_opt_sync_file;
1230
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1235
static void *test_rnd_write_rewrite_limit_sync_prealloc(void *data)
1239
new_file(&f, __FUNCTION__, "rndw");
1240
create_file(f, SIM_FILE_SIZE, PREFILL);
1242
f->fi_write = rewrite_limit_write_file;
1243
f->fi_sync = rewrite_limit_sync_file;
1244
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1249
static void *test_rnd_write_sorted_prealloc(void *data)
1253
new_file(&f, __FUNCTION__, "rndsw");
1254
create_file(f, SIM_FILE_SIZE, PREFILL);
1256
f->fi_write = sorted_write_file;
1257
f->fi_sync = sorted_sync_file;
1258
f->fi_write_all = sorted_write_all;
1259
f->fi_write_all = sorted_write_rw_all;
1260
f->fi_write_all = sorted_write_rw_no_gaps_all;
1261
random_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1266
static void *test_seq_write_prealloc(void *data)
1270
new_file(&f, __FUNCTION__, "seqw");
1271
create_file(f, SIM_FILE_SIZE, PREFILL);
1273
seq_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1278
static void *test_seq_write_no_prealloc(void *data)
1282
new_file(&f, __FUNCTION__, "seqw");
1283
create_file(f, 0, TRUNCATE);
1285
seq_write_bytes(f, SIM_FILE_SIZE, SIM_RECORD_SIZE, SIM_WRITE_AMOUNT, SIM_FLUSH_THRESHOLD, SIM_PAUSE_THRESHOLD);
1290
static void *test_seq_rw_prealloc(void *data)
1294
new_file(&f, __FUNCTION__, "seqrw");
1295
create_file(f, SIM_FILE_SIZE, PREFILL);
1297
read_write_bytes(f, SIM_FILE_SIZE);
1302
int block_write_block_count = 128;
1304
static void *test_block_write_aligned_prealloc(void *data)
1307
off_t write_amount = SIM_FILE_SIZE / 2;
1309
new_file(&f, __FUNCTION__, "block");
1310
create_file(f, SIM_FILE_SIZE, PREFILL);
1312
seq_write_blocks_aligned(f, SIM_FILE_SIZE, write_amount / block_write_block_count, write_amount);
1317
/* ------------------- THREADING ------------------- */
1319
static pthread_t run_task_as_thread(void *(*task)(void *))
1324
err = pthread_create(&thread, NULL, task, NULL);
1326
error_exit("pthread_create", err);
1330
static void wait_for_task(pthread_t thread)
1334
pthread_join(thread, &value);
1337
/* ------------------- MAIN ------------------- */
1339
static void reference_tests()
1341
test_xlog_write_prealloc(NULL);
1342
test_xlog_write_no_prealloc(NULL);
1343
test_xlog_write_set_eof(NULL);
1345
test_rnd_write_prealloc(NULL);
1346
test_rnd_write_no_prealloc(NULL);
1347
test_rnd_write_rewrite_all_sync_prealloc(NULL);
1348
test_rnd_write_rewrite_min_max_sync_prealloc(NULL);
1349
test_rnd_write_rewrite_opt_sync_prealloc(NULL);
1350
test_rnd_write_rewrite_limit_sync_prealloc(NULL);
1352
test_rnd_write_sorted_prealloc(NULL);
1354
test_seq_write_prealloc(NULL);
1355
test_seq_write_no_prealloc(NULL);
1356
test_seq_rw_prealloc(NULL);
1358
test_block_write_aligned_prealloc(NULL);
1361
static void do_task(void *(*task)(void *))
1364
t1 = run_task_as_thread(task);
1368
static void do_test_1()
1373
t1 = run_task_as_thread(test_rnd_write_sorted_prealloc);
1374
//t2 = run_task_as_thread(test_xlog_write_prealloc);
1377
//wait_for_task(t2);
1380
static void do_test_2()
1382
//do_task(test_rnd_write_prealloc);
1383
//do_task(test_rnd_write_rewrite_min_max_sync_prealloc);
1384
do_task(test_rnd_write_rewrite_limit_sync_prealloc);
1387
block_write_block_count = 1;
1388
do_task(test_block_write_aligned_prealloc);
1389
block_write_block_count = 2;
1390
do_task(test_block_write_aligned_prealloc);
1391
block_write_block_count = 4;
1392
do_task(test_block_write_aligned_prealloc);
1393
block_write_block_count = 8;
1394
do_task(test_block_write_aligned_prealloc);
1395
block_write_block_count = 16;
1396
do_task(test_block_write_aligned_prealloc);
1397
block_write_block_count = 32;
1398
do_task(test_block_write_aligned_prealloc);
1399
block_write_block_count = 64;
1400
do_task(test_block_write_aligned_prealloc);
1401
block_write_block_count = 128;
1402
do_task(test_block_write_aligned_prealloc);
1406
int main(int argc, char **argv)
1410
//m = run_task_as_thread(iotest_monitor);
1414
monitor_running = FALSE;