home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pctech
/
hlsrc.arc
/
HLDISK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-09-09
|
12KB
|
417 lines
/*+
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);
}