#include "defs.h"
#define COUNT 1000
#define FCOUNT 1
typedef struct ForkMap {
int id;
int type;
int count;
struct timeval tstart;
struct timeval tend;
} ForkMap;
void DoIt(int Action, int count, ForkMap *smap);
ForkMap *StatsMap;
int AddForks = 0;
int AddCount = COUNT;
int LookupForks = 0;
int LookupCount = COUNT;
char StatsPath[PATH_MAX];
void
Usage(void)
{
fprintf(stderr, "A simple history performance tester\n\n");
fprintf(stderr, "Usage: dhisbench [-ac n] [-af n] [-F] [-f historyfile] [-l]\n");
fprintf(stderr, " [-lc n] [-lf n] [-m map_file]\n");
fprintf(stderr, " where:\n");
fprintf(stderr, "\t-ac\tspecify number if history additions (default:%d)\n",
AddCount);
fprintf(stderr, "\t-af\tspecify number if addition forks (default: %d)\n",
AddForks);
fprintf(stderr, "\t-F\tfast mode - no locking or duplicate checking for add\n");
fprintf(stderr, "\t-Fl\tdon't perform locking on history adds\n");
fprintf(stderr, "\t-Fs\tdon't check for duplicates on history adds\n");
fprintf(stderr, "\t-f FILE\tuse FILE has the history file (default: %s)\n",
PatDbExpand(DHistoryPat));
fprintf(stderr, "\t-h n\tspecify history hash size\n");
fprintf(stderr, "\t-lc\tspecify number of history lookups (default: %d)\n",
LookupCount);
fprintf(stderr, "\t-lf\tspecify number of lookup forks (default: %d)\n",
LookupForks);
fprintf(stderr, "\t-m FILE\tuse FILE for the temp stats mmap (default: %s)\n",
StatsPath);
fprintf(stderr, "\nWARNING: This program writes garbage entries to the history file\n\n");
exit(1);
}
const char *HistoryFile = NULL;
int HOFlags = 0;
int
main(int ac, char **av)
{
int i;
int n;
int rpid;
int mapfd;
int mapindex = 0;
struct timeval tstart;
struct timeval tend;
double elapsed;
int LookupTotal = 0;
double LookupTime = 0.0;
int AddTotal = 0;
double AddTime = 0.0;
LoadDiabloConfig(ac, av);
strncpy(StatsPath, PatRunExpand("%s/dhisbench.map"), sizeof(StatsPath) - 1);
StatsPath[sizeof(StatsPath) - 1] = '\0';
for (i = 1; i < ac; ++i) {
char *ptr = av[i];
if (*ptr == '-') {
ptr += 2;
switch(ptr[-1]) {
case 'a':
if (*ptr == 'f') {
ptr++;
AddForks = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
} else if (*ptr == 'c') {
ptr++;
AddCount = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
}
break;
case 'C':
if (*ptr == 0)
++i;
break;
case 'F':
if (*ptr == 'l')
HOFlags = HGF_FAST;
else if (*ptr == 's')
HOFlags = HGF_NOSEARCH;
else
HOFlags = HGF_FAST|HGF_NOSEARCH;
break;
case 'f':
HistoryFile = (*ptr) ? ptr : av[++i];
break;
case 'h':
n = bsizetol((*ptr) ? ptr : av[++i]);
if (n < 256 * 1024 || n > 128 * 1024 * 1024) {
fprintf(stderr, "Illegal Hash size: %d\n", n);
exit(1);
}
if ((n ^ (n - 1)) != (n << 1) - 1) {
fprintf(stderr, "Hash size not a power of 2: %d\n", n);
exit(1);
}
DOpts.HashSize = n;
case 'l':
if (*ptr == 'f') {
ptr++;
LookupForks = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
} else if (*ptr == 'c') {
ptr++;
LookupCount = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
}
break;
case 'm':
if (!*ptr)
ptr = av[++i];
if (ptr == NULL || !*ptr)
Usage();
strncpy(StatsPath, ptr, sizeof(StatsPath) - 1);
StatsPath[sizeof(StatsPath) - 1] = '\0';
break;
default:
Usage();
}
}
}
if (AddForks == 0 && LookupForks == 0)
Usage();
if (AddForks == 0)
HOFlags |= HGF_READONLY;
if (HistoryFile == NULL)
HistoryFile = PatDbExpand(DHistoryPat);
printf("History File: %s\n", HistoryFile);
printf("Flags : ");
if (HOFlags & HGF_READONLY)
printf("RO ");
if (HOFlags & HGF_FAST)
printf("NOLOCK ");
if (HOFlags & HGF_NOSEARCH)
printf("NOSEARCH ");
printf("\n");
printf("Hash Size : %d\n", DOpts.HashSize);
/*
* Create history if it doesn't exist
*/
HistoryOpen(HistoryFile, HOFlags);
HistoryClose();
remove(StatsPath);
mapfd = open(StatsPath, O_RDWR|O_CREAT|O_EXCL, 0600);
if (mapfd == -1) {
fprintf(stderr, "Cannot create %s: %s", StatsPath, strerror(errno));
exit(1);
}
for (i = 0; i < AddForks + LookupForks; i++) {
ForkMap tsmap = { 0 };
write(mapfd, &tsmap, sizeof(tsmap));
}
StatsMap = xmap(NULL, sizeof(ForkMap) * (AddForks + LookupForks),
PROT_READ|PROT_WRITE, MAP_SHARED, mapfd, 0);
if (StatsMap == NULL) {
perror("mmap");
exit(1);
}
gettimeofday(&tstart, NULL);
for (i = 0; i < AddForks; i++)
if (fork() == 0) {
DoIt(2, AddCount, &StatsMap[mapindex]);
} else {
mapindex++;
}
for (i = 0; i < LookupForks; i++)
if (fork() == 0) {
DoIt(1, LookupCount, &StatsMap[mapindex]);
} else {
mapindex++;
}
i = AddForks + LookupForks;
while (i > 0)
if (waitpid(-1, &rpid, 0) != -1)
i--;
gettimeofday(&tend, NULL);
for (i = 0; i < mapindex; i++) {
ForkMap *smap = &StatsMap[i];
elapsed = (smap->tend.tv_sec + smap->tend.tv_usec / 1000000.0) -
(smap->tstart.tv_sec + smap->tstart.tv_usec / 1000000.0);
if (smap->type == 1) {
printf("L ");
LookupTotal += smap->count;
if (elapsed > LookupTime)
LookupTime = elapsed;
} else {
printf("A ");
AddTotal += smap->count;
if (elapsed > AddTime)
AddTime = elapsed;
}
printf("%10d %10.3f %10.0f\n", smap->count, elapsed, smap->count / elapsed);
}
elapsed = (tend.tv_sec + tend.tv_usec / 1000000.0) -
(tstart.tv_sec + tstart.tv_usec / 1000000.0);
printf("Lookups: %d\n", LookupTotal);
printf(" Adds: %d\n", AddTotal);
printf("Lookup Time: %.3f seconds\n", LookupTime);
printf(" Add Time: %.3f seconds\n", AddTime);
printf("Total Time: %.3f seconds\n", elapsed);
if (LookupTime == 0)
LookupTime = 1;
if (AddTime == 0)
AddTime = 1;
printf("%.0f lookups per second\n", LookupTotal / LookupTime);
printf("%.0f adds per second\n", AddTotal / AddTime);
close(mapfd);
remove(StatsPath);
exit(0);
}
void
DoIt(int Action, int count, ForkMap *smap)
{
int i;
char msgid[512];
hash_t hv;
History h = { 0 };
HistoryOpen(HistoryFile, HOFlags);
printf("pid=%d action=%d count=%d\n", getpid(), Action, count);
srandom(time(NULL) + getpid());
smap->type = Action;
gettimeofday(&smap->tstart, NULL);
for (i = 0; i < count; i++) {
sprintf(msgid,"<%d%08lx$%08lx@%08lx.%08lx.%08lx>", i,
random(), random(), random(), random(), random());
hv = hhash(msgid);
if (Action == 1) {
HistoryLookupByHash(hv, NULL);
} else if (Action == 2) {
h.hv = hv;
h.gmt = 1;
HistoryAdd((char *)msgid, &h);
}
smap->count++;
}
gettimeofday(&smap->tend, NULL);
exit(0);
}
syntax highlighted by Code2HTML, v. 0.9.1