On 6/7/13 8:06 AM, Dave Chinner wrote: > From: Dave Chinner <dchinner@xxxxxxxxxx> > > For benchmarking of bulkstat, add a multithreaded mode that spawns a > thread per AG and runs bulkstat on every AG in parallel. There is a > small amount of overlap between each AG because of the way the > interface works only on inode numbers, so some inodes are reported > twice. A real implementation of this sort of parallelism would be > greatly helped by adding an AG parameter to the bulkstat interface. > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> At least w/ older xfsprogs[[qa]-devel] packages, I get: bstat.c:41: error: redefinition of 'fls' /usr/include/xfs/bitops.h:8: note: previous definition of 'fls' was here bstat.c:70: error: redefinition of 'xfs_highbit32' /usr/include/xfs/xfs_bit.h:50: note: previous definition of 'xfs_highbit32' was here w/ the new functions you've added here... -Eric > --- > src/Makefile | 2 +- > src/bstat.c | 388 +++++++++++++++++++++++++++++++++++++++++++++------------- > 2 files changed, 302 insertions(+), 88 deletions(-) > > diff --git a/src/Makefile b/src/Makefile > index c18ffc9..243a432 100644 > --- a/src/Makefile > +++ b/src/Makefile > @@ -22,7 +22,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \ > > SUBDIRS = > > -LLDLIBS = $(LIBATTR) $(LIBHANDLE) $(LIBACL) > +LLDLIBS = $(LIBATTR) $(LIBHANDLE) $(LIBACL) -lpthread > > ifeq ($(HAVE_XLOG_ASSIGN_LSN), true) > LINUX_TARGETS += loggen > diff --git a/src/bstat.c b/src/bstat.c > index 4e22ecd..0fc7d9d 100644 > --- a/src/bstat.c > +++ b/src/bstat.c > @@ -18,6 +18,60 @@ > > #include "global.h" > #include <xfs/jdm.h> > +#include <pthread.h> > + > + > +int debug; > +int quiet; > +int statit; > +int verbose; > +int threaded; > + > +unsigned int > +libxfs_log2_roundup(unsigned int i) > +{ > + unsigned int rval; > + > + for (rval = 0; rval < NBBY * sizeof(i); rval++) { > + if ((1 << rval) >= i) > + break; > + } > + return rval; > +} > +static inline int fls(int x) > +{ > + int r = 32; > + > + if (!x) > + return 0; > + if (!(x & 0xffff0000u)) { > + x <<= 16; > + r -= 16; > + } > + if (!(x & 0xff000000u)) { > + x <<= 8; > + r -= 8; > + } > + if (!(x & 0xf0000000u)) { > + x <<= 4; > + r -= 4; > + } > + if (!(x & 0xc0000000u)) { > + x <<= 2; > + r -= 2; > + } > + if (!(x & 0x80000000u)) { > + x <<= 1; > + r -= 1; > + } > + return r; > +} > + > +static inline int xfs_highbit32(__uint32_t v) > +{ > + return fls(v) - 1; > +} > + > > void > dotime(void *ti, char *s) > @@ -62,87 +116,21 @@ printstat(struct stat64 *sp) > dotime(&sp->st_ctime, "ctime"); > } > > -int > -main(int argc, char **argv) > +static int > +do_bstat( > + int fsfd, > + jdm_fshandle_t *fshandlep, > + char *name, > + int nent, > + __u64 first, > + __u64 last) > { > __s32 count; > int total = 0; > - int fsfd; > - int i; > - __u64 last = 0; > - char *name; > - int nent; > - int debug = 0; > - int quiet = 0; > - int statit = 0; > - int verbose = 0; > xfs_bstat_t *t; > int ret; > - jdm_fshandle_t *fshandlep = NULL; > - int fd; > - struct stat64 sb; > - int nread; > - char *cc_readlinkbufp; > - int cc_readlinkbufsz; > - int c; > xfs_fsop_bulkreq_t bulkreq; > - > - while ((c = getopt(argc, argv, "cdl:qv")) != -1) { > - switch (c) { > - case 'q': > - quiet = 1; > - break; > - case 'v': > - verbose = 1; > - break; > - case 'c': > - statit = 1; > - break; > - case 'd': > - debug = 1; > - break; > - case 'l': > - last = atoi(optarg); > - break; > - case '?': > - printf("usage: xfs_bstat [-c] [-q] [-v] [ dir [ batch_size ]]\n"); > - printf(" -c Check the results against stat(3) output\n"); > - printf(" -q Quiet\n"); > - printf(" -l _num_ Inode to start with\n"); > - printf(" -v Verbose output\n"); > - exit(1); > - } > - } > - argc -= optind; > - argv += optind; > - > - if (argc < 1) > - name = "."; > - else > - name = *argv; > - > - fsfd = open(name, O_RDONLY); > - if (fsfd < 0) { > - perror(name); > - exit(1); > - } > - if (argc < 2) > - nent = 4096; > - else > - nent = atoi(*++argv); > - > - if (verbose) > - printf("Bulkstat test on %s, batch size=%d statcheck=%d\n", > - name, nent, statit); > - > - if (statit) { > - fshandlep = jdm_getfshandle( name ); > - if (! fshandlep) { > - printf("unable to construct sys handle for %s: %s\n", > - name, strerror(errno)); > - return -1; > - } > - } > + __u64 ino; > > t = malloc(nent * sizeof(*t)); > > @@ -150,23 +138,27 @@ main(int argc, char **argv) > printf( > "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d\n", (long long)last, nent); > > - bulkreq.lastip = &last; > + ino = first; > + > + bulkreq.lastip = &ino; > bulkreq.icount = nent; > bulkreq.ubuffer = t; > bulkreq.ocount = &count; > > while ((ret = xfsctl(name, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) == 0) { > + int i; > + > total += count; > > if (verbose) > printf( > - "XFS_IOC_FSBULKSTAT test: last=%lld ret=%d count=%d total=%d\n", > - (long long)last, ret, count, total); > + "XFS_IOC_FSBULKSTAT test: first/last/ino=%lld/%lld/%lld ret=%d count=%d total=%d\n", > + (long long)first, (long long)last, (long long)ino, ret, count, total); > if (count == 0) > - exit(0); > + break; > > if ( quiet && ! statit ) > - continue; > + goto next; > > for (i = 0; i < count; i++) { > if (! quiet) { > @@ -174,6 +166,12 @@ main(int argc, char **argv) > } > > if (statit) { > + char *cc_readlinkbufp; > + int cc_readlinkbufsz; > + struct stat64 sb; > + int nread; > + int fd; > + > switch(t[i].bs_mode & S_IFMT) { > case S_IFLNK: > cc_readlinkbufsz = MAXPATHLEN; > @@ -244,10 +242,231 @@ main(int argc, char **argv) > } > } > } > - > +next: > if (debug) > break; > + > + if (ino >= last) > + break; > } > + if (verbose) > + printf( > + "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d ret=%d count=%d\n", > + (long long)last, nent, ret, count); > + > + return total; > +} > + > +struct thread_args { > + pthread_t tid; > + int fsfd; > + jdm_fshandle_t *fshandlep; > + char *name; > + int nent; > + __u64 first; > + __u64 last; > + int ret; > +}; > + > +static void * > +do_bstat_thread( > + void *args) > +{ > + struct thread_args *targs = args; > + > + targs->ret = do_bstat(targs->fsfd, targs->fshandlep, targs->name, > + targs->nent, targs->first, targs->last); > + return NULL; > +} > + > +/* > + * XFS_AGINO_TO_INO(mp,a,i) \ > + * (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) > + * > + * i always zero, so: > + * a << XFS_INO_AGINO_BITS(mp) > + * > + * XFS_INO_AGINO_BITS(mp) (mp)->m_agino_log > + * > + * mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog > + * > + * sb_inopblog = fsgeom.blocksize / fsgeom.inodesize > + * sb_agblklog = (__uint8_t)libxfs_log2_roundup((unsigned int)fsgeom.agblocks); > + * > + * a << (libxfs_highbit32(fsgeom.blocksize /fsgeom.inodesize) + > + * libxfs_log2_roundup(fsgeom.agblocks)); > + */ > +#define FSGEOM_INOPBLOG(fsg) \ > + (xfs_highbit32((fsg).blocksize / (fsg).inodesize)) > +#define FSGEOM_AGINO_TO_INO(fsg, a, i) \ > + (((__u64)(a) << (FSGEOM_INOPBLOG(fsg) + \ > + libxfs_log2_roundup((fsg).agblocks))) | (i)) > + > +/* > + * XFS_OFFBNO_TO_AGINO(mp,b,o) \ > + * ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) > + * > + * i always zero, so: > + * b << XFS_INO_OFFSET_BITS(mp) > + * > + * XFS_INO_OFFSET_BITS(mp) (mp)->m_sb.sb_inopblog > + */ > +#define FSGEOM_OFFBNO_TO_AGINO(fsg, b, o) \ > + ((__u32)(((b) << FSGEOM_INOPBLOG(fsg)) | (o))) > +static int > +do_threads( > + int fsfd, > + jdm_fshandle_t *fshandlep, > + char *name, > + int nent, > + __u64 first) > +{ > + struct xfs_fsop_geom geom; > + struct thread_args *targs; > + int ret; > + int i; > + int numthreads; > + int total = 0; > + > + > + /* get number of AGs */ > + ret = ioctl(fsfd, XFS_IOC_FSGEOMETRY, &geom); > + if (ret) { > + perror("XFS_IOC_FSGEOMETRY"); > + exit(1); > + } > + > + /* allocate thread array */ > + targs = malloc(geom.agcount * sizeof(*targs)); > + if (ret) { > + perror("malloc(targs)"); > + exit(1); > + } > + > + for (i = 0; i < geom.agcount; i++) { > + __u64 last; > + > + last = FSGEOM_AGINO_TO_INO(geom, i, > + FSGEOM_OFFBNO_TO_AGINO(geom, > + geom.agblocks - 1, 0)); > + > + if (first > last) { > + i--; > + continue; > + } > + first = MAX(first, FSGEOM_AGINO_TO_INO(geom, i, 0)); > + > + targs[i].fsfd = fsfd; > + targs[i].fshandlep = fshandlep; > + targs[i].name = name; > + targs[i].nent = nent; > + targs[i].first = first; > + targs[i].last = last; > + targs[i].ret = 0; > + } > + numthreads = i; > + > + /* start threads */ > + for (i = 0; i< numthreads; i++) { > + ret = pthread_create(&targs[i].tid, NULL, do_bstat_thread, &targs[i]); > + if (ret) { > + perror("pthread-create"); > + exit(1); > + } > + } > + > + > + /* join threads */ > + for (i = 0; i < numthreads; i++) { > + if (targs[i].tid) { > + pthread_join(targs[i].tid, NULL); > + total += targs[i].ret; > + } > + } > + > + /* die */ > + return total; > +} > + > + > +int > +main(int argc, char **argv) > +{ > + int fsfd; > + __u64 first = 0; > + char *name; > + int nent; > + int ret; > + jdm_fshandle_t *fshandlep = NULL; > + int c; > + > + while ((c = getopt(argc, argv, "cdl:qtv")) != -1) { > + switch (c) { > + case 'q': > + quiet = 1; > + break; > + case 'v': > + verbose = 1; > + break; > + case 'c': > + statit = 1; > + break; > + case 'd': > + debug = 1; > + break; > + case 'l': > + first = atoi(optarg); > + break; > + case 't': > + threaded = 1; > + break; > + case '?': > + printf("usage: xfs_bstat [-c] [-q] [-v] [ dir [ batch_size ]]\n"); > + printf(" -c Check the results against stat(3) output\n"); > + printf(" -q Quiet\n"); > + printf(" -l _num_ Inode to start with\n"); > + printf(" -v Verbose output\n"); > + exit(1); > + } > + } > + argc -= optind; > + argv += optind; > + > + if (argc < 1) > + name = "."; > + else > + name = *argv; > + > + fsfd = open(name, O_RDONLY); > + if (fsfd < 0) { > + perror(name); > + exit(1); > + } > + if (argc < 2) > + nent = 4096; > + else > + nent = atoi(*++argv); > + > + if (verbose) > + printf("Bulkstat test on %s, batch size=%d statcheck=%d\n", > + name, nent, statit); > + > + if (statit) { > + fshandlep = jdm_getfshandle( name ); > + if (! fshandlep) { > + printf("unable to construct sys handle for %s: %s\n", > + name, strerror(errno)); > + return -1; > + } > + } > + > + if (threaded) > + ret = do_threads(fsfd, fshandlep, name, nent, first); > + else > + ret = do_bstat(fsfd, fshandlep, name, nent, first, -1LL); > + > + if (verbose) > + printf("Bulkstat found %d inodes\n", ret); > > if (fsfd) > close(fsfd); > @@ -255,10 +474,5 @@ main(int argc, char **argv) > if (ret < 0 ) > perror("xfsctl(XFS_IOC_FSBULKSTAT)"); > > - if (verbose) > - printf( > - "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d ret=%d count=%d\n", > - (long long)last, nent, ret, count); > - > - return 1; > + return 0; > } > _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs