home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 576.lha / DiskSpeed_v4.0 / DiskSpeed.c < prev    next >
C/C++ Source or Header  |  1991-09-11  |  44KB  |  1,711 lines

  1. /*
  2.  *                          DiskSpeed v4.0
  3.  *                                by
  4.  *                           Michael Sinz
  5.  *
  6.  *             Copyright (c) 1989 by MKSoft Development
  7.  *
  8.  *            MKSoft Development
  9.  *            163 Appledore Drive
  10.  *            Downingtown, PA 19335
  11.  *
  12.  * Yes, this is yet another disk speed testing program, but with a few
  13.  * differences.  It was designed to give the most accurate results of the
  14.  * true disk performance in the system.  For this reason many of
  15.  * DiskSpeed's results may look either lower or higher than current disk
  16.  * performance tests.
  17.  *
  18.  ******************************************************************************
  19.  *                                          *
  20.  *    Reading legal mush can turn your brain into guacamole!              *
  21.  *                                          *
  22.  *        So here is some of that legal mush:                  *
  23.  *                                          *
  24.  * Permission is hereby granted to distribute this program's source          *
  25.  * executable, and documentation for non-commercial purposes, so long as the  *
  26.  * copyright notices are not removed from the sources, executable or          *
  27.  * documentation.  This program may not be distributed for a profit without   *
  28.  * the express written consent of the author Michael Sinz.              *
  29.  *                                          *
  30.  * This program is not in the public domain.                      *
  31.  *                                          *
  32.  * Fred Fish is expressly granted permission to distribute this program's     *
  33.  * source and executable as part of the "Fred Fish freely redistributable     *
  34.  * Amiga software library."                              *
  35.  *                                          *
  36.  * Permission is expressly granted for this program and it's source to be     *
  37.  * distributed as part of the Amicus Amiga software disks, and the          *
  38.  * First Amiga User Group's Hot Mix disks.                      *
  39.  *                                          *
  40.  ******************************************************************************
  41.  *
  42.  * Main code and testing sections...
  43.  */
  44.  
  45. #include    <exec/types.h>
  46. #include    <exec/execbase.h>
  47. #include    <exec/memory.h>
  48. #include    <exec/lists.h>
  49. #include    <exec/nodes.h>
  50. #include    <exec/devices.h>
  51. #include    <exec/io.h>
  52. #include    <exec/ports.h>
  53. #include    <devices/timer.h>
  54. #include    <dos/dos.h>
  55. #include    <dos/dosextens.h>
  56. #include    <intuition/intuition.h>
  57. #include    <intuition/screens.h>
  58. #include    <workbench/workbench.h>
  59. #include    <workbench/startup.h>
  60.  
  61. #include    <clib/exec_protos.h>
  62. #include    <clib/dos_protos.h>
  63. #include    <clib/timer_protos.h>
  64. #include    <clib/intuition_protos.h>
  65. #include    <clib/icon_protos.h>
  66.  
  67. #include    <pragmas/exec_pragmas.h>
  68. #include    <pragmas/dos_pragmas.h>
  69. #include    <pragmas/timer_pragmas.h>
  70. #include    <pragmas/intuition_pragmas.h>
  71. #include    <pragmas/icon_pragmas.h>
  72.  
  73. #include    <string.h>
  74. #include    <stdio.h>
  75.  
  76. #include    "renderinfo.h"
  77. #include    "mks_list.h"
  78. #include    "makeboxes.h"
  79.  
  80. /*
  81.  * First, the timer stuff...
  82.  */
  83. struct MyTimer
  84. {
  85. struct    timerequest    *tr;
  86. struct    timeval        time;
  87. struct    MsgPort        *port;
  88.     BOOL        Open;
  89. };
  90.  
  91. /*
  92.  * The "TextLine" structure used to display text in the information
  93.  * "window" in DiskSpeed.
  94.  */
  95. struct    TextLine
  96. {
  97. struct    Node    tl_Node;
  98.     ULONG    tl_Size;    /* Size of the allocation */
  99.     char    tl_Text[1];    /* For the NULL... */
  100. };
  101.  
  102. /*
  103.  * My global structure...
  104.  */
  105. struct DiskSpeed
  106. {
  107. struct    Window        *Window;    /* The DiskSpeed window... */
  108. struct    RenderInfo    *ri;        /* MKSoft Render Info */
  109.  
  110.     BPTR    Output;        /* The output file handle! */
  111. struct    Process    *Me;        /* Pointer to my process... */
  112. struct    MyTimer    *timer;        /* Pointer to a timer structure */
  113.  
  114. struct    FileInfoBlock    *fib;    /* Pointer to a FileInfoBlock */
  115.  
  116. /* */
  117. struct    MinList    TextList;    /* The list the results test is linked to... */
  118. struct    DisplayList    *List;    /* The "List" gadget */
  119. /* */
  120.     ULONG    Min_Time;    /* Minimum time in seconds for a test */
  121.     ULONG    Base_CPU;    /* Base CPU available... */
  122.     ULONG    CPU_Total;    /* Sum of CPU availability */
  123.     ULONG    CPU_Count;    /* Count of CPU availability */
  124.  
  125. /* Testing parameters */
  126.     UBYTE    HighDMA;    /* Set to TRUE for high video DMA... */
  127.     UBYTE    Test_DIR;    /* Set to test directory stuff */
  128.     UBYTE    Test_SEEK;    /* Set to test SEEK/READ */
  129.     UBYTE    pad;
  130.  
  131.     ULONG    Align_Types;    /* Set bits of alignment types... */
  132.     ULONG    Mem_TYPES;    /* Set memory type flags to test... */
  133.     ULONG    Test_Size[4];    /* The four test sizes... */
  134.  
  135. /* Now for the gadgets */
  136. struct    Gadget    DeviceGadget;
  137. struct    Gadget    CommentsGadget;
  138. struct    Gadget    StartTestGadget;
  139. struct    Gadget    SaveResultsGadget;
  140. struct    Gadget    StopTestGadget;
  141.  
  142. struct    StringInfo    DeviceInfo;
  143. struct    StringInfo    CommentsInfo;
  144.  
  145. struct    Border    StringBorder[4];
  146. struct    Border    ActionBorder[4];
  147. struct    Border    DetailBorder[2];
  148.  
  149. struct    IntuiText    DeviceText;
  150. struct    IntuiText    CommentsText;
  151. struct    IntuiText    StartTest;
  152. struct    IntuiText    SaveResults;
  153. struct    IntuiText    StopTest;
  154.  
  155.     SHORT    StringVectors[5*2*4];
  156.     SHORT    ActionVectors[5*2*2];
  157.  
  158. /* */
  159.     char    Device[256];    /* Device name under test... */
  160.     char    Comments[256];    /* Comments string gadget... */
  161.     char    Undo[256];    /* Our one UNDO buffer... */
  162.  
  163. /* */
  164.     char    CPU_Type[6];    /* 680?0 in this string (plus NULL) */
  165.     char    Exec_Ver[14];    /* Version of Exec */
  166.  
  167. /* */
  168.     char    tmp1[256];    /* Some temp buffer space... */
  169. };
  170.  
  171. #define    DEVICE_GADGET    1
  172. #define    COMMENT_GADGET    2
  173. #define    TEST_GADGET    3
  174. #define    SAVE_GADGET    4
  175. #define    STOP_GADGET    5
  176.  
  177. extern    struct    Library    *SysBase;
  178. extern    struct    Library    *DOSBase;
  179. extern    struct    Library    *IntuitionBase;
  180. extern    struct    Library    *GfxBase;
  181. extern    struct    Library    *IconBase;
  182.     struct    Library    *LayersBase;
  183.  
  184. /* Some prototypes not given... BTW - This is mainly needed for 1.3 compatibility... ARG!!! */
  185. void *CreateExtIO( struct MsgPort *msg, long size );
  186. struct MsgPort *CreatePort( UBYTE *name, long pri );
  187. void DeleteExtIO( struct IORequest *io );
  188. void DeletePort( struct MsgPort *io );
  189. void DeleteTask( struct Task *task );
  190. void NewList( struct List *list );
  191.  
  192. char    FILE_CREATE[]=    "File Create:   ";
  193. char    FILE_OPEN[]=    "File Open:     ";
  194. char    FILE_SCAN[]=    "Directory Scan:";
  195. char    FILE_DELETE[]=    "File Delete:   ";
  196. char    SEEK_READ[]=    "Seek/Read:     ";
  197.  
  198. char    BYTES_CREATE[]=    "Create file:   ";
  199. char    BYTES_WRITE[]=    "Write to file: ";
  200. char    BYTES_READ[]=    "Read from file:";
  201.  
  202. char    SEEK_UNITS[]=    "seeks/sec";
  203. char    FILE_UNITS[]=    "files/sec";
  204. char    BYTE_UNITS[]=    "bytes/sec";
  205.  
  206. char    FILE_STRING[]=    "%04lx DiskSpeed Test File ";
  207.  
  208. char    TEST_DIR[]=    " DiskSpeed Test Directory ";
  209.  
  210. char    COPYRIGHT[]=    "MKSoft DiskSpeed 4.0 - Copyright © 1989-91 MKSoft Development";
  211.  
  212. char    START_TEST[]=    "Start Test";
  213. char    SAVE_RESULTS[]=    "Save Results";
  214. char    STOP_TEST[]=    "Stop Test";
  215.  
  216. static char fontnam[11]="topaz.font";
  217. struct TextAttr TOPAZ80={fontnam,8,0,FPF_ROMFONT};
  218.  
  219. #define    NUM_FILES    200
  220.  
  221. /*
  222.  * This is the minimum time for test that can be extended/shorted automatically
  223.  * This number should not be set too low otherwise the test results will be
  224.  * inaccurate due to timer granularity.  (in seconds)
  225.  */
  226. #define    MIN_TEST_TIME    8
  227.  
  228. /*
  229.  * This section of code is used to test CPU availability.  Due to the nature of
  230.  * the code, the actual test code for the task is in assembly...
  231.  */
  232. extern    ULONG    __far    CPU_Use_Base;
  233. extern    ULONG    __far    CPU_State_Flag;
  234. extern    ULONG    __far    CPU_Count_Low;
  235. extern    ULONG    __far    CPU_Count_High;
  236.  
  237. struct Task *Init_CPU_Available(void);
  238. void Free_CPU_Available(void);
  239. void CPU_Calibrate(void);
  240.  
  241.  
  242. /* The Wait pointer I use... */
  243. USHORT __chip WaitPointer[36] =
  244. {
  245.     0x0000, 0x0000, 0x0400, 0x07C0, 0x0000, 0x07C0, 0x0100, 0x0380, 0x0000,
  246.     0x07E0, 0x07C0, 0x1FF8, 0x1FF0, 0x3FEC, 0x3FF8, 0x7FDE, 0x3FF8, 0x7FBE,
  247.     0x7FFC, 0xFF7F, 0x7EFC, 0xFFFF, 0x7FFC, 0xFFFF, 0x3FF8, 0x7FFE, 0x3FF8,
  248.     0x7FFE, 0x1FF0, 0x3FFC, 0x07C0, 0x1FF8, 0x0000, 0x07E0, 0x0000, 0x0000
  249. };
  250.  
  251. /*
  252.  * These two defines set up and clear the WaitPointer...
  253.  */
  254. #define    SetWait(x)    SetPointer(x,WaitPointer,16L,16L,-6L,0L)
  255. #define    ClearWait(x)    ClearPointer(x)
  256.  
  257. /*
  258.  * This routine returns the amount of time in the timer...
  259.  * The number returned is in Seconds...
  260.  */
  261. ULONG Read_Timer(struct MyTimer *mt)
  262. {
  263. struct    Library    *TimerBase=(struct Library *)(mt->tr->tr_node.io_Device);
  264.  
  265.     /* Get the current time... */
  266.     mt->tr->tr_node.io_Command=TR_GETSYSTIME;
  267.     mt->tr->tr_node.io_Flags=IOF_QUICK;
  268.     DoIO((struct IORequest *)(mt->tr));
  269.  
  270.     /* Subtract last timer result and store as the timer result */
  271.     SubTime(&(mt->tr->tr_time),&(mt->time));
  272.     return(mt->tr->tr_time.tv_secs);
  273. }
  274.  
  275. /*
  276.  * Start the timer...
  277.  */
  278. void Start_Timer(struct MyTimer *mt)
  279. {
  280.     /* Get the current time... */
  281.     mt->tr->tr_node.io_Command=TR_GETSYSTIME;
  282.     mt->tr->tr_node.io_Flags=IOF_QUICK;
  283.     DoIO((struct IORequest *)(mt->tr));
  284.  
  285.     /* Store current time as the timer result */
  286.     mt->time=mt->tr->tr_time;
  287.  
  288.     /*
  289.      * This here is a nasty trick...  Since the timer device
  290.      * has a low resolution, we wait until we get to the exact
  291.      * cross-over from one TICK to the next.  We know that the
  292.      * tick value is larger than 10 so if the difference
  293.      * between two calls to the timer is > 10 then it must
  294.      * have been a TICK that just went through.  This is
  295.      * not "friendly" code but since we are testing the system
  296.      * and it is not "application" code, it is not a problem.
  297.      */
  298.     while ((mt->tr->tr_time.tv_micro-mt->time.tv_micro) < 10)
  299.     {
  300.         /* Store current time as the timer result */
  301.         mt->time=mt->tr->tr_time;
  302.  
  303.         /* Get the current time... */
  304.         mt->tr->tr_node.io_Command=TR_GETSYSTIME;
  305.         mt->tr->tr_node.io_Flags=IOF_QUICK;
  306.         DoIO((struct IORequest *)(mt->tr));
  307.     }
  308.  
  309.     /* Store current time as the timer result */
  310.     mt->time=mt->tr->tr_time;
  311. }
  312.  
  313. /*
  314.  * Stop the timer...
  315.  */
  316. void Stop_Timer(struct MyTimer *mt)
  317. {
  318. struct    Library    *TimerBase=(struct Library *)(mt->tr->tr_node.io_Device);
  319.  
  320.     /* Get the current time... */
  321.     mt->tr->tr_node.io_Command=TR_GETSYSTIME;
  322.     mt->tr->tr_node.io_Flags=IOF_QUICK;
  323.     DoIO((struct IORequest *)(mt->tr));
  324.  
  325.     /* Subtract last timer result and store as the timer result */
  326.     SubTime(&(mt->tr->tr_time),&(mt->time));
  327.     mt->time=mt->tr->tr_time;
  328. }
  329.  
  330. /*
  331.  * Free a MyTimer structure as best as possible.  Do all of the error checks
  332.  * here since this will also be called for partial timer initializations.
  333.  */
  334. void Free_Timer(struct MyTimer *mt)
  335. {
  336.     if (mt)
  337.     {
  338.         if (mt->port)
  339.         {
  340.             if (mt->tr)
  341.             {
  342.                 if (mt->Open)
  343.                 {
  344.                     CloseDevice((struct IORequest *)(mt->tr));
  345.                 }
  346.                 DeleteExtIO((struct IORequest *)(mt->tr));
  347.             }
  348.             DeletePort(mt->port);
  349.         }
  350.         FreeMem(mt,sizeof(struct MyTimer));
  351.     }
  352. }
  353.  
  354. /*
  355.  * Initialize a MyTimer structure.  It will return NULL if it did not work.
  356.  */
  357. struct MyTimer *Init_Timer(void)
  358. {
  359. struct    MyTimer    *mt;
  360.  
  361.     if (mt=AllocMem(sizeof(struct MyTimer),MEMF_PUBLIC|MEMF_CLEAR))
  362.     {
  363.         mt->Open=FALSE;
  364.         if (mt->port=CreatePort(NULL,0L))
  365.         {
  366.             if (mt->tr=CreateExtIO(mt->port,sizeof(struct timerequest)))
  367.             {
  368.                 if (!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)(mt->tr),0L))
  369.                 {
  370.                     mt->Open=TRUE;
  371.                 }
  372.             }
  373.         }
  374.         if (!(mt->Open))
  375.         {
  376.             Free_Timer(mt);
  377.             mt=NULL;
  378.         }
  379.     }
  380.     return(mt);
  381. }
  382.  
  383. /*
  384.  * Now, for the routines that will pull in the lines and display them as
  385.  * needed in the display...
  386.  */
  387. void AddDisplayLine(struct DiskSpeed *global,char *line)
  388. {
  389.     ULONG        size=strlen(line);
  390. struct    TextLine    *tline;
  391.  
  392.     if (global->Window)
  393.     {
  394.         if (tline=AllocMem(size+=sizeof(struct TextLine),MEMF_PUBLIC|MEMF_CLEAR))
  395.         {
  396.             tline->tl_Size=size;
  397.             tline->tl_Node.ln_Name=tline->tl_Text;
  398.             strcpy(tline->tl_Text,line);
  399.  
  400.             AddTail((struct List *)&(global->TextList),&(tline->tl_Node));
  401.  
  402.             /* Now display it... */
  403.             FreshList(global->Window,global->List,&(global->TextList));
  404.         }
  405.     }
  406.     else if (global->Output)
  407.     {
  408.         Write(global->Output,line,size);
  409.         Write(global->Output,"\n",1);
  410.     }
  411. }
  412.  
  413. void FreeDisplayList(struct DiskSpeed *global)
  414. {
  415. struct    TextLine    *tline;
  416.  
  417.     while (tline=(struct TextLine *)RemHead((struct List *)&(global->TextList)))
  418.     {
  419.         FreeMem(tline,tline->tl_Size);
  420.     }
  421.  
  422.     /* Update the display */
  423.     if (global->Window) FreshList(global->Window,global->List,NULL);
  424. }
  425.  
  426. /*...*/
  427.  
  428. BOOL Check_Quit(struct DiskSpeed *global)
  429. {
  430. BOOL    worked=TRUE;
  431. struct    IntuiMessage    *msg;
  432.  
  433.     if (global->Window)
  434.     {
  435.         while (msg=(struct IntuiMessage *)GetMsg(global->Window->UserPort))
  436.         {
  437.             if (msg->Class==CLOSEWINDOW) worked=FALSE;
  438.             else if (msg->Class==GADGETUP) if (msg->IAddress=&(global->StopTestGadget)) worked=FALSE;
  439.             Check_ListGadget(global->Window,msg);
  440.             ReplyMsg((struct Message *)msg);
  441.         }
  442.     }
  443.  
  444.     if (SetSignal(0,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) worked=FALSE;
  445.  
  446.     if (!worked) AddDisplayLine(global,"*** Interrupted by user ***");
  447.  
  448.     return(worked);
  449. }
  450.  
  451. /*...*/
  452.  
  453. /*
  454.  * It knows that the Y value is fixed point by n-digits...
  455.  */
  456. ULONG MaxDivide(ULONG x,ULONG y,ULONG digits)
  457. {
  458. ULONG    result;
  459. ULONG    num=0;    /* Number of 10 units adjusted for so far */
  460.  
  461.     while ((x<399999999) && (num<digits))
  462.     {
  463.         x*=10;
  464.         num++;
  465.     }
  466.  
  467.     while (num<digits)
  468.     {
  469.         num++;
  470.         if (num==digits) y+=5;    /* Round it if last digit... */
  471.         y=y/10;
  472.     }
  473.  
  474.     if (y) result=x/y;
  475.     else result=-1;    /* MAX INT if y=0 */
  476.  
  477.     return(result);
  478. }
  479.  
  480. /*
  481.  * Build a string and add it to the display of results.
  482.  * This routine knows how to take the timer results and the CPU
  483.  * results and format them into a string with the given header
  484.  * and the given unit of measure.
  485.  */
  486. VOID Display_Result(struct DiskSpeed *global,char *Header,ULONG number,char *Units)
  487. {
  488. char    *p=global->tmp1;
  489. char    format[48];
  490. ULONG    clicks;    /* To figure out the number of clicks/second */
  491. ULONG    time;
  492. ULONG    tmp_time;
  493.  
  494.     /* First, make sure (as best as possible) that the CPU values are right */
  495.     CPU_State_Flag=TRUE;
  496.     Delay(1);    /* Let it run into the TRUE CPU_State_Flag */
  497.  
  498.     /* 1,000,000 micro = 1 second... */
  499.     time=(global->timer->time.tv_secs * 1000000) + global->timer->time.tv_micro;
  500.     /* time is now in micro seconds... */
  501.  
  502.     number=MaxDivide(number,time,6);
  503.  
  504.     strcpy(format,"%s %9ld %s");
  505.     if (!number)
  506.     {
  507.         strcpy(format,"%s       < %ld %s");
  508.         number=1;
  509.     }
  510.  
  511.     if (global->Base_CPU)
  512.     {
  513.         tmp_time=time;    /* For below... */
  514.  
  515.         while (CPU_Count_High)
  516.         {
  517.             /* Adjust the time and the CPU count as needed */
  518.             tmp_time=tmp_time >> 1;
  519.             CPU_Count_Low=CPU_Count_Low >> 1;
  520.             if (CPU_Count_High & 1) CPU_Count_Low += 0x80000000;
  521.             CPU_Count_High=CPU_Count_High >> 1;
  522.         }
  523.  
  524.         clicks=MaxDivide(CPU_Count_Low,tmp_time,6);
  525.         clicks=(MaxDivide(clicks,global->Base_CPU,3)+5)/10;
  526.         global->CPU_Total+=clicks;
  527.         global->CPU_Count++;
  528.  
  529.         strcat(format,"  |  CPU Available: %ld%%");
  530.     }
  531.  
  532.     sprintf(p,format,Header,number,Units,clicks);
  533.  
  534.     AddDisplayLine(global,p);
  535. }
  536.  
  537. VOID Display_Error(struct DiskSpeed *global,char *test)
  538. {
  539.     sprintf(global->tmp1,"Error:  %s test failed.");
  540.     AddDisplayLine(global,global->tmp1);
  541. }
  542.  
  543. /*
  544.  * In order to keep the file create test fair, it must always do
  545.  * the same number of files.  The way filing systems work, many times
  546.  * the get slower as the number of files in a directory grow
  547.  */
  548. BOOL CreateFileTest(struct DiskSpeed *global)
  549. {
  550. BPTR    file;
  551. ULONG    count;
  552. BOOL    worked=TRUE;
  553. char    *p=global->tmp1;    /* For speed reasons */
  554.  
  555.     Start_Timer(global->timer);
  556.     Init_CPU_Available();        /* Start counting free CPU cycles... */
  557.  
  558.     for (count=0;(count<NUM_FILES) && (worked &= Check_Quit(global));count++)
  559.     {
  560.         sprintf(p,FILE_STRING,count);
  561.         if (file=Open(p,MODE_NEWFILE)) Close(file);
  562.         else
  563.         {
  564.             Display_Error(global,"File Create");
  565.             worked=FALSE;
  566.         }
  567.     }
  568.  
  569.     Stop_Timer(global->timer);
  570.  
  571.     if (worked) Display_Result(global,FILE_CREATE,NUM_FILES,FILE_UNITS);
  572.  
  573.     Free_CPU_Available();
  574.  
  575.     return(worked);
  576. }
  577.  
  578. BOOL OpenFileTest(struct DiskSpeed *global)
  579. {
  580. BPTR    file;
  581. ULONG    count=0;
  582. BOOL    worked=TRUE;
  583. char    *p=global->tmp1;
  584.  
  585.     Start_Timer(global->timer);
  586.     Init_CPU_Available();        /* Start counting free CPU cycles... */
  587.     while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  588.     {
  589.         sprintf(p,FILE_STRING,(ULONG)(count % NUM_FILES));
  590.         count++;
  591.         if (file=Open(p,MODE_OLDFILE)) Close(file);
  592.         else
  593.         {
  594.             Display_Error(global,"File Open");
  595.             worked=FALSE;
  596.         }
  597.     }
  598.     Stop_Timer(global->timer);
  599.  
  600.     if (worked) Display_Result(global,FILE_OPEN,count,FILE_UNITS);
  601.  
  602.     Free_CPU_Available();
  603.     return(worked);
  604. }
  605.  
  606. BOOL ScanDirectoryTest(struct DiskSpeed *global)
  607. {
  608. BPTR    lock=NULL;
  609. ULONG    count=0;
  610. BOOL    worked=TRUE;
  611.  
  612.     Start_Timer(global->timer);
  613.     Init_CPU_Available();        /* Start counting free CPU cycles... */
  614.     while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  615.     {
  616.         if (lock)
  617.         {
  618.             if (!ExNext(lock,global->fib)) lock=NULL;
  619.             else count++;
  620.         }
  621.         else
  622.         {
  623.             CurrentDir(lock=CurrentDir(NULL));
  624.             if (Examine(lock,global->fib)) count++;
  625.             else
  626.             {
  627.                 Display_Error(global,"Directory Scan");
  628.                 worked=FALSE;
  629.             }
  630.         }
  631.     }
  632.     Stop_Timer(global->timer);
  633.  
  634.     if (worked) Display_Result(global,FILE_SCAN,count,FILE_UNITS);
  635.  
  636.     Free_CPU_Available();
  637.     return(worked);
  638. }
  639.  
  640. /*
  641.  * In order to keep the file delete test fair, it must always do
  642.  * the same number of files.  The way filing systems work, many times
  643.  * the get slower as the number of files in a directory grow
  644.  */
  645. BOOL DeleteFileTest(struct DiskSpeed *global)
  646. {
  647. ULONG    count;
  648. BOOL    worked=TRUE;
  649. char    *p=global->tmp1;
  650.  
  651.     Start_Timer(global->timer);
  652.     Init_CPU_Available();        /* Start counting free CPU cycles... */
  653.  
  654.     for (count=0;(count<NUM_FILES) && (worked &= Check_Quit(global));count++)
  655.     {
  656.         sprintf(p,FILE_STRING,count);
  657.         if (!DeleteFile(p))
  658.         {
  659.             Display_Error(global,"File Delete");
  660.             worked=FALSE;
  661.         }
  662.     }
  663.  
  664.     Stop_Timer(global->timer);
  665.  
  666.     if (worked) Display_Result(global,FILE_DELETE,NUM_FILES,FILE_UNITS);
  667.  
  668.     Free_CPU_Available();
  669.  
  670.     return(worked);
  671. }
  672.  
  673. BOOL SeekReadTest(struct DiskSpeed *global)
  674. {
  675. BPTR    file;
  676. ULONG    size;
  677. ULONG    count;
  678. LONG    pos=0;
  679. LONG    buffer[16];
  680. BOOL    worked=FALSE;
  681. void    *buf;
  682.  
  683.     /* First we build a file by writing the ROM to disk... */
  684.     if (file=Open(FILE_STRING,MODE_NEWFILE))
  685.     {
  686.         size=0x40000;    /* Start by asking for 256K */
  687.         while (size && (!(buf=AllocMem(size,MEMF_PUBLIC)))) size=size>>1;
  688.  
  689.         if (buf)
  690.         {
  691.             worked=TRUE;
  692.             /* Write a 256K file... */
  693.             count=0x40000/size;
  694.             while ((count>0) && (worked&=Check_Quit(global)))
  695.             {
  696.                 count--;
  697.                 if (size!=Write(file,buf,size))
  698.                 {
  699.                     worked=FALSE;
  700.                     Display_Error(global,"Seek/Read");
  701.                 }
  702.             }
  703.             FreeMem(buf,size);
  704.         }
  705.         else Display_Error(global,"Seek/Read");
  706.  
  707.         Start_Timer(global->timer);
  708.         Init_CPU_Available();        /* Start counting free CPU cycles... */
  709.         while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  710.         {
  711.             Seek(file,pos,OFFSET_BEGINING);
  712.             Read(file,buffer,64);
  713.             count++;
  714.  
  715.             Seek(file,-(pos+64),OFFSET_END);
  716.             Read(file,buffer,64);
  717.             count++;
  718.  
  719.             Seek(file,-(pos+(size/3)),OFFSET_CURRENT);
  720.             Read(file,buffer,64);
  721.             count++;
  722.  
  723.             /* Come up with another position... */
  724.             pos=(pos+(size/11)) % (size/3);
  725.         }
  726.         Stop_Timer(global->timer);
  727.  
  728.         if (worked) Display_Result(global,SEEK_READ,count,SEEK_UNITS);
  729.  
  730.         Free_CPU_Available();
  731.  
  732.         Close(file);
  733.         DeleteFile(FILE_STRING);
  734.     }
  735.     else Display_Error(global,"Seek/Read");
  736.  
  737.     return(worked);
  738. }
  739.  
  740. BOOL SpeedTest(struct DiskSpeed *global,ULONG size,ULONG offset,ULONG mem_type)
  741. {
  742. BOOL    worked=TRUE;
  743. char    *buffer;
  744. char    *mem;        /* What we really allocated */
  745. char    *type;
  746. char    *type2;
  747. ULONG    loop;
  748. ULONG    count;
  749. LONG    times;
  750. BPTR    file=NULL;
  751.  
  752.     AddDisplayLine(global,"");
  753.  
  754.     type="FAST";
  755.     if (mem_type & MEMF_CHIP) type="CHIP";
  756.  
  757.     type2="LONG";
  758.     if (offset & 2) type2="WORD";
  759.     if (offset & 1) type2="BYTE";
  760.  
  761.     if (mem=AllocMem(size+offset,mem_type|MEMF_PUBLIC))
  762.     {
  763.         /* Set up memory... */
  764.         buffer=&(mem[offset]);
  765.  
  766.         for (loop=0;loop<size;loop++) buffer[loop]=(UBYTE)loop;
  767.  
  768.         sprintf(global->tmp1,"Testing with a %ld byte buffer.  (%s-aligned, MEMF_%s)",size,type2,type);
  769.         AddDisplayLine(global,global->tmp1);
  770.  
  771.         count=0;
  772.         times=0;
  773.  
  774.         Start_Timer(global->timer);
  775.         Init_CPU_Available();        /* Start counting free CPU cycles... */
  776.         while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  777.         {
  778.             if (times<1)
  779.             {
  780.                 if (file) Close(file);
  781.                 DeleteFile(FILE_STRING);
  782.                 if (!(file=Open(FILE_STRING,MODE_NEWFILE)))
  783.                 {
  784.                     Display_Error(global,"Create File");
  785.                     worked=FALSE;
  786.                 }
  787.                 times=0x40000/size;    /* Try to make file at least 256K size */
  788.             }
  789.             if (file)
  790.             {
  791.                 if (size!=Write(file,buffer,size))
  792.                 {
  793.                     Display_Error(global,"Create File");
  794.                     worked=FALSE;
  795.                 }
  796.                 else count+=size;
  797.                 times--;
  798.             }
  799.         }
  800.         Stop_Timer(global->timer);
  801.  
  802.         if (worked) Display_Result(global,BYTES_CREATE,count,BYTE_UNITS);
  803.  
  804.         /* Fill out the file... */
  805.         if (file) while ((worked &= Check_Quit(global)) && (times>0))
  806.         {
  807.             Write(file,buffer,size);
  808.             times--;
  809.         }
  810.  
  811.         if (file) Close(file);
  812.         file=NULL;
  813.  
  814.         if (worked) if (!(file=Open(FILE_STRING,MODE_OLDFILE)))
  815.         {
  816.             Display_Error(global,"Write File");
  817.             worked=FALSE;
  818.         }
  819.  
  820.         count=0;
  821.         times=0;
  822.  
  823.         Start_Timer(global->timer);
  824.         Init_CPU_Available();        /* Start counting free CPU cycles... */
  825.         while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  826.         {
  827.             if (times<1)
  828.             {
  829.                 Seek(file,0,OFFSET_BEGINNING);
  830.                 times=0x40000/size;    /* Try to make file at least 256K size */
  831.             }
  832.             if (size!=Write(file,buffer,size))
  833.             {
  834.                 Display_Error(global,"Write File");
  835.                 worked=FALSE;
  836.             }
  837.             else count+=size;
  838.             times--;
  839.         }
  840.         Stop_Timer(global->timer);
  841.  
  842.         if (worked) Display_Result(global,BYTES_WRITE,count,BYTE_UNITS);
  843.  
  844.         if (file) Close(file);
  845.         file=NULL;
  846.  
  847.         if (worked) if (!(file=Open(FILE_STRING,MODE_OLDFILE)))
  848.         {
  849.             Display_Error(global,"Read File");
  850.             worked=FALSE;
  851.         }
  852.  
  853.         count=0;
  854.         times=0;
  855.  
  856.         Start_Timer(global->timer);
  857.         Init_CPU_Available();        /* Start counting free CPU cycles... */
  858.         while ((worked &= Check_Quit(global)) && (Read_Timer(global->timer) < global->Min_Time))
  859.         {
  860.             if (times<1)
  861.             {
  862.                 Seek(file,0,OFFSET_BEGINNING);
  863.                 times=0x40000/size;    /* Try to make file at least 256K size */
  864.             }
  865.             if (size!=Read(file,buffer,size))
  866.             {
  867.                 Display_Error(global,"Read File");
  868.                 worked=FALSE;
  869.             }
  870.             else count+=size;
  871.             times--;
  872.         }
  873.         Stop_Timer(global->timer);
  874.  
  875.         if (worked)
  876.         {
  877.             for (loop=0;loop<size;loop++) worked &= (buffer[loop]==(UBYTE)loop);
  878.             if (!worked) AddDisplayLine(global,"*** Data Error ***  Buffer did not read correctly.");
  879.         }
  880.  
  881.         if (worked) Display_Result(global,BYTES_READ,count,BYTE_UNITS);
  882.  
  883.         if (file) Close(file);
  884.  
  885.         Free_CPU_Available();
  886.         FreeMem(mem,size+offset);
  887.         DeleteFile(FILE_STRING);
  888.     }
  889.     else
  890.     {
  891.         sprintf(global->tmp1,"Skipping %ld byte MEMF_%s test due to lack of memory.",size,type);
  892.         AddDisplayLine(global,global->tmp1);
  893.     }
  894.  
  895.     return(worked);
  896. }
  897.  
  898. /*
  899.  * Clean up (remove) all of the files in the current directory...
  900.  */
  901. void CleanUpFiles(struct DiskSpeed *global)
  902. {
  903. BPTR    lock;
  904.  
  905.     CurrentDir(lock=CurrentDir(NULL));    /* Get current directory lock */
  906.  
  907.     while (lock)
  908.     {
  909.         if (Examine(lock,global->fib))
  910.         {
  911.             if (ExNext(lock,global->fib)) DeleteFile(global->fib->fib_FileName);
  912.             else lock=NULL;
  913.         }
  914.         else lock=NULL;
  915.     }
  916. }
  917.  
  918. void DoTests(struct DiskSpeed *global)
  919. {
  920. char    *p=global->tmp1;
  921. BOOL    working;
  922. ULONG    memtype;
  923. ULONG    offset;
  924. LONG    buffers;
  925. char    *fstring;
  926. short    size;
  927.  
  928.     /*
  929.      * Ok, so now we are ready to run...  Display the
  930.      * test conditions...
  931.      */
  932.     strcpy(p,"CPU: ");
  933.     strcat(p,global->CPU_Type);
  934.     strcat(p,"  OS Version: ");
  935.     strcat(p,global->Exec_Ver);
  936.     if (global->HighDMA) strcat(p,"  High");
  937.     else strcat(p,"  Normal");
  938.     strcat(p," Video DMA");
  939.     AddDisplayLine(global,p);
  940.  
  941.     /*
  942.      * Now, if we are in 2.0 OS, we can also find out the number of buffers
  943.      * (maybe) on that device.  This is important.
  944.      */
  945.     fstring="Device: %s    Buffers: <information unavailable>";
  946.     if (DOSBase->lib_Version > 36L)
  947.     {
  948.         /*
  949.          * Ok, so we can now try to get a reading of the buffers
  950.          * for the place we are about to test...
  951.          *
  952.          * Note:  Since we are in the "CURRENTDIR" of the test disk,
  953.          * we are using "" as the "device" to which to call AddBuffers()
  954.          */
  955.         if ((buffers=AddBuffers("",0)) > 0) fstring="Device:  %s    Buffers: %ld";
  956.     }
  957.  
  958.     sprintf(p,fstring,global->Device,buffers);
  959.     AddDisplayLine(global,p);
  960.  
  961.     if (global->Comments[0])
  962.     {
  963.         strcpy(p,"Comments: ");
  964.         strcat(p,global->Comments);
  965.         AddDisplayLine(global,p);
  966.     }
  967.  
  968.     AddDisplayLine(global,"");
  969.  
  970.     if (CPU_Use_Base) Delay(60);    /* Make sure filesystem has flushed... */
  971.  
  972.     Init_CPU_Available();
  973.     if (CPU_Use_Base) Delay(75);    /* Get a quick reading (~1.5 seconds) */
  974.     Free_CPU_Available();
  975.  
  976.     if (CPU_Use_Base)
  977.     {
  978.         /*
  979.          * Now, generate a countdown value that is aprox 3 times 1.5 second...
  980.          */
  981.         CPU_Use_Base=(CPU_Count_Low * 3) + 1;
  982.         CPU_Count_Low=CPU_Use_Base;
  983.         Forbid();
  984.         Start_Timer(global->timer);
  985.         CPU_Calibrate();
  986.         Stop_Timer(global->timer);
  987.         Permit();
  988.  
  989.         /*
  990.          * If it looks like we did not get a good reading,
  991.          * set up CPU_Use_Base to 0 in order to turn off
  992.          * CPU readings...
  993.          */
  994.         if (global->timer->time.tv_secs<4)
  995.         {
  996.             AddDisplayLine(global,"CPU Calibration shows that CPU availability tests");
  997.             AddDisplayLine(global,"would be inaccurate in the current system state.");
  998.             CPU_Use_Base=0;
  999.         }
  1000.         else CPU_Use_Base=MaxDivide(CPU_Use_Base,(global->timer->time.tv_secs * 1000000) + global->timer->time.tv_micro,6);
  1001.     }
  1002.  
  1003.     global->Base_CPU=CPU_Use_Base;
  1004.  
  1005.     if (CPU_Use_Base) sprintf(p,"CPU Speed Rating: %ld",(((CPU_Use_Base/500)+1) >> 1 ));
  1006.     else strcpy(p,"No CPU Speed Rating -- CPU % not available.");
  1007.     AddDisplayLine(global,p);
  1008.     AddDisplayLine(global,"");
  1009.  
  1010.     global->CPU_Total=0L;
  1011.     global->CPU_Count=0L;
  1012.  
  1013.     working=Check_Quit(global);
  1014.  
  1015.     if (working) if (global->Test_DIR)
  1016.     {
  1017.         AddDisplayLine(global,"Testing directory manipulation speed.");
  1018.         if (working) working=CreateFileTest(global);
  1019.         if (working) working=OpenFileTest(global);
  1020.         if (working) working=ScanDirectoryTest(global);
  1021.         if (working) working=DeleteFileTest(global);
  1022.     }
  1023.  
  1024.     if (working) if (global->Test_SEEK)
  1025.     {
  1026.         AddDisplayLine(global,"");
  1027.         if (working) working=SeekReadTest(global);
  1028.     }
  1029.  
  1030.     /* Now for some of the more complex tests */
  1031.     /* result=SpeedTest(global,Buffer,offset,mem_type); */
  1032.  
  1033.     memtype=MEMF_FAST;
  1034.     while (memtype)
  1035.     {
  1036.         if (memtype & global->Mem_TYPES) for (offset=4;offset>0;offset=offset >> 1) if (offset & global->Align_Types)
  1037.         {
  1038.             for (size=0;size<4;size++) if (global->Test_Size[size])
  1039.             {
  1040.                 if (working) working=SpeedTest(global,global->Test_Size[size],offset&3,memtype);
  1041.             }
  1042.         }
  1043.  
  1044.         if (memtype & MEMF_CHIP) memtype=0;
  1045.         else memtype=MEMF_CHIP;
  1046.     }
  1047.  
  1048.     CleanUpFiles(global);
  1049.  
  1050.     if ((working) && (global->CPU_Count))
  1051.     {
  1052.         AddDisplayLine(global,"");
  1053.         global->CPU_Total=(((global->CPU_Total << 1) / global->CPU_Count)+1) >> 1;
  1054.         global->CPU_Count=(((global->Base_CPU * global->CPU_Total) / 50000)+1) >> 1;
  1055.         sprintf(p,"Average CPU Available: %ld%%  |  CPU Availability index: %ld",global->CPU_Total,global->CPU_Count);
  1056.         AddDisplayLine(global,p);
  1057.     }
  1058. }
  1059.  
  1060. void StartTest(struct DiskSpeed *global)
  1061. {
  1062. BPTR    lock;
  1063. BPTR    newlock;
  1064. APTR    oldwindow;
  1065.  
  1066.     oldwindow=global->Me->pr_WindowPtr;
  1067.     global->Me->pr_WindowPtr=(APTR)(-1L);
  1068.  
  1069.     FreeDisplayList(global);
  1070.  
  1071.     AddDisplayLine(global,COPYRIGHT);
  1072.     AddDisplayLine(global,"-------------------------------------------------------------");
  1073.  
  1074.     if (lock=Lock(global->Device,ACCESS_READ))
  1075.     {
  1076.         lock=CurrentDir(lock);
  1077.         if (newlock=CreateDir(TEST_DIR))
  1078.         {
  1079.             UnLock(newlock);
  1080.             if (newlock=Lock(TEST_DIR,ACCESS_READ))
  1081.             {
  1082.                 newlock=CurrentDir(newlock);
  1083.  
  1084.                 /*
  1085.                  * Now do all of the tests...
  1086.                  */
  1087.                 DoTests(global);
  1088.  
  1089.                 newlock=CurrentDir(newlock);
  1090.                 UnLock(newlock);
  1091.             }
  1092.             else AddDisplayLine(global,"Error:  Could not access test directory.");
  1093.             DeleteFile(TEST_DIR);
  1094.         }
  1095.         else AddDisplayLine(global,"Error:  Could not create test directory.");
  1096.         lock=CurrentDir(lock);
  1097.         UnLock(lock);
  1098.     }
  1099.     else AddDisplayLine(global,"Error:  Could not get a lock on test device.");
  1100.  
  1101.     global->Me->pr_WindowPtr=oldwindow;
  1102. }
  1103.  
  1104. VOID SetVersionStrings(struct DiskSpeed *global)
  1105. {
  1106. UWORD    flags=((struct ExecBase *)(SysBase))->AttnFlags;
  1107. char    *p;
  1108.  
  1109.     strcpy(global->CPU_Type,"68000");
  1110.     p=&(global->CPU_Type[3]);
  1111.     if (flags & AFF_68010) *p='1';
  1112.     if (flags & AFF_68020) *p='2';
  1113.     if (flags & AFF_68030) *p='3';
  1114.     if (flags & AFF_68040) *p='4';
  1115.  
  1116.     sprintf(global->Exec_Ver,"%ld.%ld",(ULONG)(SysBase->lib_Version),(ULONG)(((struct ExecBase *)SysBase)->SoftVer));
  1117. }
  1118.  
  1119. /*
  1120.  * A simple string check that also works with '=' at the end of the string
  1121.  */
  1122. char *Check_String(char *arg,char *match)
  1123. {
  1124. char    *p;
  1125. char    *next=NULL;
  1126.  
  1127.     p=arg;
  1128.     while (*p)
  1129.     {
  1130.         if (*p=='=')
  1131.         {
  1132.             *p='\0';
  1133.             next=p;
  1134.         }
  1135.         else p++;
  1136.     }
  1137.  
  1138.     if (stricmp(arg,match))
  1139.     {
  1140.         if (next) *next='=';
  1141.         next=NULL;
  1142.     }
  1143.     else
  1144.     {
  1145.         if (next) next++;
  1146.         else next=p;
  1147.     }
  1148.  
  1149.     return(next);
  1150. }
  1151.  
  1152. /*
  1153.  * This routine closes down the GUI
  1154.  */
  1155. void Close_GUI(struct DiskSpeed *global)
  1156. {
  1157.     if (global->Window)
  1158.     {
  1159.         CloseWindow(global->Window);
  1160.         global->Window=NULL;
  1161.     }
  1162.     if (global->List)
  1163.     {
  1164.         FreeListGadget(global->List);
  1165.         global->List=NULL;
  1166.     }
  1167.     if (global->ri)
  1168.     {
  1169.         CleanUp_RenderInfo(global->ri);
  1170.         global->ri=NULL;
  1171.     }
  1172. }
  1173.  
  1174. /*
  1175.  * This routine is used to open the GUI...
  1176.  */
  1177. BOOL Open_GUI(struct DiskSpeed *global)
  1178. {
  1179.     BOOL        worked=FALSE;
  1180.     UWORD        internalwidth;
  1181.     UWORD        internalheight;
  1182. struct    Gadget        *gad=NULL;
  1183. struct    NewWindow    nw;
  1184.  
  1185.     if (!global->Window)
  1186.     {
  1187.         /* Now, open/set up the GUI... */
  1188.         nw.LeftEdge=0;
  1189.         nw.TopEdge=11;
  1190.         nw.Width=540;
  1191.         nw.Height=180;
  1192.         nw.DetailPen=-1;
  1193.         nw.BlockPen=-1;
  1194.         nw.IDCMPFlags=GADGETDOWN|GADGETUP|CLOSEWINDOW|ACTIVEWINDOW;
  1195.         nw.Flags=SMART_REFRESH|ACTIVATE|NOCAREREFRESH|RMBTRAP|WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG;
  1196.         nw.FirstGadget=NULL;
  1197.         nw.CheckMark=NULL;
  1198.         nw.Title=COPYRIGHT;
  1199.         nw.Type=WBENCHSCREEN;
  1200.  
  1201.         if (global->Window=OpenWindow(&nw)) if ((global->Window->Height-global->Window->BorderTop-global->Window->BorderBottom) > 120)
  1202.         {
  1203.             if (global->ri=Get_RenderInfo(global->Window->WScreen))
  1204.             {
  1205.                 internalwidth=global->Window->Width-global->Window->BorderLeft-global->Window->BorderRight;
  1206.                 internalheight=global->Window->Height-global->Window->BorderTop-global->Window->BorderBottom;
  1207.  
  1208.                 global->List=InitListGadget(&TOPAZ80,&gad,1,
  1209.                                 global->ri->Highlight,
  1210.                                 global->ri->Shadow,
  1211.                                 global->Window->BorderLeft+4,
  1212.                                 global->Window->BorderTop+33,
  1213.                                 internalwidth-8,
  1214.                                 internalheight-49);
  1215.  
  1216.                 /*
  1217.                  * Set up borders for the string gadgets
  1218.                  */
  1219.                 global->StringBorder[0].LeftEdge=-5;
  1220.                 global->StringBorder[0].TopEdge=-3;
  1221.                 global->StringBorder[0].FrontPen=global->ri->Highlight;
  1222.                 global->StringBorder[0].DrawMode=JAM1;
  1223.                 global->StringBorder[0].Count=5;
  1224.                 global->StringBorder[0].XY=&(global->StringVectors[0*5*2]);
  1225.                 global->StringBorder[0].NextBorder=&(global->StringBorder[1]);
  1226.  
  1227.                 global->StringBorder[1]=global->StringBorder[0];
  1228.                 global->StringBorder[1].FrontPen=global->ri->Shadow;
  1229.                 global->StringBorder[1].XY=&(global->StringVectors[1*5*2]);
  1230.                 global->StringBorder[1].NextBorder=&(global->StringBorder[2]);
  1231.  
  1232.                 global->StringBorder[2].LeftEdge=-3;
  1233.                 global->StringBorder[2].TopEdge=-2;
  1234.                 global->StringBorder[2].FrontPen=global->ri->Shadow;
  1235.                 global->StringBorder[2].DrawMode=JAM1;
  1236.                 global->StringBorder[2].Count=5;
  1237.                 global->StringBorder[2].XY=&(global->StringVectors[2*5*2]);
  1238.                 global->StringBorder[2].NextBorder=&(global->StringBorder[3]);
  1239.  
  1240.                 global->StringBorder[3]=global->StringBorder[2];
  1241.                 global->StringBorder[3].FrontPen=global->ri->Highlight;
  1242.                 global->StringBorder[3].XY=&(global->StringVectors[3*5*2]);
  1243.                 global->StringBorder[3].NextBorder=NULL;
  1244.  
  1245.                 FillTopLeft_Border(&(global->StringBorder[0]),internalwidth-81,14);
  1246.                 FillBottomRight_Border(&(global->StringBorder[1]),internalwidth-81,14);
  1247.                 FillTopLeft_Border(&(global->StringBorder[2]),internalwidth-85,12);
  1248.                 FillBottomRight_Border(&(global->StringBorder[3]),internalwidth-85,12);
  1249.  
  1250.                 /*
  1251.                  * Now add the few other gadgets to the window...
  1252.                  */
  1253.                 global->DeviceGadget.NextGadget=gad;        gad=&(global->DeviceGadget);
  1254.                 gad->LeftEdge=82+global->Window->BorderLeft;
  1255.                 gad->TopEdge=5+global->Window->BorderTop;
  1256.                 gad->Width=internalwidth-91;
  1257.                 gad->Height=8;
  1258.                 gad->Flags=GADGHCOMP;
  1259.                 gad->Activation=RELVERIFY;
  1260.                 gad->GadgetType=STRGADGET;
  1261.                 gad->GadgetRender=(APTR)&(global->StringBorder[0]);
  1262.                 gad->GadgetText=&(global->DeviceText);
  1263.                 gad->SpecialInfo=(APTR)&(global->DeviceInfo);
  1264.                 gad->GadgetID=DEVICE_GADGET;
  1265.  
  1266.                 global->CommentsGadget=global->DeviceGadget;
  1267.                 global->CommentsGadget.NextGadget=gad;        gad=&(global->CommentsGadget);
  1268.                 gad->TopEdge+=15;
  1269.                 gad->GadgetText=&(global->CommentsText);
  1270.                 gad->SpecialInfo=(APTR)&(global->CommentsInfo);
  1271.                 gad->GadgetID=COMMENT_GADGET;
  1272.  
  1273.                 global->DeviceInfo.Buffer=global->Device;
  1274.                 global->DeviceInfo.UndoBuffer=global->Undo;
  1275.                 global->DeviceInfo.MaxChars=250;
  1276.                 global->CommentsInfo=global->DeviceInfo;
  1277.                 global->CommentsInfo.Buffer=global->Comments;
  1278.  
  1279.                 global->DeviceText.FrontPen=1;
  1280.                 global->DeviceText.BackPen=0;
  1281.                 global->DeviceText.DrawMode=JAM2;
  1282.                 global->DeviceText.LeftEdge=-64;    /* 8 x 8 */
  1283.                 global->DeviceText.TopEdge=0;
  1284.                 global->DeviceText.ITextFont=&TOPAZ80;
  1285.                 global->DeviceText.IText="Device:";
  1286.  
  1287.                 global->CommentsText=global->DeviceText;
  1288.                 global->CommentsText.LeftEdge=-80;    /* 10 x 8 */
  1289.                 global->CommentsText.IText="Comments:";
  1290.  
  1291.                 /*
  1292.                  * Set up borders for the action gadgets (One set for all gadgets...)
  1293.                  */
  1294.                 global->ActionBorder[0].FrontPen=global->ri->Highlight;
  1295.                 global->ActionBorder[0].DrawMode=JAM1;
  1296.                 global->ActionBorder[0].Count=5;
  1297.                 global->ActionBorder[0].XY=&(global->ActionVectors[0*5*2]);
  1298.                 global->ActionBorder[0].NextBorder=&(global->ActionBorder[1]);
  1299.  
  1300.                 global->ActionBorder[1].FrontPen=global->ri->Shadow;
  1301.                 global->ActionBorder[1].DrawMode=JAM1;
  1302.                 global->ActionBorder[1].Count=5;
  1303.                 global->ActionBorder[1].XY=&(global->ActionVectors[1*5*2]);
  1304.                 global->ActionBorder[1].NextBorder=NULL;
  1305.  
  1306.                 global->ActionBorder[2]=global->ActionBorder[0];
  1307.                 global->ActionBorder[2].FrontPen=global->ri->Shadow;
  1308.                 global->ActionBorder[2].NextBorder=&(global->ActionBorder[3]);
  1309.  
  1310.                 global->ActionBorder[3]=global->ActionBorder[1];
  1311.                 global->ActionBorder[3].FrontPen=global->ri->Highlight;
  1312.  
  1313.                 FillTopLeft_Border(&(global->ActionBorder[0]),108,12);
  1314.                 FillBottomRight_Border(&(global->ActionBorder[1]),108,12);
  1315.  
  1316.                 /*
  1317.                  * Now for the two action gadgets at the bottom...
  1318.                  */
  1319.                 global->StartTestGadget.NextGadget=gad;        gad=&(global->StartTestGadget);
  1320.                 gad->LeftEdge=global->Window->BorderLeft+4;
  1321.                 gad->TopEdge=global->Window->Height-global->Window->BorderBottom-14;
  1322.                 gad->Width=108;
  1323.                 gad->Height=12;
  1324.                 gad->Flags=((global->ri->Shadow==global->ri->Highlight) ? GADGHCOMP : GADGHIMAGE);
  1325.                 gad->Activation=RELVERIFY;
  1326.                 gad->GadgetType=BOOLGADGET;
  1327.                 gad->GadgetRender=(APTR)&(global->ActionBorder[0]);
  1328.                 gad->SelectRender=(APTR)&(global->ActionBorder[2]);
  1329.                 gad->GadgetText=&(global->StartTest);
  1330.                 gad->GadgetID=TEST_GADGET;
  1331.  
  1332.                 global->StartTest.FrontPen=1;
  1333.                 global->StartTest.DrawMode=JAM1;
  1334.                 global->StartTest.ITextFont=&TOPAZ80;
  1335.                 global->StartTest.IText=START_TEST;
  1336.                 global->StartTest.TopEdge=2;
  1337.                 global->StartTest.LeftEdge=14;
  1338.  
  1339.                 global->SaveResultsGadget=global->StartTestGadget;
  1340.                 global->SaveResultsGadget.NextGadget=gad;    gad=&(global->SaveResultsGadget);
  1341.                 gad->LeftEdge=global->Window->Width-global->Window->BorderRight-112;
  1342.                 gad->GadgetText=&(global->SaveResults);
  1343.                 gad->GadgetID=SAVE_GADGET;
  1344.  
  1345.                 global->SaveResults=global->StartTest;
  1346.                 global->SaveResults.IText=SAVE_RESULTS;
  1347.                 global->SaveResults.LeftEdge=6;
  1348.  
  1349.                 global->StopTestGadget=global->StartTestGadget;
  1350.                 global->StopTestGadget.NextGadget=gad;    gad=&(global->StopTestGadget);
  1351.                 gad->LeftEdge=(global->Window->Width-108)/2;
  1352.                 gad->GadgetText=&(global->StopTest);
  1353.                 gad->GadgetID=STOP_GADGET;
  1354.  
  1355.                 global->StopTest=global->StartTest;
  1356.                 global->StopTest.IText=STOP_TEST;
  1357.                 global->StopTest.LeftEdge=18;
  1358.  
  1359.                 if (global->List)
  1360.                 {
  1361.                     AddGList(global->Window,gad,-1,-1,NULL);
  1362.                     RefreshGList(gad,global->Window,NULL,-1);
  1363.                     worked=TRUE;
  1364.                 }
  1365.             }
  1366.         }
  1367.  
  1368.         if (!worked) Close_GUI(global);
  1369.     }
  1370.  
  1371.     return(global->Window!=NULL);
  1372. }
  1373.  
  1374. /*
  1375.  * This routine will append to the end of a file the results currently in memory...
  1376.  */
  1377. void Save_Results(struct DiskSpeed *global)
  1378. {
  1379.     BPTR        fh;
  1380. struct    Node        *node;
  1381.  
  1382.     if (fh=Open("DiskSpeed.Results",MODE_OLDFILE))
  1383.     {
  1384.         Seek(fh,0,OFFSET_END);
  1385.         Write(fh,"\n\n\n",2);
  1386.     }
  1387.     else fh=Open("DiskSpeed.Results",MODE_NEWFILE);
  1388.  
  1389.     if (fh)
  1390.     {
  1391.         node=(struct Node *)(global->TextList.mlh_Head);
  1392.         while (node->ln_Succ)
  1393.         {
  1394.             Write(fh,node->ln_Name,strlen(node->ln_Name));
  1395.             Write(fh,"\n",1);
  1396.             node=node->ln_Succ;
  1397.         }
  1398.  
  1399.         Close(fh);
  1400.     }
  1401. }
  1402.  
  1403. /*
  1404.  * This routine is used to control the GUI
  1405.  */
  1406. void Do_GUI(struct DiskSpeed *global)
  1407. {
  1408.     BOOL        done=FALSE;
  1409. struct    IntuiMessage    *msg;
  1410.  
  1411.     while (!done)
  1412.     {
  1413.         WaitPort(global->Window->UserPort);
  1414.         while (msg=(struct IntuiMessage *)GetMsg(global->Window->UserPort))
  1415.         {
  1416.             if (!Check_ListGadget(global->Window,msg))
  1417.             {
  1418.                 if (msg->Class==CLOSEWINDOW) done=TRUE;
  1419.                 else if (msg->Class==GADGETUP)
  1420.                 {
  1421.                     switch(((struct Gadget *)(msg->IAddress))->GadgetID)
  1422.                     {
  1423.                     case DEVICE_GADGET:    ActivateGadget(&(global->CommentsGadget),global->Window,NULL);
  1424.                                 break;
  1425.                     case COMMENT_GADGET:    ActivateGadget(&(global->DeviceGadget),global->Window,NULL);
  1426.                                 break;
  1427.                     case TEST_GADGET:    SetWait(global->Window);
  1428.                                 StartTest(global);
  1429.                                 ClearWait(global->Window);
  1430.                                 break;
  1431.                     case SAVE_GADGET:    SetWait(global->Window);
  1432.                                 Save_Results(global);
  1433.                                 ClearWait(global->Window);
  1434.                                 break;
  1435.                     }
  1436.                 }
  1437.                 else if (msg->Class=ACTIVEWINDOW)
  1438.                 {
  1439.                     ActivateGadget(&(global->DeviceGadget),global->Window,NULL);
  1440.                 }
  1441.             }
  1442.             ReplyMsg((struct Message *)msg);
  1443.         }
  1444.     }
  1445.     /* Shut down GUI */
  1446.     Close_GUI(global);
  1447. }
  1448.  
  1449. /*
  1450.  * DRIVE/K    - select drive  (Default is current directory)
  1451.  * COMMENT/K    - set comment string
  1452.  * ALL/S    - select all tests
  1453.  * DIR/S    - setect DIR tests
  1454.  * SEEK/S    - select SEEK tests
  1455.  * CHIP/S    - select CHIP memory buffer tests
  1456.  * FAST/S    - select FAST memory buffer tests
  1457.  * LONG/S    - select LONG aligned tests
  1458.  * WORD/S    - select WORD aligned tests
  1459.  * BYTE/S    - select BYTE aligned tests
  1460.  * NOCPU/S    - turn off CPU availability tests
  1461.  * BUF1/K/N    - select buffer size 1
  1462.  * BUF2/K/N    - select buffer size 2
  1463.  * BUF3/K/N    - select buffer size 3
  1464.  * BUF4/K/N    - select buffer size 4
  1465.  * MINTIME/K/N    - select the minimum test time (default=8) in seconds
  1466.  * WINDOW/S    - use the GUI even though started from the CLI
  1467.  */
  1468.  
  1469. /*
  1470.  * do the command line parsing here...
  1471.  */
  1472. BOOL ParseArg(struct DiskSpeed *global,int argc,char *argv[],int start)
  1473. {
  1474. int    loop;
  1475. char    *arg;
  1476. char    *next;
  1477. BOOL    working=TRUE;
  1478. BOOL    window=FALSE;
  1479.  
  1480.     for (loop=start;loop<argc;loop++)
  1481.     {
  1482.         arg=argv[loop];
  1483.         if (*arg=='?')
  1484.         {
  1485.             loop=argc;
  1486.             working=FALSE;
  1487.         }
  1488.         else if (next=Check_String(arg,"DRIVE"))
  1489.         {
  1490.             if (!(*next))
  1491.             {
  1492.                 loop++;
  1493.                 if (loop<argc) next=argv[loop];
  1494.             }
  1495.             if (strlen(next)>255) *next='\0';
  1496.             if (*next) strcpy(global->Device,next);
  1497.             else working=FALSE;
  1498.         }
  1499.         else if (next=Check_String(arg,"COMMENT"))
  1500.         {
  1501.             if (!(*next))
  1502.             {
  1503.                 loop++;
  1504.                 if (loop<argc) next=argv[loop];
  1505.             }
  1506.             if (strlen(next)>255) *next='\0';
  1507.             if (*next) strcpy(global->Comments,next);
  1508.             else working=FALSE;
  1509.         }
  1510.         else if (Check_String(arg,"ALL"))
  1511.         {
  1512.             /* All tests */
  1513.             global->Test_DIR=TRUE;
  1514.             global->Test_SEEK=TRUE;
  1515.             global->Align_Types=4|2|1;
  1516.             global->Mem_TYPES=MEMF_CHIP | MEMF_FAST;
  1517.         }
  1518.         else if (next=Check_String(arg,"BUF1"))
  1519.         {
  1520.             if (!(*next))
  1521.             {
  1522.                 loop++;
  1523.                 if (loop<argc) next=argv[loop];
  1524.             }
  1525.             if (*next) stcd_l(next,&(global->Test_Size[0]));
  1526.             else working=FALSE;
  1527.         }
  1528.         else if (next=Check_String(arg,"BUF2"))
  1529.         {
  1530.             if (!(*next))
  1531.             {
  1532.                 loop++;
  1533.                 if (loop<argc) next=argv[loop];
  1534.             }
  1535.             if (*next) stcd_l(next,&(global->Test_Size[1]));
  1536.             else working=FALSE;
  1537.         }
  1538.         else if (next=Check_String(arg,"BUF3"))
  1539.         {
  1540.             if (!(*next))
  1541.             {
  1542.                 loop++;
  1543.                 if (loop<argc) next=argv[loop];
  1544.             }
  1545.             if (*next) stcd_l(next,&(global->Test_Size[2]));
  1546.             else working=FALSE;
  1547.         }
  1548.         else if (next=Check_String(arg,"BUF4"))
  1549.         {
  1550.             if (!(*next))
  1551.             {
  1552.                 loop++;
  1553.                 if (loop<argc) next=argv[loop];
  1554.             }
  1555.             if (*next) stcd_l(next,&(global->Test_Size[3]));
  1556.             else working=FALSE;
  1557.         }
  1558.         else if (next=Check_String(arg,"MINTIME"))
  1559.         {
  1560.             if (!(*next))
  1561.             {
  1562.                 loop++;
  1563.                 if (loop<argc) next=argv[loop];
  1564.             }
  1565.             if (*next) stcd_l(next,&(global->Min_Time));
  1566.             else working=FALSE;
  1567.         }
  1568.         else if (Check_String(arg,"DIR")) global->Test_DIR=TRUE;
  1569.         else if (Check_String(arg,"SEEK")) global->Test_SEEK=TRUE;
  1570.         else if (Check_String(arg,"CHIP")) global->Mem_TYPES|=MEMF_CHIP;
  1571.         else if (Check_String(arg,"FAST")) global->Mem_TYPES|=MEMF_FAST;
  1572.         else if (Check_String(arg,"LONG")) global->Align_Types|=4;
  1573.         else if (Check_String(arg,"WORD")) global->Align_Types|=2;
  1574.         else if (Check_String(arg,"BYTE")) global->Align_Types|=1;
  1575.         else if (Check_String(arg,"NOCPU")) CPU_Use_Base=FALSE;
  1576.         else if (Check_String(arg,"WINDOW")) window=TRUE;
  1577.         else
  1578.         {    /* Did not match, so error */
  1579.             working=FALSE;
  1580.         }
  1581.     }
  1582.  
  1583.     if (global->Min_Time < 1) global->Min_Time=1;
  1584.  
  1585.     if (working) if (window) working=Open_GUI(global);
  1586.  
  1587.     return(working);
  1588. }
  1589.  
  1590. /*
  1591.  * This routine is called when we want to run from a GUI
  1592.  * Normally, it is only called when started from Workbench
  1593.  * or when the CLI WINDOW option is given...
  1594.  */
  1595. void DoWorkbench(struct DiskSpeed *global,int argc,char *argv[])
  1596. {
  1597. struct    WBStartup    *wbmsg;
  1598. struct    WBArg        *wbarg;
  1599.     BPTR        lock;
  1600. struct    DiskObject    *icon;
  1601.  
  1602.     wbmsg=(struct WBStartup *)argv;
  1603.  
  1604.     if ((wbarg=wbmsg->sm_ArgList) && (wbmsg->sm_NumArgs))
  1605.     {
  1606.         /* We only care about the first one... */
  1607.         lock=CurrentDir(wbarg->wa_Lock);
  1608.  
  1609.         argc=0;
  1610.         if (icon=GetDiskObject(wbarg->wa_Name))
  1611.         {
  1612.             argv=icon->do_ToolTypes;
  1613.             while (argv[argc]) argc++;
  1614.             /*
  1615.              * Don't care about argument errors in tooltypes
  1616.              * since other things may have been in there...
  1617.              */
  1618.             ParseArg(global,argc,argv,0);
  1619.             FreeDiskObject(icon);
  1620.         }
  1621.         if (!argc)
  1622.         {
  1623.             /* All tests */
  1624.             global->Test_DIR=TRUE;
  1625.             global->Test_SEEK=TRUE;
  1626.             global->Align_Types=4|2|1;
  1627.             global->Mem_TYPES=MEMF_CHIP | MEMF_FAST;
  1628.         }
  1629.  
  1630.         if (Open_GUI(global)) Do_GUI(global);
  1631.  
  1632.         CurrentDir(lock);
  1633.     }
  1634. }
  1635.  
  1636. /*
  1637.  * This is the CLI starting point.  We do the command line parsing here...
  1638.  */
  1639. void DoCLI(struct DiskSpeed *global,int argc,char *argv[])
  1640. {
  1641.     if (ParseArg(global,argc,argv,1))
  1642.     {
  1643.         if (global->Window) Do_GUI(global);
  1644.         else StartTest(global);
  1645.     }
  1646.     else AddDisplayLine(global,"DRIVE/K,ALL/S,DIR/S,SEEK/S,CHIP/S,FAST/S,LONG/S,WORD/S,BYTE/S,NOCPU/S,BUF1/K/N,BUF2/K/N,BUF3/K/N,BUF4/K/N,MINTIME/K/N,WINDOW/S");
  1647. }
  1648.  
  1649. void main(int argc, char *argv[])
  1650. {
  1651. struct    DiskSpeed    *global;
  1652.  
  1653.     CPU_Use_Base=TRUE;    /* We want to test with CPU */
  1654.  
  1655.     if (IntuitionBase=OpenLibrary("intuition.library",33L))
  1656.     {
  1657.         if (GfxBase=OpenLibrary("graphics.library",33L))
  1658.         {
  1659.             if (LayersBase=OpenLibrary("layers.library",33L))
  1660.             {
  1661.                 if (IconBase=OpenLibrary("icon.library",33L))
  1662.                 {
  1663.                     if (global=AllocMem(sizeof(struct DiskSpeed),MEMF_PUBLIC|MEMF_CLEAR))
  1664.                     {
  1665.                         NewList((struct List *)&(global->TextList));
  1666.                         SetVersionStrings(global);
  1667.                         global->Me=(struct Process *)FindTask(NULL);
  1668.  
  1669.                         /* Standard MinTime */
  1670.                         global->Min_Time=MIN_TEST_TIME;
  1671.  
  1672.                         /* Standard sizes */
  1673.                         global->Test_Size[0]=0x200;
  1674.                         global->Test_Size[1]=0x1000;
  1675.                         global->Test_Size[2]=0x8000;
  1676.                         global->Test_Size[3]=0x40000;
  1677.  
  1678.                         if (global->fib=AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
  1679.                         {
  1680.                             if (global->timer=Init_Timer())
  1681.                             {
  1682.                                 /*
  1683.                                  * Now either set up Window or Output
  1684.                                  * depending on where we were started...
  1685.                                  *
  1686.                                  * If we can not get Output, we set up the window...
  1687.                                  */
  1688.                                 if ((argc) && (global->Output=Output()))
  1689.                                 {
  1690.                                     DoCLI(global,argc,argv);
  1691.                                 }
  1692.                                 else DoWorkbench(global,argc,argv);
  1693.  
  1694.                                 Free_Timer(global->timer);
  1695.                             }
  1696.                             FreeMem(global->fib,sizeof(struct FileInfoBlock));
  1697.                         }
  1698.  
  1699.                         FreeDisplayList(global);
  1700.                         FreeMem(global,sizeof(struct DiskSpeed));
  1701.                     }
  1702.                     CloseLibrary(IconBase);
  1703.                 }
  1704.                 CloseLibrary(LayersBase);
  1705.             }
  1706.             CloseLibrary(GfxBase);
  1707.         }
  1708.         CloseLibrary(IntuitionBase);
  1709.     }
  1710. }
  1711.