[PATCH 6/6] xfstests: add a multithreaded mode to bstat

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux