| /* |
| * 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 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. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #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); |
| } |