home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / diski117.zip / diskio.c < prev    next >
C/C++ Source or Header  |  1999-10-28  |  26KB  |  1,079 lines

  1. /* diskio.c - disk benchmark
  2.  *
  3.  * Author:  Kai Uwe Rommel <rommel@ars.muc.de>
  4.  * Created: Fri Jul 08 1994
  5.  */
  6.  
  7. static char *rcsid =
  8. "$Id: diskio.c,v 1.17 1999/10/28 17:33:33 rommel Exp rommel $";
  9. static char *rcsrev = "$Revision: 1.17 $";
  10.  
  11. /*
  12.  * $Log: diskio.c,v $
  13.  * Revision 1.17  1999/10/28 17:33:33  rommel
  14.  * corrected OS/2 timer code
  15.  *
  16.  * Revision 1.16  1999/10/25 08:36:28  rommel
  17.  * corrected timer code for NT
  18.  *
  19.  * Revision 1.15  1998/07/05 07:44:17  rommel
  20.  * added Windows NT version
  21.  * added multi disk benchmark
  22.  * added preliminary multi thread I/O benchmark
  23.  * many fixes
  24.  * general cleanup
  25.  *
  26.  * Revision 1.14  1998/01/05 18:04:04  rommel
  27.  * add fix for CD-ROM size detection problem
  28.  *
  29.  * Revision 1.13  1997/03/01 20:36:55  rommel
  30.  * handle media access errors more gracefully
  31.  *
  32.  * Revision 1.12  1997/03/01 20:21:35  rommel
  33.  * catch a few bugs and obscure situations,
  34.  * increase accuracy, too
  35.  *
  36.  * Revision 1.11  1997/02/09 15:06:38  rommel
  37.  * changed command line interface
  38.  *
  39.  * Revision 1.10  1997/01/12 21:15:10  rommel
  40.  * added CD-ROM benchmarks
  41.  *
  42.  * Revision 1.9  1995/12/31 20:24:09  rommel
  43.  * Changed CPU load calculation
  44.  * General cleanup
  45.  *
  46.  * Revision 1.8  1995/12/28 11:28:07  rommel
  47.  * Fixed async timer problem.
  48.  *
  49.  * Revision 1.7  1995/12/28 10:04:15  rommel
  50.  * Added CPU benchmark (concurrently to disk I/O)
  51.  *
  52.  * Revision 1.6  1995/11/24 16:02:10  rommel
  53.  * Added bus/drive cache speed test by 
  54.  * repeatedly reading a small amount of data
  55.  *
  56.  * Revision 1.5  1995/08/09 13:07:02  rommel
  57.  * Changes for new diskacc2 library, minor corrections, arguments.
  58.  *
  59.  * Revision 1.4  1994/07/11 14:23:00  rommel
  60.  * Changed latency timing
  61.  *
  62.  * Revision 1.3  1994/07/09 13:07:20  rommel
  63.  * Changed transfer speed test
  64.  *
  65.  * Revision 1.2  1994/07/08 21:53:05  rommel
  66.  * Cleanup
  67.  *
  68.  * Revision 1.1  1994/07/08 21:29:41  rommel
  69.  * Initial revision
  70.  * 
  71.  */
  72.  
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76.  
  77. #include "diskacc.h"
  78.  
  79. #define INTERVAL     10
  80. #define MAXTHREADS   4
  81. #define THREADSTACK  65536
  82.  
  83. char *pBuffer;
  84.  
  85. int time_over;
  86. long dhry_result, dhry_stones;
  87.  
  88. extern unsigned long Number_Of_Runs;
  89. extern long dhry_stone(void);
  90.  
  91. #ifdef OS2
  92.  
  93. #define INCL_DOS
  94. #define INCL_DOSDEVICES
  95. #define INCL_DOSDEVIOCTL
  96. #define INCL_DOSERRORS
  97. #define INCL_NOPM
  98. #include <os2.h>
  99.  
  100. #define idle_priority() \
  101.   DosSetPriority(PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MAXIMUM, 0)
  102. #define normal_priority() \
  103.   DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0)
  104.  
  105. typedef HEV semaphore;
  106. static ULONG nSemCount;
  107. #define create_sem(phsem) \
  108.   DosCreateEventSem(0, phsem, 0, FALSE)
  109. #define destroy_sem(hsem) \
  110.   DosCloseEventSem(hsem)
  111. #define post_sem(hsem) \
  112.   DosPostEventSem(hsem)
  113. #define reset_sem(hsem) \
  114.   DosResetEventSem(hsem, nSemCount)
  115. #define wait_sem(hsem) \
  116.   DosWaitEventSem(hsem, SEM_INDEFINITE_WAIT)
  117.  
  118. typedef QWORD TIMER;
  119.  
  120. HEV hSemTimer;
  121.  
  122. VOID APIENTRY timer_thread(ULONG nArg)
  123. {
  124.   HTIMER hTimer;
  125.  
  126.   DosCreateEventSem(0, &hSemTimer, DC_SEM_SHARED, 0);
  127.   DosAsyncTimer(nArg * 1000, (HSEM) hSemTimer, &hTimer);
  128.   DosWaitEventSem(hSemTimer, SEM_INDEFINITE_WAIT);
  129.   DosStopTimer(hTimer);
  130.   DosCloseEventSem(hSemTimer);
  131.  
  132.   time_over = 1;
  133.   Number_Of_Runs = 0;
  134.  
  135.   DosExit(EXIT_THREAD, 0);
  136. }
  137.  
  138. int start_alarm(ULONG nSeconds)
  139.   TID ttid;
  140.  
  141.   time_over = 0;
  142.   Number_Of_Runs = -1;
  143.  
  144.   if (DosCreateThread(&ttid, timer_thread, nSeconds, 0, THREADSTACK))
  145.     return printf("Cannot create timer thread.\n"), -1;
  146.  
  147.   return 0;
  148. }
  149.  
  150. void stop_alarm(void)
  151. {
  152.   DosPostEventSem(hSemTimer);
  153. }
  154.  
  155. int start_timer(TIMER *nStart)
  156. {
  157.   if (DosTmrQueryTime(nStart))
  158.     return printf("Timer error.\n"), -1;
  159.  
  160.   return 0;
  161. }
  162.  
  163. int stop_timer(TIMER *nStart, int accuracy)
  164. {
  165.   TIMER nStop;
  166.   ULONG nFreq;
  167.  
  168.   if (DosTmrQueryTime(&nStop))
  169.     return printf("Timer error.\n"), -1;
  170.   if (DosTmrQueryFreq(&nFreq))
  171.     return printf("Timer error.\n"), -1;
  172.  
  173.   nFreq = (nFreq + accuracy / 2) / accuracy;
  174.  
  175.   return (* (__int64*) &nStop - * (__int64*) nStart) / nFreq;
  176. }
  177.  
  178. #endif
  179.  
  180. #ifdef WIN32
  181.  
  182. /* the following perhaps only works with IBM's compiler */
  183. #define _INTEGRAL_MAX_BITS 64
  184. #include <windows.h>
  185.  
  186. #define idle_priority() \
  187.   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE)
  188. #define normal_priority() \
  189.   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL)
  190.  
  191. typedef HANDLE semaphore;
  192. #define create_sem(phsem) \
  193.   (*(phsem) = CreateEvent(0, TRUE, FALSE, 0))
  194. #define destroy_sem(hsem) \
  195.   CloseHandle(hsem)
  196. #define post_sem(hsem) \
  197.   SetEvent(hsem)
  198. #define reset_sem(hsem) \
  199.   ResetEvent(hsem)
  200. #define wait_sem(hsem) \
  201.   WaitForSingleObject(hsem, INFINITE)
  202.  
  203. typedef LARGE_INTEGER TIMER;
  204.  
  205. HANDLE hTimerThread;
  206.  
  207. DWORD CALLBACK timer_thread(void * pArg)
  208. {
  209.   Sleep((UINT) pArg * 1000);
  210.  
  211.   time_over = 1;
  212.   Number_Of_Runs = 0;
  213.  
  214.   return 0;
  215. }
  216.  
  217. int start_alarm(long nSeconds)
  218.   DWORD ttid;
  219.  
  220.   time_over = 0;
  221.   Number_Of_Runs = -1;
  222.  
  223.   hTimerThread = CreateThread(0, THREADSTACK, timer_thread, (void *) nSeconds, 0, &ttid);
  224.  
  225.   if (hTimerThread == NULL)
  226.     return printf("Cannot create timer thread.\n"), -1;
  227.  
  228.   return 0;
  229. }
  230.  
  231. void stop_alarm(void)
  232. {
  233.   TerminateThread(hTimerThread, 0);
  234.  
  235.   time_over = 1;
  236.   Number_Of_Runs = 0;
  237. }
  238.  
  239. int start_timer(TIMER *nStart)
  240. {
  241.   if (!QueryPerformanceCounter(nStart))
  242.     return printf("Timer error.\n"), -1;
  243.  
  244.   return 0;
  245. }
  246.  
  247. unsigned long stop_timer(TIMER *nStart, int nAccuracy)
  248. {
  249.   TIMER nStop, nFreq;
  250.  
  251.   if (!QueryPerformanceCounter(&nStop))
  252.     return printf("Timer error.\n"), -1;
  253.   if (!QueryPerformanceFrequency(&nFreq))
  254.     return printf("Timer error.\n"), -1;
  255.  
  256.   nFreq.QuadPart = (nFreq.QuadPart + nAccuracy / 2) / nAccuracy;
  257.  
  258.   return (nStop.QuadPart - nStart->QuadPart) / nFreq.QuadPart;
  259. }
  260.  
  261. #endif
  262.  
  263. typedef struct 
  264. {
  265.   int nHandle, nData, nCnt;
  266.   unsigned nSector, nSides, nSectors, nTracks;
  267.   void *pBuffer;
  268.   semaphore sDone;
  269. }
  270. THREADPARMS;
  271.  
  272. void run_dhrystone(void)
  273. {
  274.   long dhry_time = dhry_stone();
  275.  
  276.   /* originally, time is measured in ms */
  277.   dhry_time = (dhry_time + 5) / 10;
  278.   /* now it is in units of 10 ms */
  279.  
  280.   if (dhry_time == 0)
  281.     dhry_time = 1; /* if less than 10 ms, then assume at least 10 ms */
  282.  
  283.   /* now calculate runs per second */
  284.   dhry_stones = Number_Of_Runs * 100 / dhry_time;
  285.   /* by the time we cross 20 million dhrystones per second with a CPU, 
  286.      we will hopefully have only 64-bit machines to run this on ... */
  287. }
  288.  
  289. void dhry_thread(void *nArg)
  290. {
  291.   idle_priority();
  292.   run_dhrystone();
  293.  
  294.   _endthread();
  295. }
  296.  
  297. int bench_hd_bus(int nHandle, unsigned nSides, unsigned nSectors, unsigned nSector)
  298. {
  299.   int nCnt = 0, nData = 0, nTime, nTrack;
  300.   TIMER nLocal;
  301.  
  302.   printf("Drive cache/bus transfer rate: ");
  303.   fflush(stdout);
  304.  
  305.   if (start_alarm(INTERVAL))
  306.     return -1;
  307.  
  308.   if (start_timer(&nLocal))
  309.     return -1;
  310.  
  311.   while (!time_over)
  312.   {
  313.     if (DskRead(nHandle, 0, 0, 1, nSectors, pBuffer))
  314.     {
  315.       stop_alarm();
  316.       printf("Disk read error.\n");
  317.       return -1;
  318.     }
  319.  
  320.     nData += nSectors * nSector;
  321.   }
  322.  
  323.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  324.     return -1;
  325.  
  326.   printf("%d k/sec\n", nData / nTime);
  327.  
  328.   return 0;
  329. }
  330.  
  331. int bench_hd_transfer(int nHandle, int nTrack, int nDirection, 
  332.               unsigned nSides, unsigned nSectors, unsigned nSector)
  333. {
  334.   int nCnt, nData = 0, nTime;
  335.   TIMER nLocal;
  336.  
  337.   printf("Data transfer rate on cylinder %-4d: ", nTrack);
  338.   fflush(stdout);
  339.  
  340.   if (start_alarm(INTERVAL))
  341.     return -1;
  342.  
  343.   if (start_timer(&nLocal))
  344.     return -1;
  345.  
  346.   for (nCnt = 0; !time_over; nCnt++)
  347.   {
  348.     if (DskRead(nHandle, nCnt % nSides, 
  349.         nTrack + (nCnt / nSides) * nDirection, 1, nSectors, pBuffer))
  350.     {
  351.       stop_alarm();
  352.       printf("Disk read error.\n");
  353.       return -1;
  354.     }
  355.  
  356.     nData += nSectors * nSector;
  357.   }
  358.  
  359.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  360.     return -1;
  361.  
  362.   printf("%d k/sec\n", nData / nTime);
  363.  
  364.   return 0;
  365. }
  366.  
  367. int bench_hd_cpuusage(int nHandle, unsigned nSides, 
  368.               unsigned nSectors, unsigned nSector)
  369. {
  370.   int nCnt, nData = 0, nTime, nPercent;
  371.   TIMER nLocal;
  372.  
  373.   printf("CPU usage by full speed disk transfers: ");
  374.   fflush(stdout);
  375.  
  376.   if (start_alarm(INTERVAL))
  377.     return -1;
  378.  
  379.   if (_beginthread(dhry_thread, 0, THREADSTACK, 0) == -1)
  380.     return -1;
  381.  
  382.   if (start_timer(&nLocal))
  383.     return -1;
  384.  
  385.   for (nCnt = 0; !time_over; nCnt++)
  386.   {
  387.     if (DskRead(nHandle, nCnt % nSides, nCnt / nSides, 1, nSectors, pBuffer))
  388.     {
  389.       stop_alarm();
  390.       printf("Disk read error.\n");
  391.       return -1;
  392.     }
  393.  
  394.     nData += nSectors * nSector;
  395.   }
  396.  
  397.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  398.     return -1;
  399.  
  400.   nPercent = (dhry_result - dhry_stones) * 100 / dhry_result;
  401.  
  402.   printf("%d%%\n", nPercent);
  403.  
  404.   return 0;
  405. }
  406.  
  407. int bench_hd_latency(int nHandle, unsigned nTracks, unsigned nSides, unsigned nSectors)
  408. {
  409.   int nCnt, nSector, nTime;
  410.   TIMER nLocal;
  411.  
  412.   printf("Average latency time: ");
  413.   fflush(stdout);
  414.  
  415.   srand(1);
  416.  
  417.   if (start_alarm(INTERVAL))
  418.     return -1;
  419.  
  420.   if (start_timer(&nLocal))
  421.     return -1;
  422.  
  423.   for (nCnt = 0; !time_over; nCnt++)
  424.   {
  425.     nSector = rand() * nSectors / RAND_MAX + 1;
  426.  
  427.     if (DskRead(nHandle, 0, 0, nSector, 1, pBuffer))
  428.     {
  429.       stop_alarm();
  430.       printf("Disk read error.\n");
  431.       return -1;
  432.     }
  433.   }
  434.  
  435.   if ((nTime = stop_timer(&nLocal, 1000)) == -1)
  436.     return -1;
  437.  
  438.   nTime = nTime * 10 / nCnt;
  439.  
  440.   printf("%d.%d ms\n", nTime / 10, nTime % 10);
  441.  
  442.   return nTime;
  443. }
  444.  
  445. int bench_hd_seek(int nHandle, unsigned nTracks, unsigned nSides, unsigned nSectors)
  446. {
  447.   int nCnt, nSide, nTrack, nSector, nTime;
  448.   TIMER nLocal;
  449.  
  450.   printf("Average data access time: ");
  451.   fflush(stdout);
  452.  
  453.   srand(1);
  454.  
  455.   if (start_alarm(INTERVAL))
  456.     return -1;
  457.  
  458.   if (start_timer(&nLocal))
  459.     return -1;
  460.  
  461.   for (nCnt = 0; !time_over; nCnt++)
  462.   {
  463.     nSide   = rand() * nSides   / RAND_MAX;
  464.     nSector = rand() * nSectors / RAND_MAX;
  465.     nTrack  = rand() * nTracks  / RAND_MAX;
  466.  
  467.     if (DskRead(nHandle, nSide, nTrack, nSector, 1, pBuffer))
  468.     {
  469.       stop_alarm();
  470.       printf("Disk read error.\n");
  471.       return -1;
  472.     }
  473.   }
  474.  
  475.   if ((nTime = stop_timer(&nLocal, 1000)) == -1)
  476.     return -1;
  477.  
  478.   nTime = nTime * 10 / nCnt;
  479.  
  480.   printf("%d.%d ms\n", nTime / 10, nTime % 10);
  481.  
  482.   return 0;
  483. }
  484.  
  485. void bench_hd_thread(void *pArg)
  486. {
  487.   THREADPARMS *ptr = (THREADPARMS *) pArg;
  488.   int nTrack, nSide;
  489.  
  490. #if 0
  491.   srand(1);
  492. #endif
  493.  
  494.   while (!time_over)
  495.   {
  496. #if 0
  497.     nTrack = rand() * ptr->nTracks / RAND_MAX;
  498.     nSide = rand() * ptr->nSides / RAND_MAX;
  499. #else
  500.     nTrack = ptr->nCnt / ptr->nSides;
  501.     nSide = ptr->nCnt % ptr->nSides;
  502.     ptr->nCnt += MAXTHREADS;
  503. #endif
  504.  
  505.     if (DskRead(ptr->nHandle, nSide, nTrack, 1, ptr->nSectors, ptr->pBuffer))
  506.     {
  507.       stop_alarm();
  508.       printf("Disk read error.\n");
  509.       break;
  510.     }
  511.  
  512.     ptr->nData += ptr->nSectors * ptr->nSector;
  513.   }
  514.  
  515.   post_sem(ptr->sDone);
  516.  
  517.   _endthread();
  518. }
  519.  
  520. int bench_hd_mthread(int nHandle, unsigned nTracks, unsigned nSides, 
  521.              unsigned nSectors, unsigned nSector)
  522. {
  523.   int nTime, nPercent, nCnt, nTotal;
  524.   THREADPARMS tHD[MAXTHREADS];
  525.   TIMER nLocal;
  526.  
  527.   printf("Multithreaded disk I/O (%d threads): ", MAXTHREADS);
  528.   fflush(stdout);
  529.  
  530.   for (nCnt = 0; nCnt < MAXTHREADS; nCnt++)
  531.   {
  532.     tHD[nCnt].nHandle  = nHandle;
  533.     tHD[nCnt].nTracks  = nTracks;
  534.     tHD[nCnt].nSides   = nSides;
  535.     tHD[nCnt].nSectors = nSectors;
  536.     tHD[nCnt].nSector  = nSector;
  537.     tHD[nCnt].nData    = 0;
  538.     tHD[nCnt].nCnt     = nCnt;
  539.  
  540.     if ((tHD[nCnt].pBuffer = DskAlloc(nSectors, nSector)) == NULL)
  541.       return printf("\nNot enough memory.\n"), -1;
  542.  
  543.     create_sem(&(tHD[nCnt].sDone));
  544.   }
  545.  
  546.   if (start_alarm(INTERVAL))
  547.     return -1;
  548.  
  549.   if (start_timer(&nLocal))
  550.     return -1;
  551.  
  552.   for (nCnt = 0; nCnt < MAXTHREADS; nCnt++)
  553.     if (_beginthread(bench_hd_thread, 0, THREADSTACK, tHD + nCnt) == -1)
  554.       return -1;
  555.  
  556.   idle_priority();
  557.   run_dhrystone();
  558.   normal_priority();
  559.  
  560.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  561.     return -1;
  562.  
  563.   nPercent = (dhry_result - dhry_stones) * 100 / dhry_result;
  564.   nTotal = 0;
  565.  
  566.   for (nCnt = 0; nCnt < MAXTHREADS; nCnt++)
  567.   {
  568.     wait_sem(tHD[nCnt].sDone);
  569.     destroy_sem(tHD[nCnt].sDone);
  570.  
  571.     DskFree(tHD[nCnt].pBuffer);
  572.  
  573.     nTotal += tHD[nCnt].nData;
  574.   }
  575.  
  576.   printf("%d k/sec, %d%% CPU usage\n", nTotal / nTime, nPercent);
  577.  
  578.   return 0;
  579. }
  580.  
  581. int bench_hd(int nDisk)
  582. {
  583.   int nHandle;
  584.   unsigned nSector, nSides, nTracks, nSectors;
  585.   char szName[8];
  586.  
  587.   sprintf(szName, "$%d:", nDisk);
  588.  
  589.   if ((nHandle = DskOpen(szName, 0, 0, &nSector, &nSides, &nTracks, &nSectors)) < 0)
  590.     return printf("\nCannot access disk %d.\n", nDisk), -1;
  591.  
  592.   printf("\nHard disk %d: %d sides, %d cylinders, %d sectors per track = %d MB\n", 
  593.      nDisk, nSides, nTracks, nSectors,
  594.      nSides * nTracks * nSectors / 2048);
  595.  
  596.   if ((pBuffer = DskAlloc(nSectors, nSector)) == NULL)
  597.     return printf("\nNot enough memory.\n"), -1;
  598.  
  599.   bench_hd_bus(nHandle, nSides, nSectors, nSector);
  600.   bench_hd_transfer(nHandle, 0, 1, nSides, nSectors, nSector);
  601.   bench_hd_transfer(nHandle, nTracks - 2, -1, nSides, nSectors, nSector);
  602.   bench_hd_cpuusage(nHandle, nSides, nSectors, nSector);
  603.   /* bench_hd_latency(nHandle, nTracks, nSides, nSectors); */
  604.   bench_hd_seek(nHandle, nTracks, nSides, nSectors);
  605.   bench_hd_mthread(nHandle, nTracks, nSides, nSectors, nSector);
  606.  
  607.   DskFree(pBuffer);
  608.   DskClose(nHandle);
  609.  
  610.   return 0;
  611. }
  612.  
  613. int bench_cd_transfer(int nHandle, int nStart, int nSectors)
  614. {
  615.   int nCnt, nData = 0, nTime, nRate;
  616.   TIMER nLocal;
  617.  
  618.   printf("Data transfer rate at sector %-8d: ", nStart);
  619.   fflush(stdout);
  620.   
  621.   if (start_alarm(INTERVAL))
  622.     return -1;
  623.  
  624.   if (start_timer(&nLocal))
  625.     return -1;
  626.  
  627.   for (nCnt = 0; !time_over; nCnt++)
  628.   {
  629.     if (nStart + nCnt * 32 + 32 > nSectors)
  630.       nCnt = 0;
  631.  
  632.     if (CDRead(nHandle, nStart + nCnt * 32, 32, pBuffer) == -1)
  633.     {
  634.       stop_alarm();
  635.       printf("CD-ROM read error.\n");
  636.       return -1;
  637.     }
  638.  
  639.     nData += 32 * 2048;
  640.   }
  641.  
  642.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  643.     return -1;
  644.  
  645.   nRate = nData / nTime;
  646.   printf("%d k/sec (~%.1fx)\n", nRate, (double) nRate / 150.0);
  647.  
  648.   return 0;
  649. }
  650.  
  651. int bench_cd_cpuusage(int nHandle, int nStart)
  652. {
  653.   int nCnt, nData = 0, nTime, nPercent;
  654.   TIMER nLocal;
  655.  
  656.   printf("CPU usage by full speed reads (middle of medium): ");
  657.   fflush(stdout);
  658.  
  659.   if (start_alarm(INTERVAL))
  660.     return -1;
  661.  
  662.   if (_beginthread(dhry_thread, 0, THREADSTACK, 0) == -1)
  663.     return -1;
  664.  
  665.   if (start_timer(&nLocal))
  666.     return -1;
  667.  
  668.   for (nCnt = 0; !time_over; nCnt++)
  669.   {
  670.     if (CDRead(nHandle, nStart + nCnt * 32, 32, pBuffer) == -1)
  671.     {
  672.       stop_alarm();
  673.       printf("CD-ROM read error.\n");
  674.       return -1;
  675.     }
  676.  
  677.     nData += 32 * 2048;
  678.   }
  679.  
  680.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  681.     return -1;
  682.  
  683.   nPercent = (dhry_result - dhry_stones) * 100 / dhry_result;
  684.  
  685.   printf("%d%%\n", nPercent);
  686.  
  687.   return 0;
  688. }
  689.  
  690. int bench_cd_seek(int nHandle, unsigned nSectors)
  691. {
  692.   int nCnt, nSector, nTime;
  693.   TIMER nLocal;
  694.  
  695.   printf("Average data access time: ");
  696.   fflush(stdout);
  697.  
  698.   srand(1);
  699.  
  700.   if (start_alarm(INTERVAL))
  701.     return -1;
  702.  
  703.   if (start_timer(&nLocal))
  704.     return -1;
  705.  
  706.   for (nCnt = 0; !time_over; nCnt++)
  707.   {
  708.     nSector = (nSectors * 1000) / RAND_MAX;
  709.     nSector = nSector * rand() / 1000;
  710.  
  711.     if (CDRead(nHandle, nSector, 1, pBuffer) != 1)
  712.     {
  713.       stop_alarm();
  714.       printf("CD-ROM read error.\n");
  715.       return -1;
  716.     }
  717.   }
  718.  
  719.   if ((nTime = stop_timer(&nLocal, 1000)) == -1)
  720.     return -1;
  721.  
  722.   nTime = nTime * 10 / nCnt;
  723.  
  724.   printf("%d.%d ms\n", nTime / 10, nTime % 10);
  725.  
  726.   return 0;
  727. }
  728.  
  729. int bench_cd(int nDrive)
  730. {
  731.   int nHandle, nDriveLetter, nCnt;
  732.   unsigned nSectors;
  733.   char szName[8], szUPC[8];
  734.  
  735.   if ((nDriveLetter = CDFind(nDrive)) == -1)
  736.     return printf("\nCannot access CD-ROM drive %d.\n", nDrive), -1;
  737.  
  738.   sprintf(szName, "%c:", nDriveLetter);
  739.  
  740.   if ((nHandle = CDOpen(szName, 1, szUPC, &nSectors)) == -1)
  741.     return printf("\nCannot access CD-ROM drive %d.\n", nDrive), -1;
  742.  
  743.   printf("\nCD-ROM drive %s medium has %d sectors = %d MB\n", 
  744.      szName, nSectors, nSectors / 512);
  745.  
  746.   if ((pBuffer = DskAlloc(32, 2048)) == NULL)
  747.     return printf("\nNot enough memory.\n"), -1;
  748.  
  749.   /* spin up and seek to first sector */
  750.   if (CDRead(nHandle, nSectors - 64, 32, pBuffer) == -1)
  751.     return printf("CD-ROM read error.\n"), -1;
  752.   for (nCnt = 0; nCnt < 512; nCnt += 32)
  753.     if (CDRead(nHandle, nSectors / 2 + nCnt, 32, pBuffer) == -1)
  754.       return printf("CD-ROM read error.\n"), -1;
  755.   if (CDRead(nHandle, 0, 32, pBuffer) == -1)
  756.     return printf("CD-ROM read error.\n"), -1;
  757.  
  758.   bench_cd_transfer(nHandle, 0, nSectors);
  759.   bench_cd_transfer(nHandle, nSectors - 32768, nSectors);
  760.   bench_cd_cpuusage(nHandle, nSectors / 2);
  761.   bench_cd_seek(nHandle, nSectors);
  762.  
  763.   DskFree(pBuffer);
  764.   CDClose(nHandle);
  765.  
  766.   return 0;
  767. }
  768.  
  769. void bench_concurrent_hd(void *pArg)
  770. {
  771.   THREADPARMS *ptr = (THREADPARMS *) pArg;
  772.   int nCnt;
  773.  
  774.   for (nCnt = 0; !time_over; nCnt++)
  775.   {
  776.     if (DskRead(ptr->nHandle, nCnt % ptr->nSides, nCnt / ptr->nSides, 1, 
  777.         ptr->nSectors, ptr->pBuffer))
  778.     {
  779.       stop_alarm();
  780.       printf("Disk read error.\n");
  781.       break;
  782.     }
  783.  
  784.     ptr->nData += ptr->nSectors * ptr->nSector;
  785.   }
  786.  
  787.   post_sem(ptr->sDone);
  788.  
  789.   _endthread();
  790. }
  791.  
  792. int bench_concurrent_allhds(int *nHD, int nDisks)
  793. {
  794.   int nTime, nPercent, nTotal, nCnt;
  795.   char szName[8];
  796.   THREADPARMS tHD[256];
  797.   TIMER nLocal;
  798.  
  799.   printf("\nConcurrent full speed reads on %d hard disks: ", nDisks);
  800.   fflush(stdout);
  801.  
  802.   for (nCnt = 0; nCnt < nDisks; nCnt++)
  803.   {
  804.     sprintf(szName, "$%d:", nHD[nCnt]);
  805.  
  806.     if ((tHD[nCnt].nHandle = DskOpen(szName, 0, 0, &tHD[nCnt].nSector,
  807.                      &tHD[nCnt].nSides, &tHD[nCnt].nTracks, 
  808.                      &tHD[nCnt].nSectors)) < 0)
  809.       return printf("\nCannot access disk %d.\n", nHD[nCnt]), -1;
  810.  
  811.     if ((tHD[nCnt].pBuffer = DskAlloc(tHD[nCnt].nSectors, 
  812.                       tHD[nCnt].nSector)) == NULL)
  813.       return printf("\nNot enough memory.\n"), -1;
  814.  
  815.     create_sem(&tHD[nCnt].sDone);
  816.     tHD[nCnt].nData = tHD[nCnt].nCnt = nCnt;
  817.   }
  818.  
  819.   if (start_alarm(INTERVAL))
  820.     return -1;
  821.  
  822.   if (start_timer(&nLocal))
  823.     return -1;
  824.  
  825.   for (nCnt = 0; nCnt < nDisks; nCnt++)
  826.     if (_beginthread(bench_concurrent_hd, 0, THREADSTACK, tHD + nCnt) == -1)
  827.       return -1;
  828.  
  829.   idle_priority();
  830.   run_dhrystone();
  831.   normal_priority();
  832.  
  833.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  834.     return -1;
  835.  
  836.   nPercent = (dhry_result - dhry_stones) * 100 / dhry_result;
  837.   nTotal = 0;
  838.  
  839.   for (nCnt = 0; nCnt < nDisks; nCnt++)
  840.   {
  841.     wait_sem(tHD[nCnt].sDone);
  842.     destroy_sem(tHD[nCnt].sDone);
  843.  
  844.     DskFree(tHD[nCnt].pBuffer);
  845.     DskClose(tHD[nCnt].nHandle);
  846.  
  847.     nTotal += tHD[nCnt].nData;
  848.   }
  849.  
  850.   printf("\nCombined throughput: %d k/sec\n", nTotal / nTime);
  851.   printf("CPU usage: %d%%\n", nPercent);
  852.  
  853.   return 0;
  854. }
  855.  
  856. void bench_concurrent_cd(void *pArg)
  857. {
  858.   THREADPARMS *ptr = (THREADPARMS *) pArg;
  859.   int nCnt, nStart = ptr->nSectors / 2;
  860.  
  861.   for (nCnt = 0; !time_over; nCnt++)
  862.   {
  863.     if (CDRead(ptr->nHandle, nStart + nCnt * 32, 32, ptr->pBuffer) == -1)
  864.     {
  865.       stop_alarm();
  866.       printf("CD-ROM read error.\n");
  867.       break;
  868.     }
  869.  
  870.     ptr->nData += 32 * 2048;
  871.   }
  872.  
  873.   post_sem(ptr->sDone);
  874.  
  875.   _endthread();
  876. }
  877.  
  878. int bench_concurrent_hdcd(int nDisk, int nCD)
  879. {
  880.   int nDriveLetter, nTime, nPercent, nCnt;
  881.   char szName[8], szUPC[8];
  882.   THREADPARMS tHD, tCD;
  883.   TIMER nLocal;
  884.  
  885.   printf("\nConcurrent hard disk %d and CD-ROM %d reads at full speed: ", nDisk, nCD);
  886.   fflush(stdout);
  887.  
  888.   sprintf(szName, "$%d:", nDisk);
  889.  
  890.   if ((tHD.nHandle = DskOpen(szName, 0, 0, &tHD.nSector,
  891.                  &tHD.nSides, &tHD.nTracks, &tHD.nSectors)) < 0)
  892.     return printf("\nCannot access disk %d.\n", nDisk), -1;
  893.  
  894.   if ((tHD.pBuffer = DskAlloc(tHD.nSectors, tHD.nSector)) == NULL)
  895.     return printf("\nNot enough memory.\n"), -1;
  896.  
  897.   create_sem(&tHD.sDone);
  898.   tHD.nData = tHD.nCnt = 0;
  899.  
  900.   if ((nDriveLetter = CDFind(nCD)) == -1)
  901.     return printf("\nCannot access CD-ROM drive %d.\n", nCD), -1;
  902.  
  903.   sprintf(szName, "%c:", nDriveLetter);
  904.  
  905.   if ((tCD.nHandle = CDOpen(szName, 1, szUPC, &tCD.nSectors)) == -1)
  906.     return printf("\nCannot access CD-ROM drive %d.\n", nCD), -1;
  907.  
  908.   if ((tCD.pBuffer = DskAlloc(32, 2048)) == NULL)
  909.     return printf("\nNot enough memory.\n"), -1;
  910.  
  911.   /* spin up and seek to first sector */
  912.   if (CDRead(tCD.nHandle, tCD.nSectors - 64, 32, tCD.pBuffer) == -1)
  913.     return printf("CD-ROM read error.\n"), -1;
  914.   for (nCnt = 0; nCnt < 512; nCnt += 32)
  915.     if (CDRead(tCD.nHandle, tCD.nSectors / 2 + nCnt, 32, tCD.pBuffer) == -1)
  916.       return printf("CD-ROM read error.\n"), -1;
  917.   if (CDRead(tCD.nHandle, 0, 32, tCD.pBuffer) == -1)
  918.     return printf("CD-ROM read error.\n"), -1;
  919.  
  920.   create_sem(&tCD.sDone);
  921.   tCD.nData = tCD.nCnt = 0;
  922.  
  923.   if (start_alarm(INTERVAL))
  924.     return -1;
  925.  
  926.   if (start_timer(&nLocal))
  927.     return -1;
  928.  
  929.   if (_beginthread(bench_concurrent_hd, 0, THREADSTACK, &tHD) == -1)
  930.     return -1;
  931.   if (_beginthread(bench_concurrent_cd, 0, THREADSTACK, &tCD) == -1)
  932.     return -1;
  933.  
  934.   idle_priority();
  935.   run_dhrystone();
  936.   normal_priority();
  937.  
  938.   if ((nTime = stop_timer(&nLocal, 1024)) == -1)
  939.     return -1;
  940.  
  941.   wait_sem(tHD.sDone);
  942.   destroy_sem(tHD.sDone);
  943.  
  944.   DskFree(tHD.pBuffer);
  945.   DskClose(tHD.nHandle);
  946.  
  947.   wait_sem(tCD.sDone);
  948.   destroy_sem(tCD.sDone);
  949.  
  950.   DskFree(tCD.pBuffer);
  951.   CDClose(tCD.nHandle);
  952.  
  953.   printf("\nHard disk throughput (cylinder 0): %d k/sec\n", tHD.nData / nTime);
  954.   printf("CD-ROM throughput (middle of medium): %d k/sec\n", tCD.nData / nTime);
  955.  
  956.   nPercent = (dhry_result - dhry_stones) * 100 / dhry_result;
  957.   printf("CPU usage: %d%%\n", nPercent);
  958.  
  959.   return 0;
  960. }
  961.  
  962. int bench_dhry(void)
  963. {
  964.   printf("Dhrystone benchmark for this CPU: ");
  965.   fflush(stdout);
  966.  
  967.   if (start_alarm(INTERVAL / 2))
  968.     return -1;
  969.  
  970.   run_dhrystone();
  971.  
  972.   dhry_result = dhry_stones;
  973.  
  974.   if (dhry_result == 0)
  975.     dhry_result = 1; /* to avoid dividing by zero later on */
  976.  
  977.   printf("%d runs/sec\n", dhry_result);
  978.  
  979.   return 0;
  980. }
  981.  
  982. int main(int argc, char **argv)
  983. {
  984.   char szVersion[32];
  985.   int nDisks, nCDROMs, nCount, xHD[256], xCD[256], cHD = 0, cCD = 0;
  986.  
  987.   strcpy(szVersion, rcsrev + sizeof("$Revision: ") - 1);
  988.   *strchr(szVersion, ' ') = 0;
  989.  
  990.   printf("\nDISKIO - Fixed Disk Benchmark, Version %s"
  991.      "\n(C) 1994-1998 Kai Uwe Rommel\n", szVersion);
  992.  
  993.   nDisks = DskCount();
  994.   printf("\nNumber of fixed disks: %d\n", nDisks);
  995.  
  996.   nCDROMs = CDFind(0);
  997.   if (nCDROMs == -1) /* not even the driver is loaded */
  998.     nCDROMs = 0;
  999.   printf("Number of CD-ROM drives: %d\n", nCDROMs);
  1000.  
  1001.   if (argc > 1)
  1002.   {
  1003.     nDisks = nCDROMs = 0;
  1004.  
  1005.     for (nCount = 1; nCount < argc; )
  1006.       if (stricmp(argv[nCount], "-hd") == 0)
  1007.       {
  1008.         for (nCount++; argv[nCount] && argv[nCount][0] != '-'; nCount++)    /*PLF Wed  97-02-26 22:31:38*/
  1009.       xHD[nDisks++] = atoi(argv[nCount]);
  1010.       }
  1011.       else if (stricmp(argv[nCount], "-cd") == 0)
  1012.       {
  1013.         for (nCount++; argv[nCount] && argv[nCount][0] != '-'; nCount++)    /*PLF Wed  97-02-26 22:31:47*/
  1014.       xCD[nCDROMs++] = atoi(argv[nCount]);
  1015.       }      
  1016.       else if (stricmp(argv[nCount], "-c") == 0)
  1017.       {
  1018.     if(argv[nCount+1] && argv[nCount+2])
  1019.       if (argv[nCount + 1][0] != '-' && argv[nCount + 2][0] != '-')
  1020.       {
  1021.         cHD = atoi(argv[nCount + 1]);
  1022.         cCD = atoi(argv[nCount + 2]);
  1023.         nCount += 3;
  1024.       }
  1025.       }
  1026.       else if (stricmp(argv[nCount], "-?") == 0)
  1027.       {
  1028.     printf("\nUsage:\tdiskio [options]\n"
  1029.            "\n\t-hd <list of hard disk numbers>"
  1030.            "\n\t-cd <list of CD-ROM drive numbers>"
  1031.                  "\n\t-c  <pair of hard disk and CD-ROM drive numbers>\n"
  1032.            "\nHard disk and CD-ROM drive numbers are physical ones and start at 1."
  1033.            "\nThe drive number lists must be blank separated.\n"
  1034.            "\nWith -cd, -hd and -c you can explicitly select the drives to be used"
  1035.            "\nfor hard disk, CD-ROM drive and concurrent hard disk and CD-ROM benchmarks.\n"
  1036.            "\nIf none of them is used, all drives are used for hard disk and CD-ROM"
  1037.            "\ndrive benchmarks and the first hard disk and CD-ROM drives are used"
  1038.            "\nfor the concurrent hard disk and CD-ROM benchmark\n"
  1039.            "\nExample: diskio -hd 2 3 -cd 1 -c 3 1\n");
  1040.     exit(1);
  1041.       }
  1042.  
  1043.       else
  1044.     nCount++;
  1045.   }
  1046.   else
  1047.   {
  1048.     for (nCount = 1; nCount <= nDisks; nCount++)
  1049.       xHD[nCount - 1] = nCount;
  1050.  
  1051.     for (nCount = 1; nCount <= nCDROMs; nCount++)
  1052.       xCD[nCount - 1] = nCount;
  1053.  
  1054.     if (nDisks > 0 && nCDROMs > 0)
  1055.       cHD = cCD = 1;
  1056.   }
  1057.  
  1058.   printf("\nDhrystone 2.1 C benchmark routines (C) 1988 Reinhold P. Weicker\n");
  1059.   bench_dhry();
  1060.  
  1061.   for (nCount = 0; nCount < nDisks; nCount++)
  1062.     bench_hd(xHD[nCount]);
  1063.  
  1064.   if (nDisks > 1)
  1065.     bench_concurrent_allhds(xHD, nDisks);
  1066.  
  1067.   for (nCount = 0; nCount < nCDROMs; nCount++)
  1068.     bench_cd(xCD[nCount]);
  1069.  
  1070.   if (cHD != 0 && cCD != 0)
  1071.     bench_concurrent_hdcd(cHD, cCD);
  1072.  
  1073.   return 0;
  1074. }
  1075.  
  1076. /* end of diskio.c */
  1077.