home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pctech / hlsrc / hldisk.c < prev    next >
C/C++ Source or Header  |  1988-09-09  |  12KB  |  417 lines

  1. /*+
  2.     Name:       HLDISK.C
  3.     Author:     Kent J. Quirk
  4.         (c) Copyright 1988 Ziff Communications Co.
  5.     Abstract:    This program performs a disk benchmark by writing a set of
  6.         records (generated by a pseudo-random number generator) to
  7.         disk in sequential order, then reading them sequentially and
  8.         building an index.  Next, it reads the file in index order,
  9.         building a "report" to disk as it reads it.  Finally, it
  10.         rewrites the file in index order, then repeats the report
  11.         generator test. It takes one parameter, the long number of
  12.         records to use. It uses only standard C file functions to
  13.         perform I/O.
  14.     History:    kjq - Mar 88 - Original Version
  15.         kjq - May 88 - Add environment var search for drive prefix.
  16.         kjq - Jun 88 - Add protection against Disk Full errors.
  17.         kjq - Sep 88 - Default to drive C rather than default drive.
  18.         kjq - Sep 88 - Version 1.00
  19. -*/
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <io.h>
  25. #include <ctype.h>
  26.  
  27. #include "hl.h"
  28. #include "hlstate.h"
  29. #include "hltimes.h"
  30.  
  31. #define RANDOM_INT(max) (rand()%(max))
  32. #define RANDOM_LETTER ('A'+RANDOM_INT(26))
  33.  
  34. #define INDEXFILE "$DSKDAT$.NDX"
  35. #define DATAFILE "$DSKDAT$.DAT"
  36. #define REPORTFILE "$DSKDAT$.RPT"
  37. #define SAVEDATA "$DSKDAT$.DAS"
  38. #define SAVEINDEX "$DSKDAT$.NDS"
  39.  
  40. #define TOTAL_TIMER 0
  41. #define ONE_TASK 1
  42.  
  43. DATAREC dr = {0, "", "321 Main St.", "", "Metropolis", "", "", 0};
  44.  
  45. TIME_REC timerecs[] = {
  46.     { 0L, "Total: Disk Performance"},
  47.     { 0L, "Data File Creation"},
  48.     { 0L, "Index File Creation"},
  49.     { 0L, "Report Generation"},
  50.     { 0L, "Data Reorganization"},
  51.     { 0L, "Report Gen. on Reordered Data"},
  52.     {-1L, "HLDISK"},
  53. };
  54.  
  55. /**** m a k e n a m e ****
  56.     Abstract:    Given a base filename, this reads the environment variable
  57.         to find a drive/directory combination in which to 
  58.         place the actual file.
  59.     Parameters: A filename without drive or directory specifiers
  60.     Returns:    A fully-specified filename, including drive and directory.
  61. ****************************/
  62. char *makename(name)
  63. char *name;
  64. {
  65.     static char fname[2][64];
  66.     static int next=0;
  67.     char *var;
  68.  
  69.     if ((var = getenv("HLDISK")) == NULL)
  70.     var = "C:";            /* default to drive C: */
  71.  
  72.     next = 1-next;
  73.     strcpy(fname[next], var);        /* else use prefix specified */
  74.     if (!ispunct(fname[next][strlen(fname[next])-1]))
  75.     strcat(fname[next],"\\");   /* add backslash if needed */
  76.     strcat(fname[next], name);        /* and the filename */
  77.     return(fname[next]);
  78. }
  79.  
  80. /**** m u s t o p e n ****
  81.     Abstract:    Given a filename and an attribute, this opens it,
  82.         or dies trying.
  83.     Parameters: The filename and attribute (just like fopen())
  84.     Returns:    The file pointer returned by fopen, if fopen succeeded,
  85.         or never returns if fopen failed.
  86. ****************************/
  87. FILE *mustopen(name, attr)
  88. char *name;
  89. char *attr;
  90. {
  91.     FILE *f;
  92.  
  93.     if ((f = fopen(name=makename(name), attr)) == NULL)
  94.     {
  95.     printf("Unable to open '%s' for '%s'.\n", name, attr);
  96.     exit(1);
  97.     }
  98.     return(f);
  99. }
  100.  
  101. /**** b u i l d _ i n d e x ****
  102.     Abstract:    Given a datafile, this builds the index file for it,
  103.         then calls the disk-based shell sort to sort the index
  104.         file.
  105.     Parameters: FILE *datafile -- a data file containing DATAREC records.
  106.         long nrecs -- the number of records in the file.
  107.     Returns:    Nothing
  108. ****************************/
  109. void build_index(datafile, nrecs)
  110. FILE *datafile;
  111. long nrecs;
  112. {
  113.     FILE *indexfile;
  114.     long i;
  115.     INDEXREC ir;
  116.     char buf[10];
  117.  
  118.     indexfile = mustopen(INDEXFILE, "w+b");
  119.     for (i=0; !feof(datafile); i++)
  120.     {
  121.     /* ir.fileloc = ftell(datafile); */
  122.     ir.fileloc = i * sizeof(DATAREC);
  123.     if (fread(&dr, sizeof(DATAREC), 1, datafile) != 1)
  124.         break;
  125.     memmove(ir.zip, dr.zip, sizeof(ir.zip));
  126.     memmove(ir.name, dr.name, sizeof(ir.name));
  127.     sprintf(buf, "%04X", dr.index);
  128.     memmove(ir.hexindex, buf, sizeof(ir.hexindex));
  129.     if (fwrite(&ir, sizeof(INDEXREC), 1, indexfile) != 1)
  130.     {    
  131.         perror("Failed to write to index file");
  132.         exit(1);
  133.     }
  134.     }
  135.  
  136.     if (i != nrecs)
  137.     printf("Oops!  Records indexed (%ld) != records written (%ld).\n",
  138.     i, nrecs);
  139.     shellsort(indexfile, nrecs, sizeof(INDEXREC), strcmp);
  140.     fclose(indexfile);
  141. }
  142.  
  143. /**** r e p o r t ****
  144.     Abstract:    Generates a report on the data by reading it in index order.
  145.     Parameters: FILE *datafile, *indexfile -- the data and an index to it
  146.         long nrecs -- the number of records in the files
  147.         FILE *reportfile -- the text file on which to write the report.
  148.     Returns:    nothing
  149. ****************************/
  150. void report(datafile, indexfile, nrecs, reportfile)
  151. FILE *datafile;
  152. FILE *indexfile;
  153. long nrecs;
  154. FILE *reportfile;
  155. {
  156.     INDEXREC ir;
  157.     DATAREC dr;
  158.     long this_qty, total_qty;
  159.     char last_state[2];
  160.     char last_zip[2];
  161.     int first = 1;
  162.  
  163.     fprintf(reportfile, "Zip State  Count\n");
  164.     fprintf(reportfile, "--- ----- ------\n");
  165.  
  166.     fseek(indexfile, 0L, SEEK_SET);
  167.     while (!feof(indexfile))
  168.     {
  169.     fread(&ir, sizeof(INDEXREC), 1, indexfile);
  170.     fseek(datafile, ir.fileloc, SEEK_SET);
  171.     fread(&dr, sizeof(DATAREC), 1, datafile);
  172.     if (first)
  173.     {
  174.         memmove(last_state, dr.state, sizeof(last_state));
  175.         memmove(last_zip, dr.zip, sizeof(last_zip));
  176.         first = 0;
  177.     }
  178.     if (memcmp(last_state, dr.state, sizeof(dr.state)) != 0)
  179.     {
  180.         fprintf(reportfile,"%2.2s-   %2.2s %6ld\n", last_zip, last_state, this_qty);
  181.         total_qty += this_qty;
  182.         this_qty = 0;
  183.         memmove(last_state, dr.state, sizeof(last_state));
  184.         memmove(last_zip, dr.zip, sizeof(last_zip));
  185.     }
  186.     else
  187.         this_qty += dr.qty;
  188.     }
  189.     fprintf(reportfile, "         ======\n");
  190.     fprintf(reportfile, "  Total: %6ld\n", total_qty);
  191. }
  192.  
  193. /**** r e o r g ****
  194.     Abstract:    Given the name of a data file and its index, this rewrites
  195.         the data file in index order.
  196.     Parameters: char *name, *index -- the filenames
  197.     Returns:    Nothing, but creates a new data file and gives it the same name
  198.         The original is deleted.
  199.     Comments:
  200. ****************************/
  201. void reorg(name, index)
  202. char *name;
  203. char *index;
  204. {
  205.     FILE *datafile, *newdata, *indexf, *newindex;
  206.     INDEXREC ir;
  207.     DATAREC dr;
  208.  
  209.  
  210.     if (rename(makename(name), makename(SAVEDATA)) != 0)
  211.     printf("Unable to rename %s to %s.\n",
  212.         makename(name), makename(SAVEDATA));
  213.     if (rename(makename(index), makename(SAVEINDEX)) != 0)
  214.     printf("Unable to rename %s to %s.\n",
  215.         makename(index), makename(SAVEINDEX));
  216.  
  217.     datafile = mustopen(SAVEDATA, "rb");
  218.     indexf = mustopen(SAVEINDEX, "rb");
  219.     newdata = mustopen(name, "wb");
  220.     newindex = mustopen(index, "wb");
  221.  
  222.     fseek(indexf, 0L, SEEK_SET);
  223.     while (!feof(indexf))
  224.     {
  225.     fread(&ir, sizeof(INDEXREC), 1, indexf);
  226.     fseek(datafile, ir.fileloc, SEEK_SET);
  227.     fread(&dr, sizeof(DATAREC), 1, datafile);
  228.  
  229.     ir.fileloc = ftell(newdata);
  230.     fwrite(&dr, sizeof(DATAREC), 1, newdata);
  231.     fwrite(&ir, sizeof(INDEXREC), 1, newindex);
  232.     }
  233.     fclose(newdata);
  234.     fclose(newindex);
  235.     fclose(datafile);
  236.     fclose(indexf);
  237.  
  238.     remove(makename(SAVEDATA));      /* delete old files */
  239.     remove(makename(SAVEINDEX));
  240. }
  241.  
  242. /**** d i s k t e s t ****
  243.     Abstract:    A disk performance test
  244.     Parameters: long nrecs -- the number of records to use
  245.     Returns:    nothing
  246. ****************************/
  247. void disktest(nrecs)
  248. long nrecs;
  249. {
  250.     long i;
  251.     int z;
  252.     FILE *datafile, *indexfile, *reportfile, *newdata;
  253.  
  254.     printf("HLDISK - Disk performance benchmark.\n");
  255.     start_timer(TOTAL_TIMER);       /* timer for the whole process */
  256.     start_timer(ONE_TASK);          /* single task timer */
  257.  
  258.     printf("Generate data...");
  259.     datafile = mustopen(DATAFILE, "wb");
  260.  
  261.     for (i=0; i<nrecs; i++)         /* once for each record */
  262.     {
  263.     dr.index = (int)i;                  /* ok to overflow */
  264.     dr.name[0] = (char)RANDOM_LETTER;   /* get a random letter */
  265.     dr.name[1] = 0;                     /* and null-term it */
  266.     z = RANDOM_INT(sizeof(states)/sizeof(states[0]));
  267.     dr.state[0] = states[z].state[0];   /* pick real state */
  268.     dr.state[1] = states[z].state[1];
  269.     sprintf(dr.zip, "%02d%03d", states[z].leadzip,
  270.     RANDOM_INT(1000));
  271.     dr.qty = RANDOM_INT(100);   /* store a number */
  272.     if (fwrite(&dr, sizeof(DATAREC), 1, datafile) != 1)
  273.     {
  274.         perror("Failure writing data file");
  275.         exit(1);
  276.     }
  277.     }
  278.  
  279.  
  280.     fclose(datafile);
  281.     stop_timer();
  282.     timerecs[1].ticks = get_timer(ONE_TASK);
  283.     printf("Build index...");
  284.  
  285.     start_timer(ONE_TASK);
  286.     datafile = mustopen(DATAFILE, "rb");
  287.     build_index(datafile, nrecs);
  288.     fclose(datafile);
  289.     stop_timer();
  290.     timerecs[2].ticks = get_timer(ONE_TASK);
  291.     printf("1st report...");
  292.  
  293.     start_timer(ONE_TASK);
  294.     datafile = mustopen(DATAFILE, "rb");
  295.     indexfile = mustopen(INDEXFILE, "rb");
  296.     reportfile = mustopen(REPORTFILE, "w");
  297.     report(datafile, indexfile, nrecs, reportfile);
  298.     fclose(reportfile);
  299.     fclose(indexfile);
  300.     fclose(datafile);
  301.     stop_timer();
  302.     timerecs[3].ticks = get_timer(ONE_TASK);
  303.     printf("Reorganize database...");
  304.  
  305.     start_timer(ONE_TASK);
  306.     reorg(DATAFILE, INDEXFILE);
  307.     stop_timer();
  308.     timerecs[4].ticks = get_timer(ONE_TASK);
  309.     printf("2nd report...");
  310.  
  311.     remove(REPORTFILE);
  312.     start_timer(ONE_TASK);
  313.     datafile = mustopen(DATAFILE, "rb");
  314.     indexfile = mustopen(INDEXFILE, "rb");
  315.     reportfile = mustopen(REPORTFILE, "w");
  316.     report(datafile, indexfile, nrecs, reportfile);
  317.     fclose(reportfile);
  318.     fclose(indexfile);
  319.     fclose(datafile);
  320.     stop_timer();
  321.     timerecs[5].ticks = get_timer(ONE_TASK);
  322.     timerecs[0].ticks = get_timer(TOTAL_TIMER);
  323.     printf("Done.\n");
  324. }
  325.  
  326. /**** u s a g e ****
  327.     Abstract:    Prints usage info and exits
  328.     Parameters: None
  329.     Returns:    Never
  330. ****************************/
  331. void usage()
  332. {
  333.     printf("This program is a disk performance tester.\n");
  334.     printf("If you run it with no arguments, it will\n");
  335.     printf("generate 500 records (about 100K) in the current directory.\n");
  336.     printf("Usage: HLDISK [-?] [-nRECS] [-s]\n");
  337.     printf("    where RECS is the number of records, and\n");
  338.     printf("    -s tells HLDISK not to delete the data files.\n");
  339.     printf("    -? prints this message.\n");
  340.     exit(1);
  341. }
  342.  
  343. main(argc, argv)
  344. int argc;
  345. char *argv[];
  346. {
  347.     long num_recs = 500L;
  348.     int no_del = 0;
  349.     int i;
  350.     int program = -1;
  351.     int batch = 0;
  352.     int bench = 0;
  353.     char *filename = NULL;
  354.  
  355.     for (i=1; i<argc; i++)
  356.     {
  357.     if (argv[i][0] != '-')
  358.         usage();
  359.     else
  360.     {
  361.         switch(tolower(argv[i][1])) {
  362.         case 'n':
  363.         num_recs = atol(argv[i]+2);
  364.         break;
  365.         case 's':
  366.         no_del = 1;
  367.         break;
  368.         case 'a':
  369.         batch = 1;
  370.         break;
  371.         case 'b':
  372.         bench = 1;
  373.         break;
  374.         case 'f':
  375.         filename = argv[i]+2;
  376.         break;
  377.         case 'p':
  378.         program = atoi(argv[i]+2);
  379.         break;
  380.         default:
  381.         printf("Invalid argument '%s'.\n", argv[i]);
  382.         /* break left out */
  383.         case '?':
  384.         usage();
  385.         break;
  386.         }
  387.     }
  388.     }
  389.  
  390.     disktest(num_recs);
  391.  
  392.     if ((filename != NULL) && (program != -1))
  393.     {
  394.     opentime(filename);
  395.     for (i=0; ; i++)
  396.     {
  397.         savetime(program, i, &timerecs[i]);
  398.         if (timerecs[i].ticks == -1)
  399.         break;
  400.     }
  401.     closetime();
  402.     }
  403.  
  404.     if (!bench)
  405.     for (i=0; timerecs[i].ticks != -1; i++)
  406.         printf("%5s:  %s\n", time_secs(timerecs[i].ticks),
  407.         timerecs[i].desc);
  408.  
  409.     if (no_del == 0)
  410.     {
  411.     remove(makename(DATAFILE));
  412.     remove(makename(INDEXFILE));
  413.     remove(makename(REPORTFILE));
  414.     }
  415.     return(0);
  416. }
  417.