Module Name:    src
Committed By:   manu
Date:           Wed Dec 28 17:33:53 UTC 2011

Modified Files:
        src/lib/libperfuse: debug.c fuse.h ops.c perfuse.c perfuse_if.h
            perfuse_priv.h
        src/usr.sbin/perfused: perfused.8 perfused.c perfused.h

Log Message:
Add a FUSE trace facility, with statistics collection. This should help
tracking bugs and performance issues


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/lib/libperfuse/debug.c
cvs rdiff -u -r1.4 -r1.5 src/lib/libperfuse/fuse.h
cvs rdiff -u -r1.48 -r1.49 src/lib/libperfuse/ops.c
cvs rdiff -u -r1.23 -r1.24 src/lib/libperfuse/perfuse.c \
    src/lib/libperfuse/perfuse_priv.h
cvs rdiff -u -r1.17 -r1.18 src/lib/libperfuse/perfuse_if.h
cvs rdiff -u -r1.7 -r1.8 src/usr.sbin/perfused/perfused.8
cvs rdiff -u -r1.16 -r1.17 src/usr.sbin/perfused/perfused.c
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/perfused/perfused.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libperfuse/debug.c
diff -u src/lib/libperfuse/debug.c:1.5 src/lib/libperfuse/debug.c:1.6
--- src/lib/libperfuse/debug.c:1.5	Sun Oct  3 05:46:47 2010
+++ src/lib/libperfuse/debug.c	Wed Dec 28 17:33:52 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: debug.c,v 1.5 2010/10/03 05:46:47 manu Exp $ */
+/*  $NetBSD: debug.c,v 1.6 2011/12/28 17:33:52 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -26,9 +26,11 @@
  */ 
 
 #include <puffs.h>
+#include <stdio.h>
 #include <sys/types.h>
 
 #include "perfuse_if.h"
+#include "perfuse_priv.h"
 #include "fuse.h"
 
 struct perfuse_opcode {
@@ -101,3 +103,116 @@ perfuse_opname(opcode)
 
 	return po->opname; /* "UNKNOWN" */
 }
+
+char *
+perfuse_opdump_in(ps, pm)
+	struct perfuse_state *ps;
+	perfuse_msg_t *pm;
+{
+	struct fuse_in_header *fih;
+	static char buf[BUFSIZ] = "";
+
+	fih = GET_INHDR(ps, pm);
+
+	switch(fih->opcode) {
+	case FUSE_LOOKUP: 
+		(void)snprintf(buf, sizeof(buf), "path = \"%s\"", 
+			       _GET_INPAYLOAD(ps, pm, const char *));
+		break;
+	default:
+		buf[0] = '\0';
+		break;
+	}
+
+	return buf;
+}
+
+void
+perfuse_trace_dump(pu, fp)
+	struct puffs_usermount *pu;
+	FILE *fp;
+{
+	struct perfuse_state *ps;
+	struct perfuse_trace *pt;
+	struct timespec ts_min[FUSE_OPCODE_MAX];
+	struct timespec ts_max[FUSE_OPCODE_MAX];
+	struct timespec ts_total[FUSE_OPCODE_MAX];
+	int count[FUSE_OPCODE_MAX];
+	uint64_t avg;
+	int i;
+
+	if (!(perfuse_diagflags & PDF_TRACE))
+		return;
+
+	ps = puffs_getspecific(pu);
+
+	(void)ftruncate(fileno(fp), 0);
+	(void)fseek(fp, 0, SEEK_SET);
+
+	(void)memset(&ts_min, 0, sizeof(ts_min));
+	(void)memset(&ts_max, 0, sizeof(ts_max));
+	(void)memset(&ts_total, 0, sizeof(ts_total));
+	(void)memset(&count, 0, sizeof(count));
+
+	fprintf(fp, "Last %"PRId64" operations\n", ps->ps_tracecount);
+
+	TAILQ_FOREACH(pt, &ps->ps_trace, pt_list) {
+		const char *quote = pt->pt_path[0] != '\0' ? "\"" : "";
+
+		fprintf(fp, "%lu.%09ld %s %s%s%s %s ",  
+			pt->pt_start.tv_sec, pt->pt_start.tv_nsec,
+			perfuse_opname(pt->pt_opcode),
+			quote, pt->pt_path, quote,
+			pt->pt_extra);
+
+		if (pt->pt_status == done) {
+			struct timespec ts;
+
+			ts.tv_sec = 0;	/* delint */
+			ts.tv_nsec = 0;	/* delint */
+			timespecsub(&pt->pt_end, &pt->pt_start, &ts);
+
+			fprintf(fp, "error = %d elapsed = %lu.%09lu ",
+				pt->pt_error, ts.tv_sec, ts.tv_nsec);
+
+			count[pt->pt_opcode]++;
+			timespecadd(&ts_total[pt->pt_opcode],
+				    &ts,
+				    &ts_total[pt->pt_opcode]);
+
+			if (timespeccmp(&ts, &ts_min[pt->pt_opcode], <) ||
+			    (count[pt->pt_opcode] == 1))
+				ts_min[pt->pt_opcode] = ts;
+
+			if (timespeccmp(&ts, &ts_max[pt->pt_opcode], >))
+				ts_max[pt->pt_opcode] = ts;
+		} else {
+			fprintf(fp, "ongoing ");
+		}
+
+		fprintf(fp, "\n");
+	}
+
+	fprintf(fp, "\nStatistics by operation\n");
+	fprintf(fp, "operation\tcount\tmin\tavg\tmax\n");
+	for (i = 0; i < FUSE_OPCODE_MAX; i++) {
+		time_t min;
+
+		if (count[i] != 0) {
+			avg = timespec2ns(&ts_total[i]) / count[i];
+			min = ts_min[i].tv_sec;
+		} else {
+			avg = 0;
+			min = 0;
+		}
+			
+		fprintf(fp, "%s\t%d\t%ld.%09ld\t%ld.%09ld\t%ld.%09ld\t\n",
+			perfuse_opname(i), count[i],
+			min, ts_min[i].tv_nsec,
+			(time_t)(avg / 1000000000L), (long)(avg % 1000000000L),
+			ts_max[i].tv_sec, ts_max[i].tv_nsec);
+	}	
+	
+	(void)fflush(fp);
+	return;
+}

Index: src/lib/libperfuse/fuse.h
diff -u src/lib/libperfuse/fuse.h:1.4 src/lib/libperfuse/fuse.h:1.5
--- src/lib/libperfuse/fuse.h:1.4	Tue Jun 28 16:19:16 2011
+++ src/lib/libperfuse/fuse.h	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: fuse.h,v 1.4 2011/06/28 16:19:16 manu Exp $ */
+/*  $NetBSD: fuse.h,v 1.5 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -169,6 +169,7 @@ enum fuse_opcode {
 	FUSE_DESTROY       = 38,
 	FUSE_IOCTL         = 39,
 	FUSE_POLL          = 40,
+	FUSE_OPCODE_MAX,
 
 	FUSE_CUSE_INIT     = 4096
 };

Index: src/lib/libperfuse/ops.c
diff -u src/lib/libperfuse/ops.c:1.48 src/lib/libperfuse/ops.c:1.49
--- src/lib/libperfuse/ops.c:1.48	Fri Dec 16 05:34:54 2011
+++ src/lib/libperfuse/ops.c	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: ops.c,v 1.48 2011/12/16 05:34:54 manu Exp $ */
+/*  $NetBSD: ops.c,v 1.49 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -37,6 +37,7 @@
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <sys/extattr.h>
+#include <sys/time.h>
 #include <machine/vmparam.h>
 
 #include "perfuse_priv.h"
@@ -205,6 +206,8 @@ xchg_msg(pu, opc, pm, len, wait)
 {
 	struct perfuse_state *ps;
 	struct perfuse_node_data *pnd;
+	struct perfuse_trace *pt = NULL;
+	int opcode;
 	int error;
 
 	ps = puffs_getspecific(pu);
@@ -222,9 +225,62 @@ xchg_msg(pu, opc, pm, len, wait)
 	if (pnd)
 		pnd->pnd_flags |= PND_INXCHG;
 
+	/*
+	 * Record FUSE call start if requested
+	 */
+	opcode = ps->ps_get_inhdr(pm)->opcode;
+	if (perfuse_diagflags & PDF_TRACE) {
+		if ((pt = malloc(sizeof(*pt))) == NULL)
+			DERR(EX_OSERR, "malloc failed");
+
+		pt->pt_opcode = opcode;
+		pt->pt_status = inxchg;
+
+		if (opc == 0)
+			(void)strcpy(pt->pt_path, "");
+		else
+			(void)strlcpy(pt->pt_path, 
+				      perfuse_node_path(opc),
+				      sizeof(pt->pt_path));
+
+		(void)strlcpy(pt->pt_extra,
+			      perfuse_opdump_in(ps, pm),
+			      sizeof(pt->pt_extra));
+
+		if (clock_gettime(CLOCK_REALTIME, &pt->pt_start) != 0)
+			DERR(EX_OSERR, "clock_gettime failed");
+
+		TAILQ_INSERT_TAIL(&ps->ps_trace, pt, pt_list);
+		ps->ps_tracecount++;
+	}
+
+	/*
+	 * Do actual FUSE exchange
+	 */
 	if ((error = ps->ps_xchg_msg(pu, pm, len, wait)) != 0)
 		ps->ps_destroy_msg(pm);
 
+	/*
+	 * Record FUSE call end if requested
+	 */
+	if (perfuse_diagflags & PDF_TRACE) {
+		if (clock_gettime(CLOCK_REALTIME, &pt->pt_end) != 0)
+			DERR(EX_OSERR, "clock_gettime failed");
+
+		pt->pt_status = done;
+		pt->pt_error = error;
+		while (ps->ps_tracecount > PERFUSE_TRACECOUNT_MAX) {
+			struct perfuse_trace *fpt = TAILQ_FIRST(&ps->ps_trace);
+
+			if (fpt->pt_status != done)
+				break;
+
+			TAILQ_REMOVE(&ps->ps_trace, fpt, pt_list);
+			ps->ps_tracecount--;
+			free(fpt);
+		}
+	}
+
 	if (pnd) {
 		pnd->pnd_flags &= ~PND_INXCHG;
 		(void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL);

Index: src/lib/libperfuse/perfuse.c
diff -u src/lib/libperfuse/perfuse.c:1.23 src/lib/libperfuse/perfuse.c:1.24
--- src/lib/libperfuse/perfuse.c:1.23	Sun Oct 30 05:11:37 2011
+++ src/lib/libperfuse/perfuse.c	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse.c,v 1.23 2011/10/30 05:11:37 manu Exp $ */
+/*  $NetBSD: perfuse.c,v 1.24 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -64,6 +64,7 @@ init_state(void)
 	(void)memset(ps, 0, sizeof(*ps));
 	ps->ps_max_write = UINT_MAX;
 	ps->ps_max_readahead = UINT_MAX;
+	TAILQ_INIT(&ps->ps_trace);
 	
 	/*
 	 * Most of the time, access() is broken because the filesystem
Index: src/lib/libperfuse/perfuse_priv.h
diff -u src/lib/libperfuse/perfuse_priv.h:1.23 src/lib/libperfuse/perfuse_priv.h:1.24
--- src/lib/libperfuse/perfuse_priv.h:1.23	Sun Oct 30 05:11:37 2011
+++ src/lib/libperfuse/perfuse_priv.h	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse_priv.h,v 1.23 2011/10/30 05:11:37 manu Exp $ */
+/*  $NetBSD: perfuse_priv.h,v 1.24 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -37,6 +37,19 @@
 #include "perfuse_if.h"
 #include "fuse.h"
 
+#define PERFUSE_TRACECOUNT_MAX 4096
+#define PERFUSE_TRACEPATH_MAX 256
+struct perfuse_trace {
+	int pt_opcode;
+	char pt_path[PERFUSE_TRACEPATH_MAX];
+	char pt_extra[BUFSIZ];
+	int pt_error;
+	enum { inxchg, done } pt_status;
+	struct timespec pt_start;
+	struct timespec pt_end;
+	TAILQ_ENTRY(perfuse_trace) pt_list;
+};
+
 struct perfuse_state {
 	void *ps_private;	/* Private field for libperfuse user */
 	struct puffs_usermount *ps_pu;
@@ -66,6 +79,8 @@ struct perfuse_state {
 	perfuse_get_outhdr_fn ps_get_outhdr;
 	perfuse_get_outpayload_fn ps_get_outpayload;
 	perfuse_umount_fn ps_umount;
+	TAILQ_HEAD(,perfuse_trace) ps_trace;
+	uint64_t ps_tracecount;
 };
 
 
@@ -237,6 +252,8 @@ int perfuse_node_listextattr(struct puff
 int perfuse_node_deleteextattr(struct puffs_usermount *, puffs_cookie_t,
     int, const char *, const struct puffs_cred *);
 
+char *perfuse_opdump_in(struct perfuse_state *, perfuse_msg_t *);
+
 __END_DECLS
 
 #endif /* _PERFUSE_PRIV_H_ */

Index: src/lib/libperfuse/perfuse_if.h
diff -u src/lib/libperfuse/perfuse_if.h:1.17 src/lib/libperfuse/perfuse_if.h:1.18
--- src/lib/libperfuse/perfuse_if.h:1.17	Sun Oct 30 05:11:37 2011
+++ src/lib/libperfuse/perfuse_if.h	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfuse_if.h,v 1.17 2011/10/30 05:11:37 manu Exp $ */
+/*  $NetBSD: perfuse_if.h,v 1.18 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -54,6 +54,7 @@ extern int perfuse_diagflags;
 #define PDF_SYSLOG	0x0400	/* use syslog */
 #define PDF_FILENAME	0x0800	/* File names */
 #define PDF_RESIZE	0x1000	/* Resize operations */
+#define PDF_TRACE	0x2000	/* Trace FUSE calls */
 
 /*
  * Diagnostic functions
@@ -206,5 +207,6 @@ const char *perfuse_opname(int);
 void perfuse_fs_init(struct puffs_usermount *);
 int perfuse_mainloop(struct puffs_usermount *);
 int perfuse_unmount(struct puffs_usermount *);
+void perfuse_trace_dump(struct puffs_usermount *, FILE *);
 
 #endif /* _PERFUSE_IF_H */

Index: src/usr.sbin/perfused/perfused.8
diff -u src/usr.sbin/perfused/perfused.8:1.7 src/usr.sbin/perfused/perfused.8:1.8
--- src/usr.sbin/perfused/perfused.8:1.7	Fri Dec 16 12:51:43 2011
+++ src/usr.sbin/perfused/perfused.8	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-.\" $NetBSD: perfused.8,v 1.7 2011/12/16 12:51:43 wiz Exp $
+.\" $NetBSD: perfused.8,v 1.8 2011/12/28 17:33:53 manu Exp $
 .\"
 .\" Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
 .\"
@@ -118,12 +118,30 @@ is started from
 Enable debug output only when receiving
 .Li SIGINFO .
 .El
+.Sh SIGNALS
+.Bl -tag -width indent
+.It SIGINFO
+If the 
+.Fl s
+flag was used, toggle debug output. Do nothing otherwise. 
+.It SIGUSR1
+Dump FUSE operation trace to
+.Pa /var/run/perfuse.trace .
+.El
 .Sh ERRORS
 The program logs to the syslog daemon as facility
 .Dq daemon .
 For detailed debugging use the
 .Fl d
 (debug) option.
+.Sh BUGS
+When 
+.Nm
+runs in the foreground (using the
+.Fl f
+flag), some processes using the FUSE filesystem will 
+sometime hang on 
+.Sq uvn_fp2 .
 .Sh SEE ALSO
 .Xr mount 2 ,
 .Xr perfuse_mount 3 ,

Index: src/usr.sbin/perfused/perfused.c
diff -u src/usr.sbin/perfused/perfused.c:1.16 src/usr.sbin/perfused/perfused.c:1.17
--- src/usr.sbin/perfused/perfused.c:1.16	Sun Oct 23 05:03:37 2011
+++ src/usr.sbin/perfused/perfused.c	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfused.c,v 1.16 2011/10/23 05:03:37 manu Exp $ */
+/*  $NetBSD: perfused.c,v 1.17 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -50,10 +50,19 @@
 #include "../../lib/libperfuse/perfuse_if.h"
 #include "perfused.h"
 
+/*
+ * This is used for trace file. of course it will not work if
+ * we ever mount multiple filesystems in a single perfused, 
+ * but it is not sure we will ever want to do that.
+ */
+struct puffs_usermount *perfuse_mount = NULL;
+FILE *perfuse_trace = NULL;
+
 static int access_mount(const char *, uid_t, int);
 static void new_mount(int, int);
 static int parse_debug(char *);
 static void siginfo_handler(int);
+static void sigusr1_handler(int);
 static int parse_options(int, char **);
 static void get_mount_info(int, struct perfuse_mount_info *, int);
 
@@ -267,6 +276,19 @@ new_mount(int fd, int pmnt_flags)
 		DERR(EX_OSERR, "fcntl failed");
 
 	/*
+	 * Setup trace file facility
+	 */
+	perfuse_mount = pu;
+
+	if ((perfuse_trace = fopen(_PATH_VAR_RUN_PERFUSE_TRACE, "w")) == NULL)
+		DERR(EX_OSFILE, 
+		     "could not open \"%s\"",
+		     _PATH_VAR_RUN_PERFUSE_TRACE);
+
+	if (signal(SIGUSR1, sigusr1_handler) != 0)
+		DERR(EX_OSERR, "signal failed");
+
+	/*
 	 * Hand over control to puffs main loop.
 	 */
 	if (perfuse_mainloop(pu) != 0)
@@ -333,6 +355,13 @@ siginfo_handler(int sig)
 	return;
 }
 
+/* ARGSUSED0 */
+static void
+sigusr1_handler(int sig)
+{
+	return perfuse_trace_dump(perfuse_mount, perfuse_trace);
+}
+
 static int
 parse_options(int argc, char **argv)
 {
@@ -341,6 +370,9 @@ parse_options(int argc, char **argv)
 	int retval = -1;
 
 	perfuse_diagflags = PDF_FOREGROUND | PDF_SYSLOG;
+#ifdef PERFUSE_DEBUG
+	perfuse_diagflags |= PDF_TRACE;
+#endif
 
 	while ((ch = getopt(argc, argv, "d:fsi:")) != -1) {
 		switch (ch) {

Index: src/usr.sbin/perfused/perfused.h
diff -u src/usr.sbin/perfused/perfused.h:1.5 src/usr.sbin/perfused/perfused.h:1.6
--- src/usr.sbin/perfused/perfused.h:1.5	Tue Aug 30 20:17:01 2011
+++ src/usr.sbin/perfused/perfused.h	Wed Dec 28 17:33:53 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: perfused.h,v 1.5 2011/08/30 20:17:01 joerg Exp $ */
+/*  $NetBSD: perfused.h,v 1.6 2011/12/28 17:33:53 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
@@ -34,6 +34,8 @@
 
 #define PERFUSE_MSG_T struct puffs_framebuf
 
+#define _PATH_VAR_RUN_PERFUSE_TRACE "/var/run/perfuse.trace"
+
 __BEGIN_DECLS
 
 #ifdef PERFUSE_DEBUG

Reply via email to