root / synthbench / bonnie++ / bonnie++.cpp @ 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 |
|