home *** CD-ROM | disk | FTP | other *** search
- /*+
- Name: HLDISK.C
- Author: Kent J. Quirk
- (c) Copyright 1988 Ziff Communications Co.
- Abstract: This program performs a disk benchmark by writing a set of
- records (generated by a pseudo-random number generator) to
- disk in sequential order, then reading them sequentially and
- building an index. Next, it reads the file in index order,
- building a "report" to disk as it reads it. Finally, it
- rewrites the file in index order, then repeats the report
- generator test. It takes one parameter, the long number of
- records to use. It uses only standard C file functions to
- perform I/O.
- History: kjq - Mar 88 - Original Version
- kjq - May 88 - Add environment var search for drive prefix.
- kjq - Jun 88 - Add protection against Disk Full errors.
- kjq - Sep 88 - Default to drive C rather than default drive.
- kjq - Sep 88 - Version 1.00
- -*/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <io.h>
- #include <ctype.h>
-
- #include "hl.h"
- #include "hlstate.h"
- #include "hltimes.h"
-
- #define RANDOM_INT(max) (rand()%(max))
- #define RANDOM_LETTER ('A'+RANDOM_INT(26))
-
- #define INDEXFILE "$DSKDAT$.NDX"
- #define DATAFILE "$DSKDAT$.DAT"
- #define REPORTFILE "$DSKDAT$.RPT"
- #define SAVEDATA "$DSKDAT$.DAS"
- #define SAVEINDEX "$DSKDAT$.NDS"
-
- #define TOTAL_TIMER 0
- #define ONE_TASK 1
-
- DATAREC dr = {0, "", "321 Main St.", "", "Metropolis", "", "", 0};
-
- TIME_REC timerecs[] = {
- { 0L, "Total: Disk Performance"},
- { 0L, "Data File Creation"},
- { 0L, "Index File Creation"},
- { 0L, "Report Generation"},
- { 0L, "Data Reorganization"},
- { 0L, "Report Gen. on Reordered Data"},
- {-1L, "HLDISK"},
- };
-
- /**** m a k e n a m e ****
- Abstract: Given a base filename, this reads the environment variable
- to find a drive/directory combination in which to
- place the actual file.
- Parameters: A filename without drive or directory specifiers
- Returns: A fully-specified filename, including drive and directory.
- ****************************/
- char *makename(name)
- char *name;
- {
- static char fname[2][64];
- static int next=0;
- char *var;
-
- if ((var = getenv("HLDISK")) == NULL)
- var = "C:"; /* default to drive C: */
-
- next = 1-next;
- strcpy(fname[next], var); /* else use prefix specified */
- if (!ispunct(fname[next][strlen(fname[next])-1]))
- strcat(fname[next],"\\"); /* add backslash if needed */
- strcat(fname[next], name); /* and the filename */
- return(fname[next]);
- }
-
- /**** m u s t o p e n ****
- Abstract: Given a filename and an attribute, this opens it,
- or dies trying.
- Parameters: The filename and attribute (just like fopen())
- Returns: The file pointer returned by fopen, if fopen succeeded,
- or never returns if fopen failed.
- ****************************/
- FILE *mustopen(name, attr)
- char *name;
- char *attr;
- {
- FILE *f;
-
- if ((f = fopen(name=makename(name), attr)) == NULL)
- {
- printf("Unable to open '%s' for '%s'.\n", name, attr);
- exit(1);
- }
- return(f);
- }
-
- /**** b u i l d _ i n d e x ****
- Abstract: Given a datafile, this builds the index file for it,
- then calls the disk-based shell sort to sort the index
- file.
- Parameters: FILE *datafile -- a data file containing DATAREC records.
- long nrecs -- the number of records in the file.
- Returns: Nothing
- ****************************/
- void build_index(datafile, nrecs)
- FILE *datafile;
- long nrecs;
- {
- FILE *indexfile;
- long i;
- INDEXREC ir;
- char buf[10];
-
- indexfile = mustopen(INDEXFILE, "w+b");
- for (i=0; !feof(datafile); i++)
- {
- /* ir.fileloc = ftell(datafile); */
- ir.fileloc = i * sizeof(DATAREC);
- if (fread(&dr, sizeof(DATAREC), 1, datafile) != 1)
- break;
- memmove(ir.zip, dr.zip, sizeof(ir.zip));
- memmove(ir.name, dr.name, sizeof(ir.name));
- sprintf(buf, "%04X", dr.index);
- memmove(ir.hexindex, buf, sizeof(ir.hexindex));
- if (fwrite(&ir, sizeof(INDEXREC), 1, indexfile) != 1)
- {
- perror("Failed to write to index file");
- exit(1);
- }
- }
-
- if (i != nrecs)
- printf("Oops! Records indexed (%ld) != records written (%ld).\n",
- i, nrecs);
- shellsort(indexfile, nrecs, sizeof(INDEXREC), strcmp);
- fclose(indexfile);
- }
-
- /**** r e p o r t ****
- Abstract: Generates a report on the data by reading it in index order.
- Parameters: FILE *datafile, *indexfile -- the data and an index to it
- long nrecs -- the number of records in the files
- FILE *reportfile -- the text file on which to write the report.
- Returns: nothing
- ****************************/
- void report(datafile, indexfile, nrecs, reportfile)
- FILE *datafile;
- FILE *indexfile;
- long nrecs;
- FILE *reportfile;
- {
- INDEXREC ir;
- DATAREC dr;
- long this_qty, total_qty;
- char last_state[2];
- char last_zip[2];
- int first = 1;
-
- fprintf(reportfile, "Zip State Count\n");
- fprintf(reportfile, "--- ----- ------\n");
-
- fseek(indexfile, 0L, SEEK_SET);
- while (!feof(indexfile))
- {
- fread(&ir, sizeof(INDEXREC), 1, indexfile);
- fseek(datafile, ir.fileloc, SEEK_SET);
- fread(&dr, sizeof(DATAREC), 1, datafile);
- if (first)
- {
- memmove(last_state, dr.state, sizeof(last_state));
- memmove(last_zip, dr.zip, sizeof(last_zip));
- first = 0;
- }
- if (memcmp(last_state, dr.state, sizeof(dr.state)) != 0)
- {
- fprintf(reportfile,"%2.2s- %2.2s %6ld\n", last_zip, last_state, this_qty);
- total_qty += this_qty;
- this_qty = 0;
- memmove(last_state, dr.state, sizeof(last_state));
- memmove(last_zip, dr.zip, sizeof(last_zip));
- }
- else
- this_qty += dr.qty;
- }
- fprintf(reportfile, " ======\n");
- fprintf(reportfile, " Total: %6ld\n", total_qty);
- }
-
- /**** r e o r g ****
- Abstract: Given the name of a data file and its index, this rewrites
- the data file in index order.
- Parameters: char *name, *index -- the filenames
- Returns: Nothing, but creates a new data file and gives it the same name
- The original is deleted.
- Comments:
- ****************************/
- void reorg(name, index)
- char *name;
- char *index;
- {
- FILE *datafile, *newdata, *indexf, *newindex;
- INDEXREC ir;
- DATAREC dr;
-
-
- if (rename(makename(name), makename(SAVEDATA)) != 0)
- printf("Unable to rename %s to %s.\n",
- makename(name), makename(SAVEDATA));
- if (rename(makename(index), makename(SAVEINDEX)) != 0)
- printf("Unable to rename %s to %s.\n",
- makename(index), makename(SAVEINDEX));
-
- datafile = mustopen(SAVEDATA, "rb");
- indexf = mustopen(SAVEINDEX, "rb");
- newdata = mustopen(name, "wb");
- newindex = mustopen(index, "wb");
-
- fseek(indexf, 0L, SEEK_SET);
- while (!feof(indexf))
- {
- fread(&ir, sizeof(INDEXREC), 1, indexf);
- fseek(datafile, ir.fileloc, SEEK_SET);
- fread(&dr, sizeof(DATAREC), 1, datafile);
-
- ir.fileloc = ftell(newdata);
- fwrite(&dr, sizeof(DATAREC), 1, newdata);
- fwrite(&ir, sizeof(INDEXREC), 1, newindex);
- }
- fclose(newdata);
- fclose(newindex);
- fclose(datafile);
- fclose(indexf);
-
- remove(makename(SAVEDATA)); /* delete old files */
- remove(makename(SAVEINDEX));
- }
-
- /**** d i s k t e s t ****
- Abstract: A disk performance test
- Parameters: long nrecs -- the number of records to use
- Returns: nothing
- ****************************/
- void disktest(nrecs)
- long nrecs;
- {
- long i;
- int z;
- FILE *datafile, *indexfile, *reportfile, *newdata;
-
- printf("HLDISK - Disk performance benchmark.\n");
- start_timer(TOTAL_TIMER); /* timer for the whole process */
- start_timer(ONE_TASK); /* single task timer */
-
- printf("Generate data...");
- datafile = mustopen(DATAFILE, "wb");
-
- for (i=0; i<nrecs; i++) /* once for each record */
- {
- dr.index = (int)i; /* ok to overflow */
- dr.name[0] = (char)RANDOM_LETTER; /* get a random letter */
- dr.name[1] = 0; /* and null-term it */
- z = RANDOM_INT(sizeof(states)/sizeof(states[0]));
- dr.state[0] = states[z].state[0]; /* pick real state */
- dr.state[1] = states[z].state[1];
- sprintf(dr.zip, "%02d%03d", states[z].leadzip,
- RANDOM_INT(1000));
- dr.qty = RANDOM_INT(100); /* store a number */
- if (fwrite(&dr, sizeof(DATAREC), 1, datafile) != 1)
- {
- perror("Failure writing data file");
- exit(1);
- }
- }
-
-
- fclose(datafile);
- stop_timer();
- timerecs[1].ticks = get_timer(ONE_TASK);
- printf("Build index...");
-
- start_timer(ONE_TASK);
- datafile = mustopen(DATAFILE, "rb");
- build_index(datafile, nrecs);
- fclose(datafile);
- stop_timer();
- timerecs[2].ticks = get_timer(ONE_TASK);
- printf("1st report...");
-
- start_timer(ONE_TASK);
- datafile = mustopen(DATAFILE, "rb");
- indexfile = mustopen(INDEXFILE, "rb");
- reportfile = mustopen(REPORTFILE, "w");
- report(datafile, indexfile, nrecs, reportfile);
- fclose(reportfile);
- fclose(indexfile);
- fclose(datafile);
- stop_timer();
- timerecs[3].ticks = get_timer(ONE_TASK);
- printf("Reorganize database...");
-
- start_timer(ONE_TASK);
- reorg(DATAFILE, INDEXFILE);
- stop_timer();
- timerecs[4].ticks = get_timer(ONE_TASK);
- printf("2nd report...");
-
- remove(REPORTFILE);
- start_timer(ONE_TASK);
- datafile = mustopen(DATAFILE, "rb");
- indexfile = mustopen(INDEXFILE, "rb");
- reportfile = mustopen(REPORTFILE, "w");
- report(datafile, indexfile, nrecs, reportfile);
- fclose(reportfile);
- fclose(indexfile);
- fclose(datafile);
- stop_timer();
- timerecs[5].ticks = get_timer(ONE_TASK);
- timerecs[0].ticks = get_timer(TOTAL_TIMER);
- printf("Done.\n");
- }
-
- /**** u s a g e ****
- Abstract: Prints usage info and exits
- Parameters: None
- Returns: Never
- ****************************/
- void usage()
- {
- printf("This program is a disk performance tester.\n");
- printf("If you run it with no arguments, it will\n");
- printf("generate 500 records (about 100K) in the current directory.\n");
- printf("Usage: HLDISK [-?] [-nRECS] [-s]\n");
- printf(" where RECS is the number of records, and\n");
- printf(" -s tells HLDISK not to delete the data files.\n");
- printf(" -? prints this message.\n");
- exit(1);
- }
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- long num_recs = 500L;
- int no_del = 0;
- int i;
- int program = -1;
- int batch = 0;
- int bench = 0;
- char *filename = NULL;
-
- for (i=1; i<argc; i++)
- {
- if (argv[i][0] != '-')
- usage();
- else
- {
- switch(tolower(argv[i][1])) {
- case 'n':
- num_recs = atol(argv[i]+2);
- break;
- case 's':
- no_del = 1;
- break;
- case 'a':
- batch = 1;
- break;
- case 'b':
- bench = 1;
- break;
- case 'f':
- filename = argv[i]+2;
- break;
- case 'p':
- program = atoi(argv[i]+2);
- break;
- default:
- printf("Invalid argument '%s'.\n", argv[i]);
- /* break left out */
- case '?':
- usage();
- break;
- }
- }
- }
-
- disktest(num_recs);
-
- if ((filename != NULL) && (program != -1))
- {
- opentime(filename);
- for (i=0; ; i++)
- {
- savetime(program, i, &timerecs[i]);
- if (timerecs[i].ticks == -1)
- break;
- }
- closetime();
- }
-
- if (!bench)
- for (i=0; timerecs[i].ticks != -1; i++)
- printf("%5s: %s\n", time_secs(timerecs[i].ticks),
- timerecs[i].desc);
-
- if (no_del == 0)
- {
- remove(makename(DATAFILE));
- remove(makename(INDEXFILE));
- remove(makename(REPORTFILE));
- }
- return(0);
- }
-