Module Name:    src
Committed By:   yamt
Date:           Fri Dec  9 15:17:34 UTC 2011

Added Files:
        src/usr.bin/fincore: Makefile fincore.1 fincore.c

Log Message:
a utility to show in-core status of file pages


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/usr.bin/fincore/Makefile \
    src/usr.bin/fincore/fincore.1 src/usr.bin/fincore/fincore.c

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

Added files:

Index: src/usr.bin/fincore/Makefile
diff -u /dev/null src/usr.bin/fincore/Makefile:1.1
--- /dev/null	Fri Dec  9 15:17:35 2011
+++ src/usr.bin/fincore/Makefile	Fri Dec  9 15:17:34 2011
@@ -0,0 +1,5 @@
+#	$NetBSD: Makefile,v 1.1 2011/12/09 15:17:34 yamt Exp $
+
+PROG=	fincore
+
+.include <bsd.prog.mk>
Index: src/usr.bin/fincore/fincore.1
diff -u /dev/null src/usr.bin/fincore/fincore.1:1.1
--- /dev/null	Fri Dec  9 15:17:35 2011
+++ src/usr.bin/fincore/fincore.1	Fri Dec  9 15:17:34 2011
@@ -0,0 +1,103 @@
+.\"	$NetBSD: fincore.1,v 1.1 2011/12/09 15:17:34 yamt Exp $
+.\"
+.\" Copyright (c)2011 YAMAMOTO Takashi,
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" ------------------------------------------------------------
+.Dd December 9, 2011
+.Dt FINCORE 1
+.Os
+.\" ------------------------------------------------------------
+.Sh NAME
+.Nm fincore
+.Nd query in-core status of file pages
+.\" ------------------------------------------------------------
+.Sh SYNOPSIS
+.Nm
+.Op Fl qs
+.Ar file ...
+.\" ------------------------------------------------------------
+.Sh DESCRIPTION
+The
+.Nm
+utility queries and displays in-core status of specified files.
+.Pp
+Note that the result can already be stale when being output due to other
+activities in the system.
+Thus it should be used only for advisary purposes.
+.Pp
+The
+.Nm
+utility accepts the following options.
+.Bl -tag -width hogehoge
+.It Fl q
+The quiet mode.
+Outputs nothing unless the file has in-core pages.
+.It Fl s
+The summary mode.
+Only shows number of pages.
+.El
+.\" ------------------------------------------------------------
+.Sh EXAMPLES
+The following example shows that /bin/cat and /bin/cp are fully cached in-core
+while the other executables are not in-core.
+numbers shown in the default output are page indexes in the file of
+each in-core pages.
+.Bd -literal
+% fincore /bin/c*
+/bin/cat: 0 1 2 3
+/bin/chio:
+/bin/chmod:
+/bin/cp: 0 1 2 3 4 5
+/bin/cpio:
+/bin/csh:
+% fincore -s /bin/c*
+/bin/cat: 4 / 4 in-core pages (100.00%)
+/bin/chio: 0 / 5 in-core pages (0.00%)
+/bin/chmod: 0 / 3 in-core pages (0.00%)
+/bin/cp: 6 / 6 in-core pages (100.00%)
+/bin/cpio: 0 / 36 in-core pages (0.00%)
+/bin/csh: 0 / 41 in-core pages (0.00%)
+.Ed
+.\" ------------------------------------------------------------
+.\".Sh HISTORY
+.\"The
+.\".Nm
+.\"utility first appeared in
+.\".Nx XXX .
+.\" ------------------------------------------------------------
+.\".Sh SEE ALSO
+.\".Xr XXX
+.\" ------------------------------------------------------------
+.Sh AUTHORS
+The
+.Nm
+utility is written by
+.An YAMAMOTO Takashi .
+.\" ------------------------------------------------------------
+.Sh BUGS
+The amount of CPU time the current implementation of
+.Nm
+utility would take is roughly proportional to the file sizes.
+Ideally it should be proportional to the number of in-core pages.
Index: src/usr.bin/fincore/fincore.c
diff -u /dev/null src/usr.bin/fincore/fincore.c:1.1
--- /dev/null	Fri Dec  9 15:17:35 2011
+++ src/usr.bin/fincore/fincore.c	Fri Dec  9 15:17:34 2011
@@ -0,0 +1,211 @@
+/*	$NetBSD: fincore.c,v 1.1 2011/12/09 15:17:34 yamt Exp $	*/
+
+/*-
+ * Copyright (c) 2011 YAMAMOTO Takashi,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * a utility to query which file pages are cached
+ *
+ * inspired by:
+ * 	http://net.doit.wisc.edu/~plonka/fincore/
+ * 	http://www.usenix.org/events/lisa07/tech/plonka.html
+ */
+
+#include <sys/cdefs.h>
+#if defined(__NetBSD__)
+#ifndef lint
+__RCSID("$NetBSD: fincore.c,v 1.1 2011/12/09 15:17:34 yamt Exp $");
+#endif /* not lint */
+#endif /* defined(__NetBSD__) */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(__arraycount)
+#define	__arraycount(a)	(sizeof(a)/sizeof(*a))
+#endif /* !defined(__arraycount) */
+
+size_t page_size;
+bool do_summary;
+bool be_quiet;
+
+/*
+ * fincore: query which pages of the file are in-core.
+ *
+ * this function is intended to be compatible with:
+ * 	http://lwn.net/Articles/371538/
+ * 	http://libprefetch.cs.ucla.edu/
+ *
+ * while this can be implemented in kernel much more efficiently, i'm not
+ * sure if making this a syscall in 2011 is a good idea.  this API does not
+ * seem scalable for sparsely cached huge files.  the expected scalability
+ * has been changed since the time when mincore was invented.
+ *
+ * some references:
+ * 	http://wiki.postgresql.org/images/a/a2/Pgfincore_pgday10.pdf
+ */
+
+static int
+fincore(int fd, off_t startoff, off_t endoff, unsigned char *vec)
+{
+	off_t off;
+	size_t chunk_size;
+
+	for (off = startoff; off < endoff;
+	    off += chunk_size, vec += chunk_size / page_size) {
+		void *vp;
+
+		chunk_size = MIN((off_t)(1024 * page_size), endoff - off);
+		vp = mmap(NULL, chunk_size, PROT_NONE, MAP_FILE|MAP_SHARED,
+		    fd, off);
+		if (vp == MAP_FAILED) {
+			return -1;
+		}
+		if (mincore(vp, chunk_size,
+#if !defined(__linux__)
+		    (char *)
+#endif /* !defined(__linux__) */
+		    vec)) {
+			munmap(vp, chunk_size);
+			return -1;
+		}
+		if (munmap(vp, chunk_size)) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void
+do_file(const char *name)
+{
+	unsigned char vec[4096];
+	struct stat st;
+	uintmax_t n;	/* number of pages in-core */
+	off_t off;
+	size_t chunk_size;
+	int fd;
+	bool header_done = false;
+
+	fd = open(name, O_RDONLY);
+	if (fd == -1) {
+		err(EXIT_FAILURE, "open %s", name);
+	}
+	if (fstat(fd, &st)) {
+		err(EXIT_FAILURE, "fstat %s", name);
+	}
+	n = 0;
+	for (off = 0; off < st.st_size; off += chunk_size) {
+		unsigned int i;
+
+		chunk_size = MIN(__arraycount(vec) * page_size,
+		    roundup(st.st_size - off, page_size));
+		if (fincore(fd, off, off + chunk_size, vec)) {
+			printf("\n");
+			err(EXIT_FAILURE, "fincore %s", name);
+		}
+		for (i = 0; i < chunk_size / page_size; i++) {
+			if (vec[i] == 0) {
+				continue;
+			}
+			if (!do_summary) {
+				if (!header_done) {
+					printf("%s:", name);
+					header_done = true;
+				}
+				printf(" %ju",
+				    (uintmax_t)(off / page_size + i));
+			}
+			n++;
+		}
+	}
+	close(fd);
+	if (do_summary && (n != 0 || !be_quiet)) {
+		const uintmax_t total = howmany(st.st_size, page_size);
+		const double pct = (total != 0) ? ((double)n / total * 100) : 0;
+
+		if (!header_done) {
+			printf("%s:", name);
+			header_done = true;
+		}
+		printf(" %ju / %ju in-core pages (%0.2f%%)", n, total, pct);
+	}
+	if (header_done) {
+		printf("\n");
+	} else if (!be_quiet) {
+		printf("%s: \n", name);
+	}
+}
+
+int
+/*ARGSUSED*/
+main(int argc, char *argv[])
+{
+	extern int optind;
+	long l;
+	int ch;
+
+	while ((ch = getopt(argc, argv, "sq")) != -1) {
+		switch (ch) {
+		case 's':
+			do_summary = true;
+			break;
+		case 'q':
+			be_quiet = true;
+			break;
+		default:
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	l = sysconf(_SC_PAGESIZE);
+	if (l == -1) {
+		/*
+		 * sysconf doesn't always set errno.  bad API.
+		 */
+		errx(EXIT_FAILURE, "_SC_PAGESIZE");
+	}
+	page_size = (size_t)l;
+
+	argc -= optind;
+	argv += optind;
+	while (argc > 0) {
+		do_file(argv[0]);
+		argc--;
+		argv++;
+	}
+	return EXIT_SUCCESS;
+}

Reply via email to