From: Nathan Scott Date: Fri, 7 Jul 2006 16:01:51 +0000 (+0000) Subject: Simple little program for populating a filesystem that could look like one DMF might... X-Git-Tag: v1.1.0~612 X-Git-Url: http://git.apps.os.sepia.ceph.com/?p=xfstests-dev.git;a=commitdiff_plain;h=30746979d61f8ec3aa1f6e0a3da9fbb339cdd698;ds=sidebyside Simple little program for populating a filesystem that could look like one DMF might be using. Merge of master-melb:xfs-cmds:26472a by kenmcd. --- diff --git a/src/Makefile b/src/Makefile index c82e8289..b041a1c2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \ mmapcat append_reader append_writer dirperf metaperf \ devzero feature alloc fault fstest t_access_root \ godown resvtest writemod makeextents itrash \ - multi_open_unlink + multi_open_unlink dmiperf LINUX_TARGETS = loggen xfsctl bstat t_mtab getdevicesize @@ -79,6 +79,9 @@ multi_open_unlink: multi_open_unlink.o acl_get: acl_get.o $(LIBACL) $(LIBATTR) $(LINKTEST) $(LIBACL) $(LIBATTR) $(LDLIBS) +dmiperf: dmiperf.o $(LIBATTR) + $(LINKTEST) $(LIBATTR) $(LDLIBS) + ifeq ($(PKG_PLATFORM),irix) fill2: fill2.o diff --git a/src/dmiperf.c b/src/dmiperf.c new file mode 100644 index 00000000..28f95a48 --- /dev/null +++ b/src/dmiperf.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2006 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXNAMELEN 256 +#ifndef __sgi__ +typedef unsigned int uint_t; +#endif + +/* + * Loop over directory sizes: + * make m directories + * touch n files in each directory + * write y bytes to all files in each directory + * set DMF attribute on x files in each directory + * Change directory sizes by multiplication or addition. + * Allow control of starting & stopping sizes, name length, target directory. + * Print size and wallclock time (ms per file). + * Output can be used to make graphs (gnuplot) + */ + +static uint_t addval; +static uint_t dirchars; +static char *directory; +static uint_t firstsize; +static uint_t lastsize; +static uint_t minchars; +static double mulval; +static uint_t nchars; +static uint_t ndirs; +static uint_t pfxchars; +static off64_t fsize; +static char *buffer; +static size_t bsize; + +static int mkfile(char *, char *); +static void filename(int, int, char *); +static int hexchars(uint_t); +static uint_t nextsize(uint_t); +static double now(void); +static void usage(void); + +/* + * Maximum size allowed, this is pretty nuts. + * The largest one we've ever built has been about 2 million. + */ +#define MAX_DIR_SIZE (16 * 1024 * 1024) +#define DFL_FIRST_SIZE 1 +#define DFL_LAST_SIZE (1024 * 1024) +#define MAX_DIR_COUNT 1024 +#define MIN_DIR_COUNT 1 + +#define DMFATTRLEN 22 +#define DMFATTRNAME "SGI_DMI_DMFATTR" + +int +main(int argc, char **argv) +{ + int c; + uint_t cursize; + int i; + int j; + char name[MAXNAMELEN]; + char attr[DMFATTRLEN]; + double stime; + + while ((c = getopt(argc, argv, "a:b:c:d:f:l:m:n:s:")) != -1) { + switch (c) { + case 'a': + addval = (uint_t)atoi(optarg); + break; + case 'b': + bsize = (size_t)atol(optarg); + break; + case 'c': + nchars = (uint_t)atoi(optarg); + break; + case 'd': + directory = optarg; + break; + case 'f': + firstsize = (uint_t)atoi(optarg); + break; + case 'l': + lastsize = (uint_t)atoi(optarg); + break; + case 'm': + mulval = atof(optarg); + break; + case 'n': + ndirs = (uint_t)atoi(optarg); + break; + case 's': + fsize = (off64_t)atol(optarg); + break; + case '?': + default: + usage(); + exit(1); + } + } + if (!addval && !mulval) + mulval = 2.0; + else if ((addval && mulval) || mulval < 0.0) { + usage(); + exit(1); + } + if (!bsize) + bsize = 1024 * 1024; + buffer = memalign(getpagesize(), bsize); + memset(buffer, 0xfeed, bsize); + memset(attr, 0xaaaaaaa, sizeof(attr)); + + if (!directory) + directory = "."; + else { + if (mkdir(directory, 0777) < 0 && errno != EEXIST) { + perror(directory); + exit(1); + } + if (chdir(directory) < 0) { + perror(directory); + exit(1); + } + } + if (firstsize == 0) + firstsize = DFL_FIRST_SIZE; + else if (firstsize > MAX_DIR_SIZE) + firstsize = MAX_DIR_SIZE; + if (lastsize == 0) + lastsize = DFL_LAST_SIZE; + else if (lastsize > MAX_DIR_SIZE) + lastsize = MAX_DIR_SIZE; + if (lastsize < firstsize) + lastsize = firstsize; + minchars = hexchars(lastsize - 1); + if (nchars < minchars) + nchars = minchars; + else if (nchars >= MAXNAMELEN) + nchars = MAXNAMELEN - 1; + if (ndirs > MAX_DIR_COUNT) + ndirs = MAX_DIR_COUNT; + if (ndirs < MIN_DIR_COUNT) + ndirs = MIN_DIR_COUNT; + dirchars = hexchars(ndirs); + pfxchars = nchars - minchars; + if (pfxchars) + memset(&name[dirchars + 1], 'a', pfxchars); + + cursize = firstsize; + for (j = 0; j < ndirs; j++) { + filename(0, j, name); + name[dirchars] = '\0'; + mkdir(name, 0777); + stime = now(); + for (i = 0; i < cursize; i++) { + filename((i + j) % cursize, j, name); + close(mkfile(name, attr)); + } + printf("%d %.3f\n", cursize, + (now() - stime) * 1.0e3 / (cursize * ndirs)); + cursize = nextsize(cursize); + } + return 0; +} + +static int +mkfile(char *name, char *attr) +{ + int fd; + ssize_t wrote, wsize; + off64_t bytes = fsize; + + if ((fd = open(name, O_WRONLY | O_CREAT | O_EXCL | O_DIRECT)) < 0) { + perror("open"); + exit(1); + } + if (attr_setf(fd, DMFATTRNAME, attr, DMFATTRLEN, ATTR_ROOT) < 0) { + perror("attr_setf"); + exit(1); + } + while (bytes > 0) { + wsize = (bsize < bytes) ? bsize : bytes; + if ((wrote = write(fd, buffer, wsize)) < 0) { + perror("write"); + exit(1); + } + bytes -= wrote; + } + return fd; +} + +static void +filename(int idx, int dir, char *name) +{ + static char hexc[16] = "0123456789abcdef"; + int i; + + for (i = dirchars - 1; i >= 0; i--) + *name++ = hexc[(dir >> (4 * i)) & 0xf]; + *name++ = '/'; + name += pfxchars; /* skip pfx a's */ + for (i = minchars - 1; i >= 0; i--) + *name++ = hexc[(idx >> (4 * i)) & 0xf]; + *name = '\0'; +} + +static int +hexchars(uint_t maxval) +{ + if (maxval < 16) + return 1; + if (maxval < 16 * 16) + return 2; + if (maxval < 16 * 16 * 16) + return 3; + if (maxval < 16 * 16 * 16 * 16) + return 4; + if (maxval < 16 * 16 * 16 * 16 * 16) + return 5; + if (maxval < 16 * 16 * 16 * 16 * 16 * 16) + return 6; + if (maxval < 16 * 16 * 16 * 16 * 16 * 16 * 16) + return 7; + return 8; +} + +static uint_t +nextsize(uint_t cursize) +{ + double n; + + n = cursize; + if (addval) + n += addval; + else + n *= mulval; + if (n > (double)lastsize + 0.5) + return lastsize + 1; /* i.e. out of bounds */ + else if ((uint_t)n == cursize) + return cursize + 1; + else + return (uint_t)n; +} + +static double +now(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec; +} + +static void +usage(void) +{ + fprintf(stderr, + "usage: dirperf [-d dir] [-a addstep | -m mulstep] [-f first] " + "[-l last] [-c nchars] [-n ndirs] [-s size]\n"); +}