blob: 4a1def005dee54a5648d12738185043309d8c686 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2003-2004 Silicon Graphics, Inc.
* All Rights Reserved.
*/
/*
* Test scaling of multiple processes opening/reading
* a number of small files simultaneously.
* - create <f> files
* - fork <n> processes
* - wait for all processes ready
* - start all proceses at the same time
* - each processes opens , read, closes each file
* - option to resync each process at each file
*
* test [-c cpus] [-b bytes] [-f files] [-v] [-s] [-S]
* OR
* test -i [-b bytes] [-f files]
*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void do_initfiles(void);
void slave(int);
#define VPRINT(x...) do { if(verbose) fprintf(x);} while(0)
#define perrorx(s) do {perror(s); exit(1);} while (0)
long bytes=8192;
int cpus=1;
int init=0;
int strided=0;
int files=1;
int blksize=512;
int syncstep=0;
int verbose=0;
typedef struct {
volatile long go;
long fill[15];
volatile long rdy[512];
} share_t;
share_t *sharep;
int
runon(int cpu)
{
#ifdef sys_sched_setaffinity
unsigned long mask[8];
if (cpu < 0 || cpu >= 512)
return -1;
memset(mask, 0, sizeof(mask));
mask[cpu/64] |= 1UL<<(cpu&63);
if (syscall(sys_sched_setaffinity, 0, sizeof(mask), mask))
return -1;
#endif
return 0;
}
long
scaled_atol(char *p)
{
long val;
char *pe;
val = strtol(p, &pe, 0);
if (*pe == 'K' || *pe == 'k')
val *= 1024L;
else if (*pe == 'M' || *pe == 'm')
val *= 1024L*1024L;
else if (*pe == 'G' || *pe == 'g')
val *= 1024L*1024L*1024L;
else if (*pe == 'p' || *pe == 'P')
val *= getpagesize();
return val;
}
int
main(int argc, char** argv) {
int shmid;
static char optstr[] = "c:b:f:sSivH";
int notdone, stat, i, j, c, er=0;
opterr=1;
while ((c = getopt(argc, argv, optstr)) != EOF)
switch (c) {
case 'c':
cpus = atoi(optarg);
break;
case 'b':
bytes = scaled_atol(optarg);
break;
case 'f':
files = atoi(optarg);
break;
case 'i':
init++;
break;
case 's':
syncstep++;
break;
case 'S':
strided++;
break;
case 'v':
verbose++;
break;
case '?':
er = 1;
break;
}
if (er) {
printf("usage: %s %s\n", argv[0], optstr);
exit(1);
}
if ((shmid = shmget(IPC_PRIVATE, sizeof (share_t), IPC_CREAT|SHM_R|SHM_W)) == -1)
perrorx("shmget failed");
sharep = (share_t*)shmat(shmid, (void*)0, SHM_R|SHM_W);
memset(sharep, -1, sizeof (share_t));
if (init) {
do_initfiles();
exit(0);
}
for (i=0; i<cpus; i++) {
if (fork() == 0)
slave(i);
}
for (i=0; i<files; i++) {
VPRINT(stderr, "%d:", i);
notdone = cpus;
do {
for (j=0; j<cpus; j++) {
if (sharep->rdy[j] == i) {
sharep->rdy[j] = -1;
VPRINT(stderr, " %d", j);
notdone--;
}
}
} while (notdone);
VPRINT(stderr, "\n");
sharep->go = i;
if (!syncstep)
break;
}
VPRINT(stderr, "\n");
while (wait(&stat)> 0)
VPRINT(stderr, ".");
VPRINT(stderr, "\n");
exit(0);
}
void
slave(int id)
{
int i, fd, byte;
char *buf, filename[32];
runon (id+1);
buf = malloc(blksize);
bzero(buf, blksize);
for (i=0; i<files; i++) {
if (!i || syncstep) {
sharep->rdy[id] = i;
while(sharep->go != i);
}
sprintf(filename, "/tmp/tst.%d", (strided ? ((i + id) % files) : i));
if ((fd = open (filename, O_RDONLY)) < 0) {
perrorx(filename);
}
for (byte=0; byte<bytes; byte+=blksize) {
if (read (fd, buf, blksize) != blksize)
perrorx("read of file failed");
}
close(fd);
}
exit(0);
}
void
do_initfiles(void)
{
int i, fd, byte;
char *buf, filename[32];
buf = malloc(blksize);
bzero(buf, blksize);
for (i=0; i<files; i++) {
sprintf(filename, "/tmp/tst.%d", i);
unlink(filename);
if ((fd = open (filename, O_RDWR|O_CREAT, 0644)) < 0)
perrorx(filename);
for (byte=0; byte<bytes; byte+=blksize) {
if (write (fd, buf, blksize) != blksize)
perrorx("write of file failed");
}
close(fd);
}
sync();
}