mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
575 lines
10 KiB
C
575 lines
10 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>
|
||
|
|
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
#include <sys/dirent.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
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;
|
||
|
|
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
static void d_getdents(void *);
|
||
|
|
static void *i_getdents(void);
|
||
|
|
static void t_getdents(int, void *);
|
||
|
|
#endif
|
||
|
|
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 },
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
{ "getdents", i_getdents, t_getdents, d_getdents },
|
||
|
|
#endif
|
||
|
|
{ "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;
|
||
|
|
|
||
|
|
struct getdents_data
|
||
|
|
{
|
||
|
|
void *buffer;
|
||
|
|
int buflen;
|
||
|
|
int fd;
|
||
|
|
};
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
static void
|
||
|
|
d_getdents(void *v)
|
||
|
|
{
|
||
|
|
struct getdents_data *g;
|
||
|
|
|
||
|
|
rmfiles(flist_op);
|
||
|
|
g = v;
|
||
|
|
close(g->fd);
|
||
|
|
free(g->buffer);
|
||
|
|
free(g);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
static void *
|
||
|
|
i_getdents(void)
|
||
|
|
{
|
||
|
|
struct getdents_data *g;
|
||
|
|
|
||
|
|
crfiles(flist_op, 0, (char *)0);
|
||
|
|
g = malloc(sizeof(*g));
|
||
|
|
g->buflen = 16 * 1024;
|
||
|
|
g->buffer = malloc(g->buflen);
|
||
|
|
g->fd = open(".", O_RDONLY);
|
||
|
|
return g;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef HAVE_GETDENTS
|
||
|
|
static void
|
||
|
|
t_getdents(int n, void *v)
|
||
|
|
{
|
||
|
|
int eof;
|
||
|
|
struct getdents_data *g;
|
||
|
|
int i;
|
||
|
|
int j;
|
||
|
|
|
||
|
|
for (g = v, i = 0; i < n; i++) {
|
||
|
|
(void)lseek(g->fd, 0, SEEK_SET);
|
||
|
|
eof = 0;
|
||
|
|
do {
|
||
|
|
j = ngetdents(g->fd, (dirent_t *)g->buffer, g->buflen,
|
||
|
|
&eof);
|
||
|
|
} while (j > 0 && eof == 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/* 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 available: chown, create, crunlink, linkun, open, rename, stat\n");
|
||
|
|
exit(1);
|
||
|
|
}
|