root / synthbench / bonnie++ / .svn / text-base / bonnie++.cpp.svn-base @ 0:839f52ef7657
History | View | Annotate | Download (18.9 kB)
1 |
|
---|---|
2 |
/* |
3 |
* COPYRIGHT NOTICE: |
4 |
* Copyright (c) Tim Bray, 1990. |
5 |
* Copyright (c) Russell Coker, 1999. I have updated the program, added |
6 |
* support for >2G on 32bit machines, and tests for file creation. |
7 |
* Licensed under the GPL version 2.0. |
8 |
* DISCLAIMER: |
9 |
* This program is provided AS IS with no warranty of any kind, and |
10 |
* The author makes no representation with respect to the adequacy of this |
11 |
* program for any particular purpose or with respect to its adequacy to |
12 |
* produce any particular result, and |
13 |
* The author shall not be liable for loss or damage arising out of |
14 |
* the use of this program regardless of how sustained, and |
15 |
* In no event shall the author be liable for special, direct, indirect |
16 |
* or consequential damage, loss, costs or fees or expenses of any |
17 |
* nature or kind. |
18 |
*/ |
19 |
|
20 |
#ifdef OS2 |
21 |
#define INCL_DOSFILEMGR |
22 |
#define INCL_DOSMISC |
23 |
#define INCL_DOSQUEUES |
24 |
#define INCL_DOSPROCESS |
25 |
#include <os2.h> |
26 |
#else |
27 |
#include <sys/wait.h> |
28 |
#include <unistd.h> |
29 |
#endif |
30 |
#include <sys/time.h> |
31 |
#include <time.h> |
32 |
#include <stdlib.h> |
33 |
#include "bonnie.h" |
34 |
#include "bon_io.h" |
35 |
#include "bon_file.h" |
36 |
#include "bon_time.h" |
37 |
#include "semaphore.h" |
38 |
#include <pwd.h> |
39 |
#include <grp.h> |
40 |
#include <ctype.h> |
41 |
#include <string.h> |
42 |
#include <sys/utsname.h> |
43 |
#include <signal.h> |
44 |
|
45 |
#ifdef AIX_MEM_SIZE |
46 |
#include <cf.h> |
47 |
#include <sys/cfgodm.h> |
48 |
#include <sys/cfgdb.h> |
49 |
#endif |
50 |
|
51 |
void usage(); |
52 |
|
53 |
class CGlobalItems |
54 |
{ |
55 |
public: |
56 |
bool quiet; |
57 |
bool fast; |
58 |
bool sync_bonnie; |
59 |
BonTimer timer; |
60 |
int ram; |
61 |
Semaphore sem; |
62 |
char *name; |
63 |
bool bufSync; |
64 |
int chunk_bits; |
65 |
int chunk_size() const { return m_chunk_size; } |
66 |
bool *doExit; |
67 |
void set_chunk_size(int size) |
68 |
{ delete m_buf; m_buf = new char[size]; m_chunk_size = size; } |
69 |
|
70 |
char *buf() { return m_buf; } |
71 |
|
72 |
CGlobalItems(bool *exitFlag); |
73 |
~CGlobalItems() { delete name; delete m_buf; } |
74 |
|
75 |
void decrement_and_wait(int nr_sem); |
76 |
|
77 |
void SetName(CPCCHAR path) |
78 |
{ |
79 |
delete name; |
80 |
name = new char[strlen(path) + 15]; |
81 |
#ifdef OS2 |
82 |
ULONG myPid = 0; |
83 |
DosQuerySysInfo(QSV_FOREGROUND_PROCESS, QSV_FOREGROUND_PROCESS |
84 |
, &myPid, sizeof(myPid)); |
85 |
#else |
86 |
pid_t myPid = getpid(); |
87 |
#endif |
88 |
sprintf(name, "%s/Bonnie.%d", path, int(myPid)); |
89 |
} |
90 |
private: |
91 |
int m_chunk_size; |
92 |
char *m_buf; |
93 |
|
94 |
|
95 |
CGlobalItems(const CGlobalItems &f); |
96 |
CGlobalItems & operator =(const CGlobalItems &f); |
97 |
}; |
98 |
|
99 |
CGlobalItems::CGlobalItems(bool *exitFlag) |
100 |
: quiet(false) |
101 |
, fast(false) |
102 |
, sync_bonnie(false) |
103 |
, timer() |
104 |
, ram(0) |
105 |
, sem(SemKey, TestCount) |
106 |
, name(NULL) |
107 |
, bufSync(false) |
108 |
, chunk_bits(DefaultChunkBits) |
109 |
, doExit(exitFlag) |
110 |
, m_chunk_size(DefaultChunkSize) |
111 |
, m_buf(new char[m_chunk_size]) |
112 |
{ |
113 |
SetName("."); |
114 |
} |
115 |
|
116 |
void CGlobalItems::decrement_and_wait(int nr_sem) |
117 |
{ |
118 |
if(sem.decrement_and_wait(nr_sem)) |
119 |
exit(1); |
120 |
} |
121 |
|
122 |
int TestDirOps(int directory_size, int max_size, int min_size |
123 |
, int num_directories, CGlobalItems &globals); |
124 |
int TestFileOps(int file_size, CGlobalItems &globals); |
125 |
|
126 |
static bool exitNow; |
127 |
static bool already_printed_error; |
128 |
|
129 |
#ifdef USE_SA_SIGACTION |
130 |
#define SIGNAL_NUMBER siginf->si_signo |
131 |
#else |
132 |
#define SIGNAL_NUMBER sig |
133 |
#endif |
134 |
|
135 |
extern "C" |
136 |
{ |
137 |
void ctrl_c_handler(int sig |
138 |
#ifdef USE_SA_SIGACTION |
139 |
, siginfo_t *siginf, void *unused |
140 |
#endif |
141 |
) |
142 |
{ |
143 |
if(SIGNAL_NUMBER == SIGXCPU) |
144 |
fprintf(stderr, "Exceeded CPU usage.\n"); |
145 |
else if(SIGNAL_NUMBER == SIGXFSZ) |
146 |
fprintf(stderr, "exceeded file storage limits.\n"); |
147 |
exitNow = true; |
148 |
} |
149 |
} |
150 |
|
151 |
int main(int argc, char *argv[]) |
152 |
{ |
153 |
int file_size = DefaultFileSize; |
154 |
int directory_size = DefaultDirectorySize; |
155 |
int directory_max_size = DefaultDirectoryMaxSize; |
156 |
int directory_min_size = DefaultDirectoryMinSize; |
157 |
int num_bonnie_procs = 0; |
158 |
int num_directories = 1; |
159 |
int count = -1; |
160 |
const char * machine = NULL; |
161 |
char *userName = NULL, *groupName = NULL; |
162 |
CGlobalItems globals(&exitNow); |
163 |
bool setSize = false; |
164 |
|
165 |
exitNow = false; |
166 |
already_printed_error = false; |
167 |
|
168 |
struct sigaction sa; |
169 |
#ifdef USE_SA_SIGACTION |
170 |
sa.sa_sigaction = &ctrl_c_handler; |
171 |
sa.sa_flags = SA_RESETHAND | SA_SIGINFO; |
172 |
#else |
173 |
sa.sa_handler = ctrl_c_handler; |
174 |
sa.sa_flags = SA_RESETHAND; |
175 |
#endif |
176 |
if(sigaction(SIGINT, &sa, NULL) |
177 |
|| sigaction(SIGXCPU, &sa, NULL) |
178 |
|| sigaction(SIGXFSZ, &sa, NULL)) |
179 |
{ |
180 |
printf("Can't handle SIGINT.\n"); |
181 |
return 1; |
182 |
} |
183 |
#ifdef USE_SA_SIGACTION |
184 |
sa.sa_sigaction = NULL; |
185 |
#endif |
186 |
sa.sa_handler = SIG_IGN; |
187 |
if(sigaction(SIGHUP, &sa, NULL)) |
188 |
{ |
189 |
printf("Can't handle SIGHUP.\n"); |
190 |
return 1; |
191 |
} |
192 |
|
193 |
#ifdef _SC_PHYS_PAGES |
194 |
int page_size = sysconf(_SC_PAGESIZE); |
195 |
int num_pages = sysconf(_SC_PHYS_PAGES); |
196 |
if(page_size != -1 && num_pages != -1) |
197 |
{ |
198 |
globals.ram = page_size/1024 * (num_pages/1024); |
199 |
} |
200 |
#else |
201 |
|
202 |
#ifdef AIX_MEM_SIZE |
203 |
struct CuAt *odm_obj; |
204 |
int how_many; |
205 |
|
206 |
odm_set_path("/etc/objrepos"); |
207 |
odm_obj = getattr("sys0", "realmem", 0, &how_many); |
208 |
globals.ram = atoi(odm_obj->value) / 1024; |
209 |
odm_terminate(); |
210 |
printf("Memory = %d MiB\n", globals.ram); |
211 |
#endif |
212 |
|
213 |
#endif |
214 |
|
215 |
int int_c; |
216 |
while(-1 != (int_c = getopt(argc, argv, "bd:fg:m:n:p:qr:s:u:x:y")) ) |
217 |
{ |
218 |
switch(char(int_c)) |
219 |
{ |
220 |
case '?': |
221 |
case ':': |
222 |
usage(); |
223 |
break; |
224 |
case 'b': |
225 |
globals.bufSync = true; |
226 |
break; |
227 |
case 'd': |
228 |
if(chdir(optarg)) |
229 |
{ |
230 |
fprintf(stderr, "Can't change to directory \"%s\".\n", optarg); |
231 |
usage(); |
232 |
} |
233 |
break; |
234 |
case 'f': |
235 |
globals.fast = true; |
236 |
break; |
237 |
case 'm': |
238 |
machine = optarg; |
239 |
break; |
240 |
case 'n': |
241 |
sscanf(optarg, "%d:%d:%d:%d", &directory_size |
242 |
, &directory_max_size, &directory_min_size |
243 |
, &num_directories); |
244 |
break; |
245 |
case 'p': |
246 |
num_bonnie_procs = atoi(optarg); |
247 |
/* Set semaphore to # of bonnie++ procs |
248 |
to synchronize */ |
249 |
break; |
250 |
case 'q': |
251 |
globals.quiet = true; |
252 |
break; |
253 |
case 'r': |
254 |
globals.ram = atoi(optarg); |
255 |
break; |
256 |
case 's': |
257 |
{ |
258 |
char *sbuf = strdup(optarg); |
259 |
char *size = strtok(sbuf, ":"); |
260 |
file_size = atoi(size); |
261 |
char c = size[strlen(size) - 1]; |
262 |
if(c == 'g' || c == 'G') |
263 |
file_size *= 1024; |
264 |
size = strtok(NULL, ""); |
265 |
if(size) |
266 |
{ |
267 |
int tmp = atoi(size); |
268 |
c = size[strlen(size) - 1]; |
269 |
if(c == 'k' || c == 'K') |
270 |
tmp *= 1024; |
271 |
globals.set_chunk_size(tmp); |
272 |
} |
273 |
setSize = true; |
274 |
} |
275 |
break; |
276 |
case 'g': |
277 |
if(groupName) |
278 |
usage(); |
279 |
groupName = optarg; |
280 |
break; |
281 |
case 'u': |
282 |
{ |
283 |
if(userName) |
284 |
usage(); |
285 |
userName = strdup(optarg); |
286 |
int i; |
287 |
for(i = 0; userName[i] && userName[i] != ':'; i++) |
288 |
{} |
289 |
if(userName[i] == ':') |
290 |
{ |
291 |
if(groupName) |
292 |
usage(); |
293 |
userName[i] = '\0'; |
294 |
groupName = &userName[i + 1]; |
295 |
} |
296 |
} |
297 |
break; |
298 |
case 'x': |
299 |
count = atoi(optarg); |
300 |
break; |
301 |
case 'y': |
302 |
/* tell procs to synchronize via previous |
303 |
defined semaphore */ |
304 |
globals.sync_bonnie = true; |
305 |
break; |
306 |
} |
307 |
} |
308 |
if(optind < argc) |
309 |
usage(); |
310 |
|
311 |
if(globals.ram && !setSize) |
312 |
{ |
313 |
if(file_size < (globals.ram * 2)) |
314 |
file_size = globals.ram * 2; |
315 |
// round up to the nearest gig |
316 |
if(file_size % 1024 > 512) |
317 |
file_size = file_size + 1024 - (file_size % 1024); |
318 |
} |
319 |
|
320 |
if(machine == NULL) |
321 |
{ |
322 |
struct utsname utsBuf; |
323 |
if(uname(&utsBuf) != -1) |
324 |
machine = utsBuf.nodename; |
325 |
} |
326 |
|
327 |
if(userName || groupName) |
328 |
{ |
329 |
if(bon_setugid(userName, groupName, globals.quiet)) |
330 |
return 1; |
331 |
if(userName) |
332 |
free(userName); |
333 |
} |
334 |
else if(geteuid() == 0) |
335 |
{ |
336 |
fprintf(stderr, "You must use the \"-u\" switch when running as root.\n"); |
337 |
usage(); |
338 |
} |
339 |
|
340 |
if(num_bonnie_procs && globals.sync_bonnie) |
341 |
usage(); |
342 |
|
343 |
if(num_bonnie_procs) |
344 |
{ |
345 |
if(num_bonnie_procs == -1) |
346 |
{ |
347 |
return globals.sem.clear_sem(); |
348 |
} |
349 |
else |
350 |
{ |
351 |
return globals.sem.create(num_bonnie_procs); |
352 |
} |
353 |
} |
354 |
|
355 |
if(globals.sync_bonnie) |
356 |
{ |
357 |
if(globals.sem.get_semid()) |
358 |
return 1; |
359 |
} |
360 |
|
361 |
if(file_size < 0 || directory_size < 0 || (!file_size && !directory_size) ) |
362 |
usage(); |
363 |
if(globals.chunk_size() < 256 || globals.chunk_size() > Unit) |
364 |
usage(); |
365 |
int i; |
366 |
globals.chunk_bits = 0; |
367 |
for(i = globals.chunk_size(); i > 1; i = i >> 1, globals.chunk_bits++) |
368 |
{} |
369 |
if(1 << globals.chunk_bits != globals.chunk_size()) |
370 |
usage(); |
371 |
|
372 |
if( (directory_max_size != -1 && directory_max_size != -2) |
373 |
&& (directory_max_size < directory_min_size || directory_max_size < 0 |
374 |
|| directory_min_size < 0) ) |
375 |
usage(); |
376 |
/* If the storage size is too big for the maximum number of files (1000G) */ |
377 |
if(file_size > IOFileSize * MaxIOFiles) |
378 |
usage(); |
379 |
/* If the file size is so large and the chunk size is so small that we have |
380 |
* more than 2G of chunks */ |
381 |
if(globals.chunk_bits < 20 && file_size > (1 << (31 - 20 + globals.chunk_bits)) ) |
382 |
usage(); |
383 |
// if doing more than one test run then we print a header before the |
384 |
// csv format output. |
385 |
if(count > 1) |
386 |
{ |
387 |
globals.timer.SetType(BonTimer::csv); |
388 |
globals.timer.PrintHeader(stdout); |
389 |
} |
390 |
#ifdef OS2 |
391 |
ULONG myPid = 0; |
392 |
DosQuerySysInfo(QSV_FOREGROUND_PROCESS, QSV_FOREGROUND_PROCESS |
393 |
, &myPid, sizeof(myPid)); |
394 |
#else |
395 |
pid_t myPid = getpid(); |
396 |
#endif |
397 |
srand(myPid ^ time(NULL)); |
398 |
for(; count > 0 || count == -1; count--) |
399 |
{ |
400 |
globals.timer.Initialize(); |
401 |
int rc; |
402 |
rc = TestFileOps(file_size, globals); |
403 |
if(rc) return rc; |
404 |
rc = TestDirOps(directory_size, directory_max_size, directory_min_size |
405 |
, num_directories, globals); |
406 |
if(rc) return rc; |
407 |
// if we are only doing one test run then print a plain-text version of |
408 |
// the results before printing a csv version. |
409 |
if(count == -1) |
410 |
{ |
411 |
globals.timer.SetType(BonTimer::txt); |
412 |
rc = globals.timer.DoReport(machine, file_size, directory_size |
413 |
, directory_max_size, directory_min_size |
414 |
, num_directories, globals.chunk_size() |
415 |
, globals.quiet ? stderr : stdout); |
416 |
} |
417 |
// print a csv version in every case |
418 |
globals.timer.SetType(BonTimer::csv); |
419 |
rc = globals.timer.DoReport(machine, file_size, directory_size |
420 |
, directory_max_size, directory_min_size |
421 |
, num_directories, globals.chunk_size(), stdout); |
422 |
if(rc) return rc; |
423 |
} |
424 |
} |
425 |
|
426 |
int |
427 |
TestFileOps(int file_size, CGlobalItems &globals) |
428 |
{ |
429 |
if(file_size) |
430 |
{ |
431 |
CFileOp file(globals.timer, file_size, globals.chunk_bits, globals.bufSync); |
432 |
int num_chunks; |
433 |
int words; |
434 |
char *buf = globals.buf(); |
435 |
int bufindex; |
436 |
int i; |
437 |
|
438 |
if(globals.ram && file_size < globals.ram * 2) |
439 |
{ |
440 |
fprintf(stderr |
441 |
, "File size should be double RAM for good results, RAM is %dM.\n" |
442 |
, globals.ram); |
443 |
return 1; |
444 |
} |
445 |
// default is we have 1M / 8K * 200 chunks = 25600 |
446 |
num_chunks = Unit / globals.chunk_size() * file_size; |
447 |
|
448 |
int rc; |
449 |
rc = file.open(globals.name, true, true); |
450 |
if(rc) |
451 |
return rc; |
452 |
if(exitNow) |
453 |
return EXIT_CTRL_C; |
454 |
globals.timer.timestamp(); |
455 |
|
456 |
if(!globals.fast) |
457 |
{ |
458 |
globals.decrement_and_wait(Putc); |
459 |
// Fill up a file, writing it a char at a time with the stdio putc() call |
460 |
if(!globals.quiet) fprintf(stderr, "Writing with putc()..."); |
461 |
for(words = 0; words < num_chunks; words++) |
462 |
{ |
463 |
if(file.write_block_putc() == -1) |
464 |
return 1; |
465 |
if(exitNow) |
466 |
return EXIT_CTRL_C; |
467 |
} |
468 |
fflush(NULL); |
469 |
/* |
470 |
* note that we always close the file before measuring time, in an |
471 |
* effort to force as much of the I/O out as we can |
472 |
*/ |
473 |
file.close(); |
474 |
globals.timer.get_delta_t(Putc); |
475 |
if(!globals.quiet) fprintf(stderr, "done\n"); |
476 |
} |
477 |
/* Write the whole file from scratch, again, with block I/O */ |
478 |
if(file.reopen(true)) |
479 |
return 1; |
480 |
globals.decrement_and_wait(FastWrite); |
481 |
if(!globals.quiet) fprintf(stderr, "Writing intelligently..."); |
482 |
memset(buf, 0, globals.chunk_size()); |
483 |
globals.timer.timestamp(); |
484 |
bufindex = 0; |
485 |
// for the number of chunks of file data |
486 |
for(i = 0; i < num_chunks; i++) |
487 |
{ |
488 |
if(exitNow) |
489 |
return EXIT_CTRL_C; |
490 |
// for each chunk in the Unit |
491 |
buf[bufindex]++; |
492 |
bufindex = (bufindex + 1) % globals.chunk_size(); |
493 |
if(file.write_block(PVOID(buf)) == -1) |
494 |
return io_error("write(2)"); |
495 |
} |
496 |
file.close(); |
497 |
globals.timer.get_delta_t(FastWrite); |
498 |
if(!globals.quiet) fprintf(stderr, "done\n"); |
499 |
|
500 |
|
501 |
/* Now read & rewrite it using block I/O. Dirty one word in each block */ |
502 |
if(file.reopen(false)) |
503 |
return 1; |
504 |
if (file.seek(0, SEEK_SET) == -1) |
505 |
{ |
506 |
if(!globals.quiet) fprintf(stderr, "error in lseek(2) before rewrite\n"); |
507 |
return 1; |
508 |
} |
509 |
globals.decrement_and_wait(ReWrite); |
510 |
if(!globals.quiet) fprintf(stderr, "Rewriting..."); |
511 |
globals.timer.timestamp(); |
512 |
bufindex = 0; |
513 |
for(words = 0; words < num_chunks; words++) |
514 |
{ // for each chunk in the file |
515 |
if (file.read_block(PVOID(buf)) == -1) |
516 |
return 1; |
517 |
bufindex = bufindex % globals.chunk_size(); |
518 |
buf[bufindex]++; |
519 |
bufindex++; |
520 |
if (file.seek(-1, SEEK_CUR) == -1) |
521 |
return 1; |
522 |
if (file.write_block(PVOID(buf)) == -1) |
523 |
return io_error("re write(2)"); |
524 |
if(exitNow) |
525 |
return EXIT_CTRL_C; |
526 |
} |
527 |
file.close(); |
528 |
globals.timer.get_delta_t(ReWrite); |
529 |
if(!globals.quiet) fprintf(stderr, "done\n"); |
530 |
|
531 |
|
532 |
if(!globals.fast) |
533 |
{ |
534 |
// read them all back with getc() |
535 |
if(file.reopen(false, true)) |
536 |
return 1; |
537 |
globals.decrement_and_wait(Getc); |
538 |
if(!globals.quiet) fprintf(stderr, "Reading with getc()..."); |
539 |
globals.timer.timestamp(); |
540 |
|
541 |
for(words = 0; words < num_chunks; words++) |
542 |
{ |
543 |
if(file.read_block_getc(buf) == -1) |
544 |
return 1; |
545 |
if(exitNow) |
546 |
return EXIT_CTRL_C; |
547 |
} |
548 |
|
549 |
file.close(); |
550 |
globals.timer.get_delta_t(Getc); |
551 |
if(!globals.quiet) fprintf(stderr, "done\n"); |
552 |
} |
553 |
|
554 |
/* Now suck it in, Chunk at a time, as fast as we can */ |
555 |
if(file.reopen(false)) |
556 |
return 1; |
557 |
if (file.seek(0, SEEK_SET) == -1) |
558 |
return io_error("lseek before read"); |
559 |
globals.decrement_and_wait(FastRead); |
560 |
if(!globals.quiet) fprintf(stderr, "Reading intelligently..."); |
561 |
globals.timer.timestamp(); |
562 |
for(i = 0; i < num_chunks; i++) |
563 |
{ /* per block */ |
564 |
if ((words = file.read_block(PVOID(buf))) == -1) |
565 |
return io_error("read(2)"); |
566 |
if(exitNow) |
567 |
return EXIT_CTRL_C; |
568 |
} /* per block */ |
569 |
file.close(); |
570 |
globals.timer.get_delta_t(FastRead); |
571 |
if(!globals.quiet) fprintf(stderr, "done\n"); |
572 |
|
573 |
globals.timer.timestamp(); |
574 |
if(file.seek_test(globals.quiet, globals.sem)) |
575 |
return 1; |
576 |
|
577 |
/* |
578 |
* Now test random seeks; first, set up for communicating with children. |
579 |
* The object of the game is to do "Seeks" lseek() calls as quickly |
580 |
* as possible. So we'll farm them out among SeekProcCount processes. |
581 |
* We'll control them by writing 1-byte tickets down a pipe which |
582 |
* the children all read. We write "Seeks" bytes with val 1, whichever |
583 |
* child happens to get them does it and the right number of seeks get |
584 |
* done. |
585 |
* The idea is that since the write() of the tickets is probably |
586 |
* atomic, the parent process likely won't get scheduled while the |
587 |
* children are seeking away. If you draw a picture of the likely |
588 |
* timelines for three children, it seems likely that the seeks will |
589 |
* overlap very nicely with the process scheduling with the effect |
590 |
* that there will *always* be a seek() outstanding on the file. |
591 |
* Question: should the file be opened *before* the fork, so that |
592 |
* all the children are lseeking on the same underlying file object? |
593 |
*/ |
594 |
} |
595 |
return 0; |
596 |
} |
597 |
|
598 |
int |
599 |
TestDirOps(int directory_size, int max_size, int min_size |
600 |
, int num_directories, CGlobalItems &globals) |
601 |
{ |
602 |
COpenTest open_test(globals.chunk_size(), globals.bufSync, globals.doExit); |
603 |
if(!directory_size) |
604 |
{ |
605 |
return 0; |
606 |
} |
607 |
// if directory_size (in K) * data per file*2 > (ram << 10) (IE memory /1024) |
608 |
// then the storage of file names will take more than half RAM and there |
609 |
// won't be enough RAM to have Bonnie++ paged in and to have a reasonable |
610 |
// meta-data cache. |
611 |
if(globals.ram && directory_size * MaxDataPerFile * 2 > (globals.ram << 10)) |
612 |
{ |
613 |
fprintf(stderr |
614 |
, "When testing %dK of files in %d MiB of RAM the system is likely to\n" |
615 |
"start paging Bonnie++ data and the test will give suspect\n" |
616 |
"results, use less files or install more RAM for this test.\n" |
617 |
, directory_size, globals.ram); |
618 |
return 1; |
619 |
} |
620 |
// Can't use more than 1G of RAM |
621 |
if(directory_size * MaxDataPerFile > (1 << 20)) |
622 |
{ |
623 |
fprintf(stderr, "Not enough ram to test with %dK files.\n" |
624 |
, directory_size); |
625 |
return 1; |
626 |
} |
627 |
globals.decrement_and_wait(CreateSeq); |
628 |
if(!globals.quiet) fprintf(stderr, "Create files in sequential order..."); |
629 |
if(open_test.create(globals.name, globals.timer, directory_size |
630 |
, max_size, min_size, num_directories, false)) |
631 |
return 1; |
632 |
globals.decrement_and_wait(StatSeq); |
633 |
if(!globals.quiet) fprintf(stderr, "done.\nStat files in sequential order..."); |
634 |
if(open_test.stat_sequential(globals.timer)) |
635 |
return 1; |
636 |
globals.decrement_and_wait(DelSeq); |
637 |
if(!globals.quiet) fprintf(stderr, "done.\nDelete files in sequential order..."); |
638 |
if(open_test.delete_sequential(globals.timer)) |
639 |
return 1; |
640 |
if(!globals.quiet) fprintf(stderr, "done.\n"); |
641 |
|
642 |
globals.decrement_and_wait(CreateRand); |
643 |
if(!globals.quiet) fprintf(stderr, "Create files in random order..."); |
644 |
if(open_test.create(globals.name, globals.timer, directory_size |
645 |
, max_size, min_size, num_directories, true)) |
646 |
return 1; |
647 |
globals.decrement_and_wait(StatRand); |
648 |
if(!globals.quiet) fprintf(stderr, "done.\nStat files in random order..."); |
649 |
if(open_test.stat_random(globals.timer)) |
650 |
return 1; |
651 |
globals.decrement_and_wait(DelRand); |
652 |
if(!globals.quiet) fprintf(stderr, "done.\nDelete files in random order..."); |
653 |
if(open_test.delete_random(globals.timer)) |
654 |
return 1; |
655 |
if(!globals.quiet) fprintf(stderr, "done.\n"); |
656 |
return 0; |
657 |
} |
658 |
|
659 |
void |
660 |
usage() |
661 |
{ |
662 |
fprintf(stderr, |
663 |
"usage: bonnie++ [-d scratch-dir] [-s size(MiB)[:chunk-size(b)]]\n" |
664 |
" [-n number-to-stat[:max-size[:min-size][:num-directories]]]\n" |
665 |
" [-m machine-name]\n" |
666 |
" [-r ram-size-in-MiB]\n" |
667 |
" [-x number-of-tests] [-u uid-to-use:gid-to-use] [-g gid-to-use]\n" |
668 |
" [-q] [-f] [-b] [-p processes | -y]\n" |
669 |
"\nVersion: " BON_VERSION "\n"); |
670 |
exit(1); |
671 |
} |
672 |
|
673 |
int |
674 |
io_error(CPCCHAR message, bool do_exit) |
675 |
{ |
676 |
char buf[1024]; |
677 |
|
678 |
if(!already_printed_error && !do_exit) |
679 |
{ |
680 |
sprintf(buf, "Bonnie: drastic I/O error (%s)", message); |
681 |
perror(buf); |
682 |
already_printed_error = 1; |
683 |
} |
684 |
if(do_exit) |
685 |
exit(1); |
686 |
return(1); |
687 |
} |
688 |
|