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> --- 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; } -- 1.7.10.4 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs