mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
540 lines
9.7 KiB
C
540 lines
9.7 KiB
C
/*
|
|
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* Further, this software is distributed without any warranty that it is
|
|
* free of the rightful claim of any third person regarding infringement
|
|
* or the like. Any license provided herein, whether implied or
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
|
* any, provided herein do not apply to combinations of this program with
|
|
* other software, or any other product whatsoever.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
|
*
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
|
* Mountain View, CA 94043, or:
|
|
*
|
|
* http://www.sgi.com
|
|
*
|
|
* For further information regarding this notice, see:
|
|
*
|
|
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
|
|
typedef void *(*fpi_t)(void);
|
|
typedef void (*fpt_t)(int, void *);
|
|
typedef void (*fpd_t)(void *);
|
|
typedef struct tdesc
|
|
{
|
|
char *name;
|
|
fpi_t init;
|
|
fpt_t test;
|
|
fpd_t done;
|
|
} tdesc_t;
|
|
|
|
static void d_readdir(void *);
|
|
static void *i_readdir(void);
|
|
static void t_readdir(int, void *);
|
|
static void crfiles(char **, int, char *);
|
|
static void d_chown(void *);
|
|
static void d_create(void *);
|
|
static void d_linkun(void *);
|
|
static void d_open(void *);
|
|
static void d_rename(void *);
|
|
static void d_stat(void *);
|
|
static void delflist(char **);
|
|
static void dotest(tdesc_t *);
|
|
static void *i_chown(void);
|
|
static void *i_create(void);
|
|
static void *i_linkun(void);
|
|
static void *i_open(void);
|
|
static void *i_rename(void);
|
|
static void *i_stat(void);
|
|
static char **mkflist(int, int, char);
|
|
static double now(void);
|
|
static void prtime(char *, int, double);
|
|
static void rmfiles(char **);
|
|
static void t_chown(int, void *);
|
|
static void t_create(int, void *);
|
|
static void t_crunlink(int, void *);
|
|
static void t_linkun(int, void *);
|
|
static void t_open(int, void *);
|
|
static void t_rename(int, void *);
|
|
static void t_stat(int, void *);
|
|
static void usage(void);
|
|
|
|
tdesc_t tests[] = {
|
|
{ "chown", i_chown, t_chown, d_chown },
|
|
{ "create", i_create, t_create, d_create },
|
|
{ "crunlink", (fpi_t)0, t_crunlink, (fpd_t)0 },
|
|
{ "readdir", i_readdir, t_readdir, d_readdir },
|
|
{ "linkun", i_linkun, t_linkun, d_linkun },
|
|
{ "open", i_open, t_open, d_open },
|
|
{ "rename", i_rename, t_rename, d_rename },
|
|
{ "stat", i_stat, t_stat, d_stat },
|
|
{ NULL }
|
|
};
|
|
|
|
char *buffer;
|
|
int compact = 0;
|
|
int files_bg = 0;
|
|
int files_op = 1;
|
|
char **flist_bg;
|
|
char **flist_op;
|
|
int fnlen_bg = 5;
|
|
int fnlen_op = 5;
|
|
int fsize = 0;
|
|
int iters = 0;
|
|
double time_end;
|
|
double time_start;
|
|
int totsec = 0;
|
|
int verbose = 0;
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int c;
|
|
char *testdir;
|
|
tdesc_t *tp;
|
|
|
|
testdir = getenv("TMPDIR");
|
|
if (testdir == NULL)
|
|
testdir = ".";
|
|
while ((c = getopt(argc, argv, "cd:i:l:L:n:N:s:t:v")) != -1) {
|
|
switch (c) {
|
|
case 'c':
|
|
compact = 1;
|
|
break;
|
|
case 'd':
|
|
testdir = optarg;
|
|
break;
|
|
case 'i':
|
|
iters = atoi(optarg);
|
|
break;
|
|
case 'l':
|
|
fnlen_op = atoi(optarg);
|
|
break;
|
|
case 'L':
|
|
fnlen_bg = atoi(optarg);
|
|
break;
|
|
case 'n':
|
|
files_op = atoi(optarg);
|
|
break;
|
|
case 'N':
|
|
files_bg = atoi(optarg);
|
|
break;
|
|
case 's':
|
|
fsize = atoi(optarg);
|
|
break;
|
|
case 't':
|
|
totsec = atoi(optarg);
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case '?':
|
|
fprintf(stderr, "bad option\n");
|
|
usage();
|
|
}
|
|
}
|
|
if (!iters && !totsec)
|
|
iters = 1;
|
|
if (chdir(testdir) < 0) {
|
|
perror(testdir);
|
|
return 1;
|
|
}
|
|
if (mkdir("metaperf", 0777) < 0 || chdir("metaperf") < 0) {
|
|
perror("metaperf");
|
|
return 1;
|
|
}
|
|
for (; optind < argc; optind++) {
|
|
for (tp = tests; tp->name; tp++) {
|
|
if (strcmp(argv[optind], tp->name) == 0) {
|
|
dotest(tp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
chdir("..");
|
|
rmdir("metaperf");
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
crfiles(char **flist, int fsize, char *buf)
|
|
{
|
|
int fd;
|
|
char **fnp;
|
|
|
|
for (fnp = flist; *fnp; fnp++) {
|
|
fd = creat(*fnp, 0666);
|
|
if (fsize)
|
|
write(fd, buf, fsize);
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
d_chown(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
d_create(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
}
|
|
|
|
static void
|
|
d_readdir(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
closedir((DIR *)v);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
d_linkun(void *v)
|
|
{
|
|
unlink("a");
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
d_open(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
}
|
|
|
|
static void
|
|
d_rename(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
rmfiles((char **)v);
|
|
delflist((char **)v);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
d_stat(void *v)
|
|
{
|
|
rmfiles(flist_op);
|
|
}
|
|
|
|
static void
|
|
delflist(char **flist)
|
|
{
|
|
char **fnp;
|
|
|
|
for (fnp = flist; *fnp; fnp++)
|
|
free(*fnp);
|
|
free(flist);
|
|
}
|
|
|
|
static void
|
|
dotest(tdesc_t *tp)
|
|
{
|
|
double dn;
|
|
double gotsec;
|
|
int n;
|
|
void *v;
|
|
|
|
flist_bg = mkflist(files_bg, fnlen_bg, 'b');
|
|
flist_op = mkflist(files_op, fnlen_op, 'o');
|
|
if (fsize)
|
|
buffer = calloc(fsize, 1);
|
|
else
|
|
buffer = NULL;
|
|
crfiles(flist_bg, 0, (char *)0);
|
|
n = iters ? iters : 1;
|
|
v = (void *)0;
|
|
for (;;) {
|
|
if (tp->init)
|
|
v = (tp->init)();
|
|
sync();
|
|
sleep(1);
|
|
time_start = now();
|
|
(tp->test)(n, v);
|
|
time_end = now();
|
|
if (tp->done)
|
|
(tp->done)(v);
|
|
gotsec = time_end - time_start;
|
|
if (!totsec || gotsec >= 0.9 * totsec)
|
|
break;
|
|
if (verbose)
|
|
prtime(tp->name, n, gotsec);
|
|
if (!gotsec)
|
|
gotsec = 1.0 / (2 * HZ);
|
|
if (gotsec < 0.001 * totsec)
|
|
dn = n * (0.01 * totsec / gotsec);
|
|
else if (gotsec < 0.01 * totsec)
|
|
dn = n * (0.1 * totsec / gotsec);
|
|
else
|
|
dn = n * (totsec / gotsec);
|
|
if ((int)dn <= n)
|
|
n++;
|
|
else
|
|
n = (int)dn;
|
|
}
|
|
prtime(tp->name, n, gotsec);
|
|
rmfiles(flist_bg);
|
|
delflist(flist_bg);
|
|
delflist(flist_op);
|
|
if (fsize)
|
|
free(buffer);
|
|
}
|
|
|
|
static void *
|
|
i_chown(void)
|
|
{
|
|
char **fnp;
|
|
|
|
crfiles(flist_op, 0, (char *)0);
|
|
for (fnp = flist_op; *fnp; fnp++)
|
|
chown(*fnp, 1, -1);
|
|
return (void *)0;
|
|
}
|
|
|
|
static void *
|
|
i_create(void)
|
|
{
|
|
crfiles(flist_op, fsize, buffer);
|
|
return (void *)0;
|
|
}
|
|
|
|
static void *
|
|
i_readdir(void)
|
|
{
|
|
crfiles(flist_op, 0, (char *)0);
|
|
return opendir(".");
|
|
}
|
|
|
|
static void *
|
|
i_linkun(void)
|
|
{
|
|
close(creat("a", 0666));
|
|
return (void *)0;
|
|
}
|
|
|
|
static void *
|
|
i_open(void)
|
|
{
|
|
crfiles(flist_op, 0, (char *)0);
|
|
return (void *)0;
|
|
}
|
|
|
|
static void *
|
|
i_rename(void)
|
|
{
|
|
crfiles(flist_op, 0, (char *)0);
|
|
return (void *)mkflist(files_op, fnlen_op, 'r');
|
|
}
|
|
|
|
static void *
|
|
i_stat(void)
|
|
{
|
|
crfiles(flist_op, 0, (char *)0);
|
|
return (void *)0;
|
|
}
|
|
|
|
static char **
|
|
mkflist(int files, int fnlen, char start)
|
|
{
|
|
int i;
|
|
char **rval;
|
|
|
|
rval = calloc(files + 1, sizeof(char *));
|
|
for (i = 0; i < files; i++) {
|
|
rval[i] = malloc(fnlen + 1);
|
|
sprintf(rval[i], "%0*d%c", fnlen - 1, i, start);
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
static double
|
|
now(void)
|
|
{
|
|
struct timeval t;
|
|
|
|
gettimeofday(&t, (void *)0);
|
|
return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
|
|
}
|
|
|
|
static void
|
|
prtime(char *name, int n, double t)
|
|
{
|
|
double ops_per_sec;
|
|
double usec_per_op;
|
|
|
|
ops_per_sec = (double)n * (double)files_op / t;
|
|
usec_per_op = t * 1.0e6 / ((double)n * (double)files_op);
|
|
if (compact)
|
|
printf("%s %d %d %d %d %d %d %f %f %f\n",
|
|
name, n, files_op, fnlen_op, fsize, files_bg, fnlen_bg,
|
|
t, ops_per_sec, usec_per_op);
|
|
else {
|
|
printf("%s: %d times, %d file(s) namelen %d",
|
|
name, n, files_op, fnlen_op);
|
|
if (fsize)
|
|
printf(" size %d", fsize);
|
|
if (files_bg)
|
|
printf(", bg %d file(s) namelen %d",
|
|
files_bg, fnlen_bg);
|
|
printf(", time = %f sec, ops/sec=%f, usec/op = %f\n",
|
|
t, ops_per_sec, usec_per_op);
|
|
}
|
|
}
|
|
|
|
static void
|
|
rmfiles(char **flist)
|
|
{
|
|
char **fnp;
|
|
|
|
for (fnp = flist; *fnp; fnp++)
|
|
unlink(*fnp);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_chown(int n, void *v)
|
|
{
|
|
char **fnp;
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
for (fnp = flist_op; *fnp; fnp++) {
|
|
if ((i & 1) == 0)
|
|
chown(*fnp, 2, -1);
|
|
else
|
|
chown(*fnp, 1, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_create(int n, void *v)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++)
|
|
crfiles(flist_op, fsize, buffer);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_crunlink(int n, void *v)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
crfiles(flist_op, fsize, buffer);
|
|
rmfiles(flist_op);
|
|
}
|
|
}
|
|
|
|
static void
|
|
t_readdir(int n, void *v)
|
|
{
|
|
DIR *dir;
|
|
int i;
|
|
|
|
for (dir = (DIR *)v, i = 0; i < n; i++) {
|
|
rewinddir(dir);
|
|
while ((readdir(dir)) != NULL);
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_linkun(int n, void *v)
|
|
{
|
|
char **fnp;
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
for (fnp = flist_op; *fnp; fnp++)
|
|
link("a", *fnp);
|
|
rmfiles(flist_op);
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_open(int n, void *v)
|
|
{
|
|
char **fnp;
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
for (fnp = flist_op; *fnp; fnp++)
|
|
close(open(*fnp, O_RDWR));
|
|
}
|
|
}
|
|
|
|
static void
|
|
t_rename(int n, void *v)
|
|
{
|
|
char **fnp;
|
|
int i;
|
|
char **rflist;
|
|
char **rfp;
|
|
|
|
for (rflist = (char **)v, i = 0; i < n; i++) {
|
|
for (fnp = flist_op, rfp = rflist; *fnp; fnp++, rfp++) {
|
|
if ((i & 1) == 0)
|
|
rename(*fnp, *rfp);
|
|
else
|
|
rename(*rfp, *fnp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
t_stat(int n, void *v)
|
|
{
|
|
char **fnp;
|
|
int i;
|
|
struct stat stb;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
for (fnp = flist_op; *fnp; fnp++)
|
|
stat(*fnp, &stb);
|
|
}
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: metaperf [-d dname] [-i iters|-t seconds] [-s fsize]\n"
|
|
"\t[-l opfnamelen] [-L bgfnamelen]\n"
|
|
"\t[-n opfcount] [-N bgfcount] test...\n");
|
|
fprintf(stderr,
|
|
"Tests: chown create crunlink linkun open rename stat readdir\n");
|
|
exit(1);
|
|
}
|