Skip to content
Snippets Groups Projects
diskperf.c 29.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
    **++
    **  FACILITY:  DISKPERF
    **
    **  MODULE DESCRIPTION:
    **
    **      Programme d'evaluation des performances sous-systeme disques
    **
    **  AUTHORS:
    **
    
    **      JFP. - Piéronne JF (jf.pieronne@laposte.net)
    
    **
    **  CREATION DATE:  9-Nov-1995
    **
    **  DESIGN ISSUES:
    **
    **      x
    **
    **  VERSION:
    **
    **      1.0
    **
    **
    **  MODIFICATION HISTORY:
    **
    **      Date      | Name  | Description
    **----------------+-------+-----------------------------------------------------
    **    9-Nov-1995  |  JFP  | Version initial
    **----------------+-------+-----------------------------------------------------
    **    9-Nov-1995  |  GC   | Ajout info dans fichier resultats
    **----------------+-------+-----------------------------------------------------
    **   20-Jul-2002  |  JFP  | Correction creation fichiers pour test multi-disques
    **----------------+-------+-----------------------------------------------------
    **   15-Jun-2006  |  JFP  | Message d'utilisation fichier pour tests en R/W
    **                |       | changement FAB$M_CTG en FAB$M_CBT
    **----------------+-------+-----------------------------------------------------
    **
    **--
    */
    
      compilation :
        vax : cc/decc diskperf
    
              cc/vaxc diskperf
    
        axp : cc/prefix=all diskperf
    -*/
    
    /*
    **  INCLUDE FILES
    **/
    
    #ifndef __NEW_STARLET
    
    #define __NEW_STARLET
    
    #include <climsgdef.h>
    #include <dcdef.h>
    
    #include <descrip.h>
    #include <dvidef.h>
    
    #include <fibdef.h>
    #include <gen64def.h>
    #include <iledef.h>
    
    #include <iodef.h>
    
    #include <iosbdef.h>
    #include <lib$routines.h>
    #include <libwaitdef.h>
    
    #include <rms.h>
    #include <rmsdef.h>
    
    #include <ssdef.h>
    #include <starlet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stsdef.h>
    #include <unixio.h>
    #include <unixlib.h>
    
    #define K_DisksCard 10
    #define K_MaxSimQIO 200
    
    
    /* VMS pre 6.0 */
    #ifndef IO$M_NOVCACHE
    #define IO$M_NOVCACHE 0x20000
    #endif
    
    
    #ifdef IN_VSCODE
    # define _align(n)
    #endif
    
    
    typedef struct {
    
        int _IOCount;
        int _ReadIOCount;
        int _WriteIOCount;
        int _elapsed[2];
        unsigned int _cpu;
    
    static enum _tt { KReadOnly = 0, KWriteOnly = 1, KReadWrite = 2 } TypeTest;
    static enum _ts { KDuration = 0, KIOCount = 1, KSize = 2 } TypeStop;
    
    volatile static long ReadCount;
    volatile static long WriteCount;
    static long CacheHitPercent;
    static long ReadPercent;
    static int StartingBlock;
    static int EndingBlock;
    static int Random;
    static int Pass;
    static int Interval;
    volatile static int TotIO;
    volatile static ReadIOCount;
    volatile static WriteIOCount;
    volatile static EndPass;
    volatile static ActiveIOCount = 0;
    static int SimultaneousIO;
    static int MinIOSize;
    static int MaxIOSize;
    static int ReadIOSize;
    static int WriteIOSize;
    static double ReadWriteIOSizeRatio;
    static int PassDuration;
    static int TotSize;
    static int VioModifier;
    static IOSB Iosb[K_MaxSimQIO];
    static int DisksCount;
    static char FullDevnam[K_DisksCard][65], Medianam[K_DisksCard][65];
    static char Volnam[K_DisksCard][13];
    static unsigned short Channel[K_DisksCard];
    volatile static int Address[K_DisksCard];
    Stat_s StatInfo[8][127]; /* 8 pass 1-127 blocks */
    
    static char FileName[K_DisksCard][256];
    static FIBDEF Fib[K_DisksCard];
    
    
    static _align(PAGE) char IOBuffer[K_MaxSimQIO][512 * 127]; /* buffer size 127
                                                                  blocks maximum */
    
    
    static void IOCompletionAST(int);
    
    /*
     * -- DCL callback interface
     */
    
    extern int cli$get_value(struct dsc$descriptor_s *, struct dsc$descriptor_s *,
                             short *);
    extern int cli$present(struct dsc$descriptor_s *);
    
    /*
     * -- RTL string routines
     */
    
    extern int str$free1_dx(struct dsc$descriptor_s *);
    
    static int YesOrNo(const char *str) {
        int rep = 2;
        while ((rep != 0) && (rep != 1)) {
            printf("%s", str);
            scanf("%d", &rep);
        }
        return rep;
    
    }
    
    static void InteractiveQueries() {
    
        printf("\nTest type (0 : Read only, 1 : Write only, 2 : Read-Write): ");
        scanf("%d", &i);
        TypeTest = (enum _tt)i;
        if (TypeTest == KReadWrite) {
            printf("\nRead percent: ");
            scanf("%d", &ReadPercent);
            printf("\n(Read Size / Write Size) Ratio: ");
            scanf("%lf", &ReadWriteIOSizeRatio);
        }
    
    #ifdef FullInteractive
    
        printf("\n# disks (1 - 10): ");
        scanf("%d", &DisksCount);
        getchar();
        if (DisksCount > K_DisksCard)
            exit(SS$_ABORT);
        for (i = 0; i < DisksCount; ++i) {
            int classDisk, opcnt, max, free;
            int hoav;
            int status;
            unsigned short devlen;
            unsigned short volnamlen, medialen;
            int freebl, fp, ip, catchup, merge, member, fail, refcnt;
            int errcnt;
            char devnam[65];
            ILE3 gds[] = {{4, DVI$_DEVCLASS, &classDisk, 0},
                          {4, DVI$_SHDW_CATCHUP_COPYING, &catchup, 0},
                          {4, DVI$_SHDW_FAILED_MEMBER, &fail, 0},
                          {4, DVI$_SHDW_MEMBER, &member, 0},
                          {4, DVI$_SHDW_MERGE_COPYING, &merge, 0},
                          {4, DVI$_HOST_AVAIL, &hoav, 0},
                          {4, DVI$_REFCNT, &refcnt, 0},
                          {4, DVI$_FREEBLOCKS, &freebl, 0},
                          {4, DVI$_MAXBLOCK, &max, 0},
                          {64, DVI$_MEDIA_NAME, Medianam[i], &medialen},
                          {64, DVI$_FULLDEVNAM, FullDevnam[i], &devlen},
                          {4, DVI$_OPCNT, &opcnt, 0},
                          {4, DVI$_ERRCNT, &errcnt, 0},
                          {12, DVI$_VOLNAM, Volnam[i], &volnamlen},
                          {0, 0}};
            $DESCRIPTOR(devnam_d, devnam);
    
            printf("\nDevice name: ");
            gets(devnam);
    
            puts("device name    label    type  # blocks    free blocks        I/O "
                 "     errors");
            puts("------------  --------  ----  ---------  --------------  "
                 "-----------  ------");
    
            devnam_d.dsc$w_length = strlen(devnam);
            memset(Medianam[i], ' ', sizeof(Medianam[0]) - 1);
            Medianam[i][sizeof(Medianam[0]) - 1] = '\0';
            memset(Volnam[i], ' ', sizeof(Volnam[0]) - 1);
            Volnam[i][sizeof(Volnam[0]) - 1] = '\0';
            memset(FullDevnam[i], ' ', sizeof(FullDevnam[0]) - 1);
            FullDevnam[i][sizeof(FullDevnam[0]) - 1] = '\0';
    
            status = sys$getdviw(0, 0, &devnam_d, gds, 0, 0, 0, 0);
            if (!$VMS_STATUS_SUCCESS(status))
                exit(status);
            if ((classDisk != DC$_DISK) || !hoav || member || fail || catchup ||
                merge || (refcnt == 0))
                exit(SS$_ABORT);
            if (max == 0)
                exit(SS$_ABORT);
            //    FullDevnam[i][14] = '\0';
            //    Volnam[i][9] = '\0';
            //    Medianam[i][6] = '\0';
            fp = 100.0 * (double)freebl / (double)max;
            printf("%-13s %-9s %-6s%9d%9d (%3d%%)  %9d  %6d\n", &FullDevnam[i][1],
                   Volnam[i], Medianam[i], max, freebl, fp, opcnt, errcnt);
        }
    
        printf("\nStarting block: ");
        scanf("%d", &StartingBlock);
        printf("\nEnding block: ");
        scanf("%d", &EndingBlock);
        Random = YesOrNo("\nRandom (0/1): ");
        if (!Random) {
            printf("\nInterval (blocks -1 : use IO size): ");
            scanf("%d", &Interval);
        }
    
        VioModifier = YesOrNo("\nVirtual I/O Cache (0/1): ") ? 0 : IO$M_NOVCACHE;
    
        printf("\nEstimate cache hit percent");
        if ((EndingBlock - StartingBlock) < 1000000)
            printf(" (may not be significant): ");
        else
            printf(": ");
        scanf("%d", &CacheHitPercent);
    
        printf("\nPass (8 max): ");
        scanf("%d", &Pass);
    
        printf("\nStop on (0 : Duration, 1 : IOs Count, 2 : Total Size): ");
        scanf("%d", &i);
        TypeStop = (enum _ts)i;
        switch (TypeStop) {
    
        case KDuration:
    
            printf("\nPass Duration: ");
            scanf("%d", &PassDuration);
            break;
    
        case KIOCount:
    
            printf("\nTotal IOs count: ");
            scanf("%d", &TotIO);
            break;
    
        case KSize:
    
            printf("\nTotal Size (Kbytes): ");
            scanf("%d", &TotSize);
            break;
    
            fprintf(stderr, "\nInvalid stop switch\n");
            exit(SS$_ABORT);
        }
        printf("\nSimultaneous IOs count (%d max): ", K_MaxSimQIO / DisksCount);
        scanf("%d", &SimultaneousIO);
        if (SimultaneousIO * DisksCount > K_MaxSimQIO)
            exit(SS$_ABORT);
        printf("\nMin IO size (1-127 blocks): ");
        scanf("%d", &MinIOSize);
        printf("\nMax IO size (%d-127 blocks): ", MinIOSize);
        scanf("%d", &MaxIOSize);
    
    static void ProcessCommandLine() {
    
        $DESCRIPTOR(interactiveQualDesc, "INTERACTIVE");
        $DESCRIPTOR(sequentialQualDesc, "SEQUENTIAL");
        $DESCRIPTOR(seqIntervalQualDesc, "SEQUENTIAL.INTERVAL");
        $DESCRIPTOR(disksQualDesc, "DISKS");
        $DESCRIPTOR(typeReadQualDesc, "TYPE.READ");
        $DESCRIPTOR(typeWriteQualDesc, "TYPE.WRITE");
        $DESCRIPTOR(typeRatioQualDesc, "TYPE.RATIO");
        $DESCRIPTOR(rangeStartQualDesc, "RANGE.START");
        $DESCRIPTOR(rangeSizeQualDesc, "RANGE.SIZE");
        $DESCRIPTOR(cacheQualDesc, "CACHE");
        $DESCRIPTOR(VIOCacheQualDesc, "VIOCACHE");
        $DESCRIPTOR(cachePercentQualDesc, "CACHE.PERCENT");
        $DESCRIPTOR(passQualDesc, "PASS");
        $DESCRIPTOR(EndIOQualDesc, "END.IO_COUNT");
        $DESCRIPTOR(EndSecondsQualDesc, "END.SECONDS");
        $DESCRIPTOR(EndVolumeQualDesc, "END.VOLUME");
        $DESCRIPTOR(IOSizeMinQualDesc, "IO_SIZE.MINIMUM");
        $DESCRIPTOR(IOSizeMaxQualDesc, "IO_SIZE.MAXIMUM");
        $DESCRIPTOR(readWriteRatioSizeQualDesc, "IO_SIZE.RATIO");
        $DESCRIPTOR(simultaneousIOQualDesc, "SIMULTANEOUS_IO");
        int i;
        char str[100];
        struct dsc$descriptor_s retdesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL};
        short retlen;
        int maxBlock = 0;
    
        DisksCount = 0;
        for (i = 0;
             $VMS_STATUS_SUCCESS(cli$get_value(&disksQualDesc, &retdesc, &retlen));
             ++i) {
            int classDisk, opcnt, max, free;
            int hoav;
            int status;
            unsigned short devlen;
            unsigned short volnamlen, medialen;
            int freebl, fp, ip, catchup, merge, member, fail, refcnt;
            int errcnt;
            char devnam[65];
            ILE3 gds[] = {{4, DVI$_DEVCLASS, &classDisk, 0},
                          {4, DVI$_SHDW_CATCHUP_COPYING, &catchup, 0},
                          {4, DVI$_SHDW_FAILED_MEMBER, &fail, 0},
                          {4, DVI$_SHDW_MEMBER, &member, 0},
                          {4, DVI$_SHDW_MERGE_COPYING, &merge, 0},
                          {4, DVI$_HOST_AVAIL, &hoav, 0},
                          {4, DVI$_REFCNT, &refcnt, 0},
                          {4, DVI$_FREEBLOCKS, &freebl, 0},
                          {4, DVI$_MAXBLOCK, &max, 0},
                          {64, DVI$_MEDIA_NAME, Medianam[i], &medialen},
                          {64, DVI$_FULLDEVNAM, FullDevnam[i], &devlen},
                          {4, DVI$_OPCNT, &opcnt, 0},
                          {4, DVI$_ERRCNT, &errcnt, 0},
                          {12, DVI$_VOLNAM, Volnam[i], &volnamlen},
                          {0, 0}};
            $DESCRIPTOR(devnam_d, devnam);
    
            ++DisksCount;
            if (DisksCount > K_DisksCard)
                exit(SS$_ABORT);
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            strcpy(devnam, str);
            devnam_d.dsc$w_length = strlen(devnam);
            memset(Medianam[i], ' ', sizeof(Medianam[0]) - 1);
            Medianam[i][sizeof(Medianam[0]) - 1] = '\0';
            memset(Volnam[i], ' ', sizeof(Volnam[0]) - 1);
            Volnam[i][sizeof(Volnam[0]) - 1] = '\0';
            memset(FullDevnam[i], ' ', sizeof(FullDevnam[0]) - 1);
            FullDevnam[i][sizeof(FullDevnam[0]) - 1] = '\0';
    
            status = sys$getdviw(0, 0, &devnam_d, gds, 0, 0, 0, 0);
            if (!$VMS_STATUS_SUCCESS(status))
                exit(status);
            if ((classDisk != DC$_DISK) || !hoav || member || fail || catchup ||
                merge || (refcnt == 0))
                exit(SS$_ABORT);
            if (max == 0)
                exit(SS$_ABORT);
            if ((max < maxBlock) || (maxBlock == 0))
                maxBlock = max;
            //    FullDevnam[i][14] = '\0';
            //    Volnam[i][9] = '\0';
            //    Medianam[i][6] = '\0';
        }
    
        if ($VMS_STATUS_SUCCESS(cli$present(&interactiveQualDesc))) {
            InteractiveQueries();
            return;
        }
        if ($VMS_STATUS_SUCCESS(cli$present(&sequentialQualDesc))) {
            Random = 0;
            if ($VMS_STATUS_SUCCESS(
                    cli$get_value(&seqIntervalQualDesc, &retdesc, &retlen))) {
                strncpy(str, retdesc.dsc$a_pointer, retlen);
                str[retlen] = '\0';
                sscanf(str, "%d", &Interval);
            } else
                Interval = -1;
        } else
            Random = 1;
        if ($VMS_STATUS_SUCCESS(cli$present(&typeReadQualDesc)) &&
            $VMS_STATUS_SUCCESS(cli$present(&typeWriteQualDesc))) {
            TypeTest = KReadWrite;
        } else if ($VMS_STATUS_SUCCESS(cli$present(&typeWriteQualDesc))) {
            TypeTest = KWriteOnly;
        } else { /* read only */
            TypeTest = KReadOnly;
        }
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&typeRatioQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &ReadPercent);
        } else
            ReadPercent = 80;
    
        cli$get_value(&passQualDesc, &retdesc, &retlen);
    
        strncpy(str, retdesc.dsc$a_pointer, retlen);
        str[retlen] = '\0';
    
        sscanf(str, "%d", &Pass);
    
        if ($VMS_STATUS_SUCCESS(cli$present(&rangeStartQualDesc))) {
            cli$get_value(&rangeStartQualDesc, &retdesc, &retlen);
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &StartingBlock);
        } else
            StartingBlock = 1;
        if ($VMS_STATUS_SUCCESS(cli$present(&rangeSizeQualDesc))) {
            cli$get_value(&rangeSizeQualDesc, &retdesc, &retlen);
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &EndingBlock);
        } else
            EndingBlock = StartingBlock + maxBlock / 3;
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&cachePercentQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &CacheHitPercent);
        } else if ($VMS_STATUS_SUCCESS(cli$present(&cacheQualDesc)))
            CacheHitPercent = 20;
        else
            CacheHitPercent = 0;
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&EndVolumeQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &TotSize);
            TypeStop = KSize;
        } else if ($VMS_STATUS_SUCCESS(
                       cli$get_value(&EndIOQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &TotIO);
            TypeStop = KIOCount;
        } else if ($VMS_STATUS_SUCCESS(
                       cli$get_value(&EndSecondsQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &PassDuration);
            TypeStop = KDuration;
        } else {
            PassDuration = 15;
            TypeStop = KDuration;
        }
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&IOSizeMinQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &MinIOSize);
        } else
            MinIOSize = 12;
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&IOSizeMaxQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%d", &MaxIOSize);
        } else
            MaxIOSize = MinIOSize;
    
        if ($VMS_STATUS_SUCCESS(
                cli$get_value(&readWriteRatioSizeQualDesc, &retdesc, &retlen))) {
            strncpy(str, retdesc.dsc$a_pointer, retlen);
            str[retlen] = '\0';
            sscanf(str, "%lf", &ReadWriteIOSizeRatio);
        } else
            ReadWriteIOSizeRatio = 3;
    
        cli$get_value(&simultaneousIOQualDesc, &retdesc, &retlen);
    
        strncpy(str, retdesc.dsc$a_pointer, retlen);
        str[retlen] = '\0';
    
        sscanf(str, "%d", &SimultaneousIO);
    
        if (SimultaneousIO * DisksCount > K_MaxSimQIO)
            exit(SS$_ABORT);
    
        if ($VMS_STATUS_SUCCESS(cli$present(&VIOCacheQualDesc)))
            VioModifier = 0;
        else
            VioModifier = IO$M_NOVCACHE;
    
        /*
         * Release the dynamic string we have been using.
         */
        if (retdesc.dsc$a_pointer != NULL)
            str$free1_dx(&retdesc);
    
    void IoAccess(unsigned short channel, FIBDEF *fib) {
        IOSB ioFich;
        long status;
        struct {
            unsigned long l;
            unsigned long adr;
        } fibDes;
    
        fibDes.l = sizeof(*fib);
        fibDes.adr = (unsigned long)fib;
        status = sys$qiow(0, channel, IO$_ACCESS | IO$M_ACCESS, &ioFich, 0, 0,
                          &fibDes, 0, 0, 0, 0, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nIoAccess Error\n");
            exit(status);
        }
    
    void IoDeAccess(unsigned short channel, FIBDEF *fib) {
        IOSB ioFich;
        long status;
        struct {
            unsigned long l;
            unsigned long adr;
        } fibDes;
    
        fibDes.l = sizeof(*fib);
        fibDes.adr = (unsigned long)fib;
        status = sys$qiow(0, channel, IO$_DEACCESS, &ioFich, 0, 0, &fibDes, 0, 0, 0,
                          0, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nIoDeAccess Error %X\n", status);
        }
    
    }
    
    static void DeleteFiles() {
    
        static done;
        int i;
    
        if (!done) {
            for (i = 0; i < DisksCount; ++i) {
                IoDeAccess(Channel[i], &(Fib[i]));
                delete (FileName[i]);
            }
            done = 1;
        } else {
            for (i = 0; i < DisksCount; ++i) {
                delete (FileName[i]);
            }
    
    static CreateFile(unsigned short *channel, FIBDEF *fib, char *fileName,
                      long maxVbn) {
        struct FAB fabFlog;
        struct RAB rabFlog;
        long status;
        struct FAB *fabP = 0;
        struct NAM *namP;
        long statRms;
        char temp[256];
        $DESCRIPTOR(tempDesc, temp);
        $DESCRIPTOR(fichierDesc, fileName);
    
        fichierDesc.dsc$w_length = strlen(fileName);
    
        fabFlog = cc$rms_fab;
        rabFlog = cc$rms_rab;
        fabFlog.fab$l_fna = fileName;
        fabFlog.fab$b_fns = strlen(fileName);
        fabFlog.fab$b_org = FAB$C_SEQ;
        fabFlog.fab$l_alq = maxVbn;
        fabFlog.fab$b_fac = FAB$M_GET | FAB$M_PUT;
        fabFlog.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET;
        fabFlog.fab$l_fop = FAB$M_CBT;
        fabFlog.fab$w_mrs = 512;
    
        status = sys$create(&fabFlog, 0, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nCreate Error\n");
            exit(status);
        }
        status = sys$close(&fabFlog, 0, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nClose Error\n");
            exit(status);
        }
    
        status = lib$find_file(&fichierDesc, &tempDesc, (unsigned int *)&fabP, 0, 0,
                               &statRms, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nFind File Error\n");
            exit(status);
        }
    
        status = sys$assign(&fichierDesc, channel, 0, 0, 0);
        if (!$VMS_STATUS_SUCCESS(status)) {
            fprintf(stderr, "\nAssign Error\n");
            exit(status);
        }
    
        namP = fabP->fab$l_nam;
    
    #if defined(__VAXC) || defined(VAXC)
    
        fib->fib$r_fid_overlay.fib$w_fid[0] = namP->nam$w_fid[0];
        fib->fib$r_fid_overlay.fib$w_fid[1] = namP->nam$w_fid[1];
        fib->fib$r_fid_overlay.fib$w_fid[2] = namP->nam$w_fid[2];
        fib->fib$r_acctl_overlay.fib$l_acctl = FIB$M_NOWRITE | FIB$M_WRITE;
    
        fib->fib$w_fid[0] = namP->nam$w_fid[0];
        fib->fib$w_fid[1] = namP->nam$w_fid[1];
        fib->fib$w_fid[2] = namP->nam$w_fid[2];
        fib->fib$l_acctl = FIB$M_NOWRITE | FIB$M_WRITE;
    
    #endif
    }
    
    static void DoIO(int i) {
    
        int status;
        int ioSize;
    
        switch (TypeStop) {
    
        case KDuration:
    
        case KIOCount:
        case KSize:
    
            if (TotIO == 0)
                EndPass = 1;
            else
                --TotIO;
            break;
    
            fprintf(stderr, "\nInvalid stop switch\n");
            exit(SS$_ABORT);
    
        if (!EndPass) {
            unsigned short channel = Channel[i];
            int writeIO;
    
            ++ActiveIOCount;
    
            if (TypeTest == KReadWrite) {
                writeIO = (100 * ((double)rand()) / 0x7fffffff) >= ReadPercent;
                ioSize = writeIO ? WriteIOSize : ReadIOSize;
                if (writeIO)
                    ++WriteIOCount;
                else
                    ++ReadIOCount;
            } else {
                ioSize = ReadIOSize;
                ++ReadIOCount;
            }
            if ((100 * ((double)rand()) / 0x7fffffff) >= CacheHitPercent)
                if (Random)
                    Address[i] = StartingBlock + (EndingBlock - StartingBlock) *
                                                     ((double)rand()) / 0x7fffffff;
                else {
                    Address[i] += (Interval == -1 ? ioSize : Interval);
                    if (Address[i] + ioSize > EndingBlock)
                        Address[i] = StartingBlock;
                }
            switch (TypeTest) {
            case KReadOnly:
                status =
                    sys$qio(0, channel, IO$_READLBLK, &Iosb[i], IOCompletionAST, i,
                            IOBuffer[i], 512 * ioSize, Address[i], 0, 0, 0);
                break;
            case KWriteOnly:
                status = sys$qio(0, channel, IO$_WRITEVBLK | VioModifier, &Iosb[i],
                                 IOCompletionAST, i, IOBuffer[i], 512 * ioSize,
                                 Address[i], 0, 0, 0);
                break;
            case KReadWrite:
                if (writeIO) {
                    ++WriteCount;
                    status = sys$qio(0, channel, IO$_WRITEVBLK | VioModifier,
                                     &Iosb[i], IOCompletionAST, i, IOBuffer[i],
                                     512 * ioSize, Address[i], 0, 0, 0);
                } else {
                    ++ReadCount;
                    status = sys$qio(0, channel, IO$_READVBLK | VioModifier,
                                     &Iosb[i], IOCompletionAST, i, IOBuffer[i],
                                     512 * ioSize, Address[i], 0, 0, 0);
                }
                break;
            default:
                fputs("Invalid test", stderr);
                exit(SS$_ABORT);
            }
            if (!$VMS_STATUS_SUCCESS(status))
                exit(status);
        } else if (ActiveIOCount == 0) {
            unsigned int pid = getpid();
            status = sys$wake(&pid, 0);
            if (!$VMS_STATUS_SUCCESS(status))
                exit(status);
    
        }
    }
    
    static void IOCompletionAST(int i) {
        --ActiveIOCount;
        DoIO(i);
    }
    
    #ifdef __cplusplus
    static void TimerAST(...) {
    #else
    static void TimerAST() {
    #endif
    
        FILE *fo;
    
        printf("%s %s, J.F. Pi?ronne, jf.pieronne@laposte.net\n", __DATE__,
               __TIME__);
    
        ProcessCommandLine();
    
        if (TypeTest != KReadOnly) {
            int i;
            atexit(DeleteFiles);
            for (i = 0; i < DisksCount; ++i) {
                strcpy(FileName[i], (char *)&FullDevnam[i]);
                strcat(FileName[i], "[000000]DISKPERF.TMP");
                printf("Temporary file used for write perfomance test :\n%s\n",
                       FileName[i]);
                CreateFile(&(Channel[i]), &(Fib[i]), FileName[i],
                           EndingBlock - StartingBlock + 1);
                IoAccess(Channel[i], &(Fib[i]));
            }
        } else {
            int i;
            for (i = 0; i < DisksCount; ++i) {
                char devnam[65];
                $DESCRIPTOR(devnamDesc, devnam);
                strcpy(devnam, FullDevnam[i]);
                devnamDesc.dsc$w_length = strlen(devnam);
                status = sys$assign(&devnamDesc, &(Channel[i]), 0, 0);
                if (!$VMS_STATUS_SUCCESS(status))
                    exit(status);
            }
        }
    
        for (i = 0; i < Pass; ++i) {
            //    float waitTime = 15;
            //    int waitFlags = LIB$K_NOWAKE;
    
            for (ReadIOSize = MinIOSize; ReadIOSize <= MaxIOSize; ++ReadIOSize) {
                Stat_s *sp = &(StatInfo[i][ReadIOSize - 1]);
                int sio;
                int tio;
                int ts;
                int j;
                GENERIC_64 deltaTime;
    
                ReadIOCount = WriteIOCount = 0;
    
                if (TypeTest == KReadWrite)
                    WriteIOSize = ReadIOSize / ReadWriteIOSizeRatio + 0.5;
                else
                    WriteIOSize = 1;
    
                if (WriteIOSize == 0)
                    WriteIOSize = 1;
    
                switch (TypeStop) {
                case KDuration:
                    deltaTime.gen64$l_longword[0] = -10000000 * PassDuration;
                    deltaTime.gen64$l_longword[1] = -1;
                    status = sys$setimr(0, &deltaTime, TimerAST, 0, 0);
                    if (!$VMS_STATUS_SUCCESS(status))
                        exit(status);
                    break;
                case KIOCount:
                    tio = TotIO;
                    break;
                case KSize:
                    TotIO = TotSize / ReadIOSize;
                    break;
                default:
                    fprintf(stderr, "\nInvalid stop switch\n");
                    exit(SS$_ABORT);
                }
    
                for (j = 0; j < DisksCount; ++j)
                    Address[j] = StartingBlock;
    
                lib$init_timer(NULL);
    
                status = sys$setast(0);
                if (!$VMS_STATUS_SUCCESS(status))
                    exit(status);
                for (j = 0; j < SimultaneousIO; ++j) {
                    int k;
                    for (k = 0; k < DisksCount; ++k)
                        DoIO(k);
                }
                status = sys$setast(1);
                if (!$VMS_STATUS_SUCCESS(status))
                    exit(status);
    
                while (!EndPass || ActiveIOCount) {
                    status = sys$hiber();
                    if (!$VMS_STATUS_SUCCESS(status))
                        exit(status);
                }
    
                j = 2;
                status = lib$stat_timer(&j, &(sp->_cpu));
                if (!$VMS_STATUS_SUCCESS(status))
                    exit(status);
    
                j = 1;
                status = lib$stat_timer(&j, (unsigned int *)sp->_elapsed);
                if (!$VMS_STATUS_SUCCESS(status))
                    exit(status);
    
                if (TypeStop == KIOCount)
                    TotIO = tio;
                StatInfo[i][ReadIOSize - 1]._IOCount = ReadIOCount + WriteIOCount;
                StatInfo[i][ReadIOSize - 1]._ReadIOCount = ReadIOCount;
                StatInfo[i][ReadIOSize - 1]._WriteIOCount = WriteIOCount;
                //      lib$wait(&waitTime, &waitFlags);
                sleep(5);
            }
    
        fo = fopen("diskperf.lis", "w");
        fprintf(fo, "%s and ",
                TypeTest == KWriteOnly  ? "Write"
                : TypeTest == KReadOnly ? "Read"
                                        : "Read-Write");
        fputs(Random ? "Random access test\n" : "Sequential access Test\n", fo);
        fprintf(fo, "Starting block %d, ending block %d, Simultaneous i/o %d\n",
                StartingBlock, EndingBlock, SimultaneousIO);
        fprintf(fo, "Giving cache hit percent : %d\n", CacheHitPercent);
        if (VioModifier || TypeTest == KReadOnly)
            fprintf(fo, "Virtual IO cache not active\n");
        else
            fprintf(fo, "Virtual IO cache active\n");
    
        if (TypeTest == KReadWrite)
    
            fprintf(
                fo,
                "Effective read percent : %4.1lf\nRead Size / Write Size : %lf\n",
                100 * ((double)ReadCount) / (ReadCount + WriteCount),
                ReadWriteIOSizeRatio);
        fputs("device name    label    type\n", fo);
        fputs("------------  --------  ----\n", fo);
        for (i = 0; i < DisksCount; ++i)
            fprintf(fo, "%-13s %-9s %-6s\n", &(FullDevnam[i][1]), Volnam[i],
                    Medianam[i]);
        for (ReadIOSize = MinIOSize; ReadIOSize <= MaxIOSize; ++ReadIOSize) {
            if (TypeTest == KReadWrite)
                WriteIOSize = ReadIOSize / ReadWriteIOSizeRatio + 0.5;
            else
                WriteIOSize = 1;
            if (WriteIOSize == 0)
                WriteIOSize = 1;
    
            fprintf(fo, "\n!%3d !", ReadIOSize);
            for (i = 0; i < Pass; ++i) {
                Stat_s *sp = &(StatInfo[i][ReadIOSize - 1]);
                fprintf(
                    fo, " %5d IOs %2d ms %4d IO/s %6d KB/s!", sp->_IOCount,
                    -(int)((double)sp->_elapsed[0] / 10000.0 / sp->_IOCount *
                           SimultaneousIO * DisksCount),
                    -(int)((double)(sp->_IOCount) * 10000000.0 / sp->_elapsed[0]),
                    -(int)((double)(sp->_ReadIOCount) * ReadIOSize * 10000000.0 /
                           sp->_elapsed[0] / 2) -
                        (int)((double)(sp->_WriteIOCount) * WriteIOSize *
                              10000000.0 / sp->_elapsed[0] / 2));
            }
    
        fclose(fo);
        fo = fopen("diskperf.dat", "w");
        fprintf(fo, "Size\tIOs\tService\tIO/s\tKB/s");
        for (ReadIOSize = MinIOSize; ReadIOSize <= MaxIOSize; ++ReadIOSize) {
            double ioc = 0, ser = 0, ios = 0, kbs = 0;
            for (i = 0; i < Pass; ++i) {
                Stat_s *sp = &(StatInfo[i][ReadIOSize - 1]);
                ioc += sp->_IOCount;
                ser += -(double)sp->_elapsed[0] / 10000.0 / sp->_IOCount *
                       SimultaneousIO * DisksCount;
                ios +=
                    -(int)((double)(sp->_IOCount) * 10000000.0 / sp->_elapsed[0]);
                kbs += -(int)((double)(sp->_ReadIOCount) * ReadIOSize * 10000000.0 /
                              sp->_elapsed[0] / 2) -
                       (int)((double)(sp->_WriteIOCount) * WriteIOSize *
                             10000000.0 / sp->_elapsed[0] / 2);
            }
            ioc /= Pass;
            ser /= Pass;
            ios /= Pass;
            kbs /= Pass;
            fprintf(fo, "\n%3d\t%d\t%d\t%d\t%d", ReadIOSize, (int)ioc, (int)ser,
                    (int)ios, (int)kbs);
            /*
                for(i = 0; i < Pass; ++i) {
                  Stat_s* sp = &(StatInfo[i][ReadIOSize - 1]);
                  fprintf(fo, "\t%5d\t%2d\t%4d\t%4d", sp->_IOCount,
                            - (int)((double)sp->_elapsed[0]
                                            / 10000.0
                                            / sp->_IOCount * SimultaneousIO *
               DisksCount),
                            - (int)((double)(sp->_IOCount) * 10000000.0 /
               sp->_elapsed[0]),
                            - (int)((double)(sp->_ReadIOCount) *
                                10000000.0 / sp->_elapsed[0] * ReadIOSize / 2)
                              - (int)((double)(sp->_WriteIOCount) *
                                  10000000.0 / sp->_elapsed[0] * WriteIOSize / 2));
                }
            */