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