home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume22 / iozone / part01 / iozone.c
C/C++ Source or Header  |  1991-08-21  |  18KB  |  635 lines

  1. /*
  2.     iozone.c
  3.  
  4.     'IO Zone' Benchmark Program
  5.  
  6.     Author:    Bill Norcott (Bill.Norcott@nuo.mts.dec.com)
  7.         4 Dunlap Drive
  8.         Nashua, NH  03060
  9.  
  10.     'Copyright 1991,   William D. Norcott
  11.     License to freely use and distribute this software is hereby granted 
  12.     by the author, subject to the condition that this copyright notice 
  13.     remains intact.  The author retains the exclusive right to publish 
  14.     derivative works based on this work, including, but not limited
  15.     to, revised versions of this work'
  16. */
  17. char *help[] = {
  18. "     'IO Zone' Benchmark Program",
  19. " ",
  20. "     Author:    Bill Norcott (Bill.Norcott@nuo.mts.dec.com)",
  21. "         4 Dunlap Drive",
  22. "         Nashua, NH  03060",
  23. " ",
  24. "   'Copyright 1991,   William D. Norcott",
  25. "   License to freely use and distribute this software is hereby granted ",
  26. "   by the author, subject to the condition that this copyright notice ",
  27. "   remains intact.  The author retains the exclusive right to publish ",
  28. "   derivative works based on this work, including, but not limited ",
  29. "   to, revised versions of this work'",
  30. " ",
  31. "  This test writes a 4 MEGABYTE sequential file in 512 byte chunks, then",
  32. "  rewinds it  and reads it back.  [The size of the file should be",
  33. "  big enough to factor out the effect of any disk cache.]",
  34. "        ",
  35. "  The file is written (filling any cache buffers), and then read.  If the",
  36. "  cache is >= 4 MB, then most if not all the reads will be satisfied from",
  37. "  the cache.  However, if it is less than or equal to 2 MB, then NONE of",
  38. "  the reads will be satisfied from the cache.  This is becase after the ",
  39. "  file is written, a 2 MB cache will contain the upper 2 MB of the test",
  40. "  file, but we will start reading from the beginning of the file (data",
  41. "  which is no longer in the cache)",
  42. "        ",
  43. "     NOTE: as of V1.04 default file size is now 1 MB not 4 MB",
  44. "        ",
  45. "  In order for this to be a fair test, the length of the test file must",
  46. "  be AT LEAST 2X the amount of disk cache memory for your system.  If",
  47. "  not, you are really testing the speed at which your CPU can read blocks",
  48. "  out of the cache (not a fair test)",
  49. "        ",
  50. "  IOZONE does NOT test the raw I/O speed of your disk or system.  It",
  51. "  tests the speed of sequential I/O to actual files.  Therefore, this",
  52. "  measurement factors in the efficiency of you machines file system,",
  53. "  operating system, C compiler, and C runtime library.  It produces a ",
  54. "  measurement which is the number of bytes per second that your system",
  55. "  can read or write to a file.  ",
  56. " ",
  57. "  For V1.06, IOZONE adds the 'auto test' feature.  This is activated",
  58. "  by the command:  'iozone auto' .  The auto test runs IOZONE repeatedly  ",
  59. "  using record sizes from 512 to 8192 bytes, and file sizes from 1 to 16",
  60. "  megabytes.  It creates a table of results.",
  61. "        ",
  62. "  For V1.06, IOZONE lets you specify the number of file system sizes and      ",
  63. "  record lengths to test when using auto mode.  Define the constants",
  64. "  MEGABYTES_ITER_LIMIT and RECLEN_ITER_LIMIT as seen below      ",
  65. "        ",
  66. "  For V1.09 you can show the development help by typing 'iozone help'",
  67. "        ",
  68. "  For V1.10 IOzone traps SIGINT (user interrupt) and SIGTERM",
  69. "  (kill from shell) signals and deletes the temporary file",
  70. "        ",
  71. "  This program has been ported and tested on the following computer",
  72. "  operating systems:",
  73. " ",
  74. "    Vendor        Operating System    Notes on compiling IOzone",
  75. "    -------------------------------------------------------------------------",
  76. "    Convergent        Unisys/AT&T Sys5r3  cc -DCONVERGENT -o iozone iozone.c",
  77. "    Digital Equipment    ULTRIX V4.1 ",    
  78. "    Digital Equipment    VAX/VMS V5.4        see below **     ",
  79. "    Digital Equipment    VAX/VMS (POSIX) ",
  80. "    Hewlett-Packard    HP-UX 7.05",
  81. "    IBM            AIX Ver. 3 rel. 1   cc -Dunix -o iozone iozone.c",
  82. "    Microsoft        MS-DOS 3.3        tested Borland, Microsoft C",
  83. "    OSF            OSF/1",
  84. "    SCO            UNIX System V/386 3.2.2",
  85. "    SCO            XENIX 3.2",
  86. "    Silicon Graphics    UNIX            cc -DSGI -o iozone iozone.c",
  87. "    Sun Microsystems    SUNOS 4.1.1",
  88. "        ",
  89. "    ** for VMS, define iozone as a foreign command via this DCL command:       ",
  90. " ",
  91. "     $IOZONE :== $SYS$DISK:[]IOZONE.EXE      ",
  92. " ",
  93. "     this lets you pass the command line arguments to IOZONE",
  94. " ",
  95. "  Acknowledgements to the following persons for their feedback on IOzone:       ",
  96. " ",
  97. "  Andy Puchrik, Michael D. Lawler, Krishna E. Bera, Sam Drake, John H. Hartman, ",
  98. "  Ted Lyszczarz, Bill Metzenthen, Jody Winston, Clarence Dold",
  99. "        ",
  100. "  --- MODIFICATION HISTORY:",
  101. " ",
  102. " ",
  103. "    3/7/91 William D. Norcott (Bill.Norcott@nuo.mts.dec.com)",
  104. "         created",
  105. " ",
  106. "    3/22/91 Bill Norcott        tested on OSF/1 ... it works",
  107. " ",
  108. "    3/24/91 Bill Norcott        V1.02 -- use calloc in TURBOC to",
  109. "                     fix bug with their malloc",
  110. " ",
  111. "    3/25/91 Bill Norcott        V1.03 -- add ifdef for XENIX",
  112. "                     ",
  113. "    3/27/91 Bill Norcott    V1.04 -- Includes for SCO UNIX",
  114. "                     ",
  115. "    4/26/91 Bill Norcott    V1.05 -- support AIX and SUNos, check",
  116. "                     length of read() and write()",
  117. "    4/26/91 Bill Norcott    V1.06 -- tabulate results of a series ",
  118. "                     of tests",
  119. "    5/17/91 Bill Norcott    V1.07 -- use time() for VMS",
  120. "    5/20/91 Bill Norcott    V1.08 -- use %ld for Turbo C and",
  121. "                     use #ifdef sun to bypass",
  122. "                     inclusion of limits.h",
  123. "    6/19/91 Bill Norcott    V1.09 -- rid #elif to support HP-UX and ",
  124. "                     Silicon Graphics UNIX, and",
  125. "                     add #ifdef SGI",
  126. "                     add #ifdef CONVERGENT",
  127. "                    for Convergent Technologies",
  128. "                     also add help option",
  129. "    7/2/91 Bill Norcott        V1.10 -- delete file if get SIGINT",
  130. "                     or SIGTERM",
  131. "" };
  132.  
  133. /******************************************************************
  134.  
  135.     INCLUDE FILES (system-dependent)
  136.  
  137. ******************************************************************/
  138. #include <signal.h>
  139. #ifdef    __MSDOS__        /* Turbo C define this way for PCs... */
  140. #define    MSDOS            /* Microsoft C defines this */
  141. #endif
  142. /* VMS and MS-DOS both have ANSI C compilers and use rand()/srand() */
  143. #ifdef    VMS_POSIX
  144. #undef   VMS
  145. #define    ANSI_RANDOM    1
  146. #endif
  147. #ifdef    MSDOS
  148. #define    ANSI_RANDOM    1
  149. #endif
  150. /* Convergent Technologies M680xx based with Unisys/AT&T Sys5r3 */
  151. #ifdef CONVERGENT
  152. #include <fcntl.h>
  153. #define SysVtime
  154. #endif 
  155. /* incl definitions of O_* flags for XENIX */
  156. #ifdef M_XENIX
  157. #include <fcntl.h>
  158. #endif
  159. /* SCO Unix System V */
  160. #ifdef M_UNIX
  161. #include <sys/types.h>
  162. #include <sys/fcntl.h>
  163. #endif
  164.  
  165. #if defined(VMS)
  166. #define    ANSI_RANDOM    1
  167. #include    <math.h>
  168. #include    <unixio.h>
  169. #include    <ssdef.h>
  170. #include    <file.h>
  171. #include    <time.h>
  172.  
  173. #else
  174. #ifdef MSDOS
  175. /* #elif defined(MSDOS) */
  176. #include <fcntl.h>
  177. #include <time.h>
  178. #endif
  179. /* #elif defined(unix) */
  180. #ifdef unix
  181. #include <sys/file.h>
  182. #ifndef NULL
  183. #define NULL 0
  184. #endif
  185. #endif
  186. /* 
  187. define nolimits if your system has no limits.h.  Sun's don't but I
  188. take care of this explicitly beginning with V1.08 of IOzone.
  189. */
  190. #ifdef sun
  191. #define nolimits
  192. #define BSDtime
  193. #endif
  194. /* V1.09 -- Silicon Graphics compile with -DSGI  */
  195. #ifdef SGI
  196. #define nolimits
  197. #define BSDtime
  198. #endif
  199. #ifndef nolimits
  200. #include <limits.h>
  201. #endif
  202. #endif
  203. /* for systems with System V-style time, define SysVtime */
  204. #ifdef M_SYSV
  205. #define SysVtime
  206. #endif
  207.  
  208. #ifdef SysVtime
  209. #include <sys/times.h>
  210. #include <sys/param.h>
  211. #ifndef CLK_TCK
  212. #define CLK_TCK HZ
  213. #endif
  214. #endif
  215. /* for systems with BSD style time, define BSDtime */
  216. #ifdef bsd4_2
  217. #define BSDtime
  218. #endif
  219. #ifdef BSDtime
  220. #include <sys/time.h>
  221. #endif
  222.  
  223.  
  224. /******************************************************************
  225.  
  226.     DEFINED CONSTANTS
  227.  
  228. ******************************************************************/
  229. #define MEGABYTES 1            /* number of megabytes in file */
  230. #define RECLEN 512            /* number of bytes in a record */
  231. #define FILESIZE (MEGABYTES*1024*1024)    /*size of file in bytes*/
  232. #define NUMRECS FILESIZE/RECLEN        /* number of records */
  233. #define MAXBUFFERSIZE 16*1024        /*maximum buffer size*/
  234. #define MINBUFFERSIZE 128
  235. #define TOOFAST 10
  236. #define USAGE  "\tUsage:\tiozone [megabytes] [record_length_in_bytes] \
  237. [[path]filename]\n\t\tiozone auto\n\t\tiozone help\n\n"
  238. #define THISVERSION "V1.10"
  239.  
  240. /* Define only one of the following two.  All modern operating systems
  241. have time functions so let TIME be defined */
  242. #if 1
  243. #define TIME 1
  244. #else
  245. #define NOTIME 1
  246. #endif
  247.  
  248. #define MAXNAMESIZE 1000                /* max # of characters in filename */
  249. #define CONTROL_STRING1 "\t%-8ld%-8ld%-20ld%-20ld\n"
  250. #define CONTROL_STRING2 "\t%-8s%-8s%-20s%-20s\n"
  251. /* 
  252.     For 'auto mode', these defines determine the number of iterations
  253.     to perform for both the file size and the record length.
  254.     I.e., if MEGABYTES_ITER_LIMIT = 5 use 1, 2, 4, 8 & 16 megabyte files
  255.     if RECLEN_ITER_LIMIT = 5 use 512, 1024, 2048, 4096 & 8192 byte records
  256. */ 
  257. #define MEGABYTES_ITER_LIMIT 5
  258. #define RECLEN_ITER_LIMIT 5
  259.  
  260. /******************************************************************
  261.  
  262.     FUNCTION DECLARATIONS
  263.  
  264. ******************************************************************/
  265. void auto_test();        /* perform automatic test series */
  266. void show_help();        /* show development help*/
  267. static double time_so_far();    /* time since start of program */
  268. void signal_handler();        /* clean up if user interrupts us */
  269. /******************************************************************
  270.  
  271.     GLOBAL VARIABLES
  272.  
  273. ******************************************************************/
  274. int auto_mode;
  275. char filename [MAXNAMESIZE];            /* name of temporary file */
  276.  
  277. /******************************************************************
  278.  
  279.     MAIN -- entry point
  280.  
  281. ******************************************************************/
  282. main(argc,argv) 
  283.       int argc;
  284.      char *argv[];
  285. {
  286. int fd;
  287. char *default_filename="iozone.tmp"; /*default name of temporary file*/
  288.  
  289. #ifdef    MSDOS
  290. char *buffer; 
  291. #else
  292. char buffer [MAXBUFFERSIZE];        /*a temporary data buffer*/
  293. #endif
  294. int i, status;
  295. unsigned long megabytes = MEGABYTES, goodmegs;
  296. unsigned long reclen = RECLEN, goodrecl;
  297. unsigned long filesize = FILESIZE;
  298. unsigned long numrecs = NUMRECS;
  299. unsigned long filebytes;
  300. unsigned long readrate, writerate;
  301. #ifdef TIME
  302.  double starttime1, starttime2;
  303.  double writetime, readtime;
  304.  double totaltime;
  305.  
  306. #endif
  307.  
  308. #ifdef MSDOS
  309.   buffer = (char *) calloc(1, MAXBUFFERSIZE);
  310. #endif
  311.  
  312.   if (!auto_mode)
  313.   {
  314.     printf("\n\tIOZONE: Performance Test of Sequential File I/O  --  %s\n",
  315.           THISVERSION);
  316.     printf("\t\tBy Bill Norcott\n\n");
  317.  
  318.     signal(SIGINT, signal_handler);     /* handle user interrupt */
  319.     signal(SIGTERM, signal_handler);     /* handle kill from shell */
  320.   }
  321.   strcpy(filename,default_filename);
  322.   switch (argc) {
  323.     case 1:       /* no args, take all defaults */
  324.       printf(USAGE);
  325.     break;
  326.     case 2:     /* <megabytes|filename> */
  327.     i = atoi(argv[1]); if (i) {
  328.       megabytes = i;
  329.     } else {
  330. /*
  331. 'Auto mode' will be enabled if the first command line argument is
  332. the word 'auto'.  This will trigger a series of tests
  333. */
  334.       if ( (strcmp(argv[1], "auto") == 0) || 
  335.            (strcmp(argv[1], "AUTO") == 0) )
  336.       {
  337.         auto_mode = 1;
  338.         auto_test();
  339.         printf("Completed series of tests\n");
  340.         exit(0);
  341.       } else {
  342.         auto_mode = 0;
  343.       }
  344.       if ( (strcmp(argv[1], "help") == 0) || 
  345.            (strcmp(argv[1], "HELP") == 0) )
  346.       {
  347.         show_help();
  348.         exit(0);
  349.       }
  350.       strcpy(filename,argv[1]);
  351.         }
  352.     break;
  353.     case 3:     /* <megabytes> <reclen|filename> */
  354.     megabytes = atoi(argv[1]);
  355.     if (atoi(argv[2])) {
  356.       reclen = atoi(argv[2]);
  357.     } else {
  358.       strcpy(filename,argv[2]);
  359.     }
  360.     break;
  361.     case 4:     /* <megabytes> <reclen> <filename> */
  362.     megabytes = atoi(argv[1]);
  363.     reclen = atoi(argv[2]);
  364.     strcpy(filename,argv[3]);
  365.     break;
  366.     default:
  367.       printf("IOZONE: bad usage\n");
  368.       printf(USAGE);
  369.       exit(1);
  370.  
  371.   }
  372.   if (!auto_mode)
  373.   {
  374.     printf("\tSend comments to:\tBill.Norcott@nuo.mts.dec.com\n\n");
  375.   }
  376.   filesize = megabytes*1024*1024;
  377.   numrecs = filesize/reclen;
  378.   if (reclen >  MAXBUFFERSIZE) {
  379.     printf("Error: Maximum record length is %d bytes\n", MAXBUFFERSIZE);
  380.         exit(1);
  381.     }
  382.   if (reclen < MINBUFFERSIZE) {
  383.     printf("Error: Minimum record length is %d bytes\n", MINBUFFERSIZE);
  384.         exit(1);
  385.     }
  386.   if (!auto_mode)
  387.   {
  388.     printf("\tIOZONE writes a %ld Megabyte sequential file consisting of\n",
  389.     megabytes);
  390.     printf("\t%ld records which are each %ld bytes in length.\n",
  391.     numrecs, reclen);
  392.     printf("\tIt then reads the file.  It prints the bytes-per-second\n");
  393.     printf("\trate at which the computer can read and write files.\n\n");
  394.     printf("\nWriting the %ld Megabyte file, '%s'...", megabytes, filename);
  395.   }  
  396.     if((fd = creat(filename, 0640))<0){
  397.         printf("Cannot create temporary file: %s\n", filename);
  398.         exit(1);
  399.     }
  400. #ifdef TIME
  401.     starttime1 = time_so_far();
  402. #endif
  403.     for(i=0; i<numrecs; i++){
  404. #ifndef DEBUG_ME
  405.         if(write(fd, buffer, (unsigned) reclen) != reclen)
  406.             {
  407.             printf("Error writing block %d\n", i);
  408.             exit(1);
  409.             }
  410. #endif
  411.     }
  412.  
  413. #ifdef TIME
  414.     writetime = time_so_far() - starttime1;
  415.     if (!auto_mode)
  416.         {
  417.         printf("%f seconds", writetime);
  418.         }
  419. #endif
  420.     close(fd);
  421. #if defined (VMS)
  422.     if((fd = open(filename, O_RDONLY, 0640))<0){
  423.         printf("Cannot open temporary file for read\n");
  424.         exit(1);
  425.     }
  426. #else
  427. #ifdef MSDOS
  428. /* #elif defined(MSDOS) */
  429.     if((fd = open(filename, O_RDONLY, 0640))<0){
  430.         printf("Cannot open temporary file for read\n");
  431.         exit(1);
  432.     }
  433. #else
  434.     if((fd = open(filename, O_RDONLY))<0){
  435.         printf("Cannot open temporary file for read\n");
  436.         exit(1);
  437.        }
  438. #endif
  439. #endif
  440.  
  441.  
  442.             /*start timing*/
  443. #if defined(NOTIME)
  444.     printf("start timing\n");
  445. #endif
  446.     if (!auto_mode)
  447.     {
  448.         printf("\nReading the file...");
  449.     }
  450.     starttime2 = time_so_far();
  451.    for(i=0; i<numrecs; i++) {
  452. #ifndef DEBUG_ME
  453.     if(read(fd, buffer, (unsigned) reclen) != reclen)
  454.     {
  455.         printf("Error reading block %d\n", i);
  456.         exit(1);
  457.     }
  458. #endif
  459.     }
  460. #ifdef NOTIME
  461.     printf("stop timing\n");
  462. #endif
  463. #ifdef TIME
  464.     readtime = time_so_far() - starttime2;
  465.     if (!auto_mode)
  466.     {
  467.         printf("%f seconds\n", readtime);
  468.     }
  469. #ifdef DEBUG_ME
  470.     readtime = 1;
  471.     writetime = 1;
  472. #endif
  473.     if(readtime!=0)
  474.     {   
  475.         filebytes = numrecs*reclen;
  476.         readrate = (unsigned long) ((double) filebytes / readtime);
  477.         writerate = (unsigned long) ((double) filebytes / writetime);
  478.         if (auto_mode)
  479.         {
  480.          printf(CONTROL_STRING1,
  481.             megabytes, 
  482.             reclen,
  483.             writerate,
  484.             readrate);
  485.                     
  486.         } else {
  487.         printf("\nIOZONE performance measurements:\n");
  488.         printf("\t%ld bytes/second for writing the file\n", writerate);
  489.         printf("\t%ld bytes/second for reading the file\n", readrate);
  490.         totaltime = readtime + writetime;
  491.         if (totaltime < TOOFAST) 
  492.         {
  493.             goodmegs = (TOOFAST/totaltime)*2*megabytes;
  494.             printf("\nThe test completed too quickly to give a good result\n");
  495.             printf("You will get a more precise measure of this machine's\n");
  496.             printf("performance by re-running IOZONE using the command:\n");
  497.             printf("\n\tiozone %ld ", goodmegs);
  498.             printf("\t(i.e., file size = %ld megabytes)\n", goodmegs);
  499.         }
  500.         }
  501.     } else {
  502.         goodrecl = reclen/2;
  503.         printf("\nI/O error during read.  Try again with the command:\n");
  504.         printf("\n\tiozone %ld %ld ", megabytes,  goodrecl);
  505.         printf("\t(i.e. record size = %ld bytes)\n",  goodrecl);
  506.     }
  507. #endif
  508.     close(fd);
  509. #ifndef VMS
  510.     unlink(filename);    /* delete the file */
  511.                     /*stop timer*/
  512. #endif
  513. #ifdef    MSDOS
  514.     free(buffer);        /* deallocate the memory */
  515. #endif
  516. #ifdef VMS
  517. return SS$_NORMAL;
  518. #else
  519. return 0;
  520. #endif
  521. }
  522. /******************************************************************
  523.  
  524.     SHOW_HELP -- show development help of this program
  525.  
  526. ******************************************************************/
  527. void show_help()
  528. {
  529.     int i;
  530.     printf("IOZONE: help mode\n\n");
  531.     for(i=0; strlen(help[i]); i++)
  532.     {
  533.     printf("%s\n", help[i]);
  534.     }
  535. }
  536. /******************************************************************
  537.  
  538.     SIGNAL_HANDLER -- clean up if user interrupts the program
  539.  
  540. ******************************************************************/
  541. void signal_handler()
  542. {
  543.     int i;
  544.     printf("\nIOZONE: interrupted\n\n");
  545. #ifndef VMS
  546.     printf("deleting file: %s\n", filename);
  547.     unlink(filename);    /* delete the file */
  548. #endif
  549.     printf("exiting IOzone\n\n");
  550.     exit();
  551. }
  552. /******************************************************************
  553.  
  554.     AUTO_TEST -- perform series of tests and tabulate results
  555.  
  556. ******************************************************************/
  557. void auto_test()
  558. {
  559.     int megsi, recszi;
  560.     char megs[10]; 
  561.     char recsz[10];
  562.     int i,j;
  563.     int argc = 3;
  564.     char *argv[3];
  565.     
  566.     printf("IOZONE: auto-test mode\n\n");
  567.     printf(CONTROL_STRING2,
  568.     "MB", 
  569.     "reclen",
  570.     "bytes/sec written",
  571.     "bytes/sec read");
  572.     argv[0] = "IOzone auto-test";
  573.     argv[1] = megs;
  574.     argv[2] = recsz;
  575. /*
  576. Start with file size of 1 megabyte and repeat the test MEGABYTES_ITER_LIMIT
  577. times.  Each time we run, the file size is doubled
  578. */
  579.     for(i=0,megsi=1;i<MEGABYTES_ITER_LIMIT;i++,megsi*=2) 
  580.     {
  581.     sprintf(megs, "%d", megsi);
  582. /*
  583. Start with record size of 512 bytes and repeat the test RECLEN_ITER_LIMIT
  584. times.  Each time we run, the record size is doubled
  585. */
  586.     for (j=0,recszi=512;j<RECLEN_ITER_LIMIT;j++,recszi*=2)
  587.     {
  588.         sprintf(recsz, "%d", recszi);
  589.         main(argc, argv);
  590.     }
  591.     }
  592. }
  593.  
  594. static double
  595. time_so_far()
  596. {
  597. #if defined(VMS)
  598. /* 
  599. *   5/17/91 Bill Norcott    V1.07 -- use time() for VMS
  600. The times() function in VMS returns proc & user CPU time in 10-millisecond
  601. ticks.  Instead, use time() which lacks the precision but gives clock
  602. time in seconds.
  603. */
  604.  
  605.   return (double) time(NULL);
  606.  
  607. #else
  608. #ifdef SysVtime
  609. /* #elif defined(SysVtime) */
  610.   int        val;
  611.   struct tms tms;
  612.  
  613.   if ((val = times(&tms)) == -1)
  614.     perror("times");
  615.  
  616.   return ((double) val) / ((double) CLK_TCK);
  617. #endif
  618. #if defined(MSDOS)
  619.   return ((double) clock()) / ((double) CLK_TCK);
  620. #endif
  621. #ifndef MSDOS
  622. #ifndef SysVtime
  623. /* #else */
  624.   struct timeval tp;
  625.  
  626.   if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
  627.     perror("gettimeofday");
  628.   return ((double) (tp.tv_sec)) +
  629.     (((double) tp.tv_usec) / 1000000.0);
  630. #endif
  631. #endif
  632. #endif
  633. }
  634.  
  635.