Permalink
Browse files

Add statistics to vcachefs, so we can determine access patterns for

various apps
  • Loading branch information...
1 parent 2b89010 commit b157d3d7847238cf244504539b75075a505687e7 @paulcbetts committed Sep 22, 2008
Showing with 174 additions and 8 deletions.
  1. +2 −2 aclocal.m4
  2. +4 −2 src/Makefile.am
  3. +94 −0 src/stats.c
  4. +44 −0 src/stats.h
  5. +30 −4 src/vcachefs.c
View
@@ -11,8 +11,8 @@
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
-m4_if(m4_PACKAGE_VERSION, [2.61],,
-[m4_fatal([this file was generated for autoconf 2.61.
+m4_if(m4_PACKAGE_VERSION, [2.62],,
+[m4_fatal([this file was generated for autoconf 2.62.
You have another version of autoconf. If you want to use that,
you should regenerate the build system entirely.], [63])])
View
@@ -9,7 +9,9 @@ bin_PROGRAMS = vcachefs
AM_CFLAGS = -std=c99 -g -O0
-vcachefs_LDADD = $(VCACHEFS_LIBS) -lpthread
+## HACK HACK HACK: We're adding libevent here, without ever actually checking for it!
+vcachefs_LDADD = $(VCACHEFS_LIBS) -lgthread-2.0 -lpthread -levent
vcachefs_SOURCES = \
- vcachefs.c
+ vcachefs.c \
+ stats.c
View
@@ -0,0 +1,94 @@
+/*
+ * stats.c - I/O statistics
+ *
+ * Copyright 2008 Paul Betts <paul.betts@gmail.com>
+ *
+ *
+ * License:
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/statvfs.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <event.h>
+
+#include "stats.h"
+#include "config.h"
+
+#ifdef USE_IOSTATS
+
+GIOChannel* stats_open_logging(void)
+{
+ gchar* path = g_strdup_printf("/tmp/%u.csv", (unsigned int)getpid());
+ GIOChannel* ret = g_io_channel_new_file(path, "w", NULL);
+
+ if (ret) {
+ gsize dontcare;
+ g_io_channel_write_chars(ret, "Timecode, Operation, Offset, Size, Info", -1, &dontcare, NULL);
+ }
+
+ g_free(path);
+ return ret;
+}
+
+void stats_close_logging(GIOChannel* channel)
+{
+ g_io_channel_shutdown(channel, TRUE, NULL);
+}
+
+int stats_write_record(GIOChannel* channel, const char* operation, off_t offset, size_t size, const char* info)
+{
+ if (!channel)
+ return FALSE;
+
+ const char* safe_info = (info ? info : "");
+
+ gchar* buf;
+ if (sizeof(off_t) == 8) {
+ buf = g_strdup_printf("%llu, \"%s\", %llu, %u, \"%s\"", get_time_code(), operation, offset, size, safe_info);
+ } else {
+ buf = g_strdup_printf("%llu, \"%s\", %u, %u, \"%s\"", get_time_code(), operation, offset, size, safe_info);
+ }
+
+ gsize dontcare;
+ g_io_channel_write_chars(channel, buf, -1, &dontcare, NULL);
+ g_free(buf);
+ return TRUE;
+}
+
+long long unsigned int get_time_code(void)
+{
+ /* TODO: This function's resolution blows, but getting something better requires
+ * us to jump into platform-specific nonsense */
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ unsigned long long ret = t.tv_sec * 1000 * 1000 + t.tv_usec;
+ return ret;
+}
+
+#endif
View
@@ -0,0 +1,44 @@
+/*
+ * stats.h - Userspace video caching filesystem
+ *
+ * Copyright 2008 Paul Betts <paul.betts@gmail.com>
+ *
+ *
+ * License:
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _STATS_H
+#define _STATS_H
+
+#define USE_IOSTATS 1
+
+#ifndef USE_IOSTATS
+
+#define stats_open_logging() NULL
+#define stats_close_logging(x)
+#define stats_write_record(c, op, of, s, i) true
+
+#else
+
+GIOChannel* stats_open_logging(void);
+void stats_close_logging(GIOChannel* channel);
+int stats_write_record(GIOChannel* channel, const char* operation, off_t offset, size_t size, const char* info);
+long long unsigned int get_time_code(void);
+
+#endif
+
+#endif
View
@@ -32,12 +32,20 @@
#include <sys/statvfs.h>
#include <dirent.h>
#include <unistd.h>
+
#include <glib.h>
+#include <event.h>
#include "vcachefs.h"
+/* Globals */
+struct event_base* ev_base = NULL;
+GIOChannel* stats_file = NULL;
+
-/* Utility Routines */
+/*
+ * Utility Routines
+ */
static struct vcachefs_mount* get_current_mountinfo(void)
{
@@ -109,6 +117,8 @@ static int copy_file_and_return_destfd(const char* source_root, const char* dest
if (src_fd <= 0 || dest_fd <= 0)
goto out;
+ stats_write_record(stats_file, "copyfile", 0, 0, relative_path);
+
/* We've got files, let's go to town */
char buf[4096];
int has_read, has_written;
@@ -260,6 +270,9 @@ static void* vcachefs_init(struct fuse_conn_info *conn)
mount_object->file_copy_queue = g_async_queue_new();
mount_object->file_copy_thread = g_thread_create(file_cache_copy_thread, mount_object, TRUE/*joinable*/, NULL);
+ stats_write_record(stats_file, "init_source", 0, 0, mount_object->source_path);
+ stats_write_record(stats_file, "init_target", 0, 0, mount_object->cache_path);
+
return mount_object;
}
@@ -305,6 +318,7 @@ static int vcachefs_getattr(const char *path, struct stat *stbuf)
return -ENOENT;
}
+ stats_write_record(stats_file, "getattr", 0, 0, path);
if(strcmp(path, "/") == 0) {
return (stat(mount_obj->source_path, stbuf) ? -errno : 0);
}
@@ -348,6 +362,7 @@ static int vcachefs_open(const char *path, struct fuse_file_info *fi)
}
/* FUSE handles this differently */
+ stats_write_record(stats_file, "open", 0, 0, path);
return 0;
}
@@ -379,9 +394,12 @@ static int vcachefs_read(const char *path, char *buf, size_t size, off_t offset,
return -ENOENT;
/* Let's see if we can do this read from the file cache */
- if( (ret = read_from_fd(fde->filecache_fd, &fde->filecache_offset, buf, size, offset)) >= 0)
+ if( (ret = read_from_fd(fde->filecache_fd, &fde->filecache_offset, buf, size, offset)) >= 0) {
+ stats_write_record(stats_file, "cached_read", size, offset, path);
goto out;
+ }
+ stats_write_record(stats_file, "uncached_read", size, offset, path);
ret = read_from_fd(fde->source_fd, &fde->source_offset, buf, size, offset);
out:
@@ -426,9 +444,12 @@ static int vcachefs_access(const char *path, int amode)
if(path == NULL || strlen(path) == 0)
return -ENOENT;
- if(strcmp(path, "/") == 0)
+ if(strcmp(path, "/") == 0) {
+ stats_write_record(stats_file, "cached_access", amode, 0, path);
return access(mount_obj->source_path, amode);
+ }
+ stats_write_record(stats_file, "uncached_access", amode, 0, path);
gchar* full_path = g_build_filename(mount_obj->source_path, &path[1], NULL);
ret = access((char *)full_path, amode);
g_free(full_path);
@@ -476,6 +497,8 @@ static int vcachefs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
return -errno;
}
+ stats_write_record(stats_file, "readdir", offset, 0, path);
+
/* mkdir -p the cache directory */
if(strcmp(path, "/") != 0) {
char* cache_path = g_build_filename(mount_obj->cache_path, &path[1], NULL);
@@ -531,10 +554,13 @@ int main(int argc, char *argv[])
/* Check for our environment variables
* FIXME: There's got to be a less dumb way to do this */
if (!getenv("VCACHEFS_TARGET")) {
- printf(" *** Please set the VCACHEFS_TARGET environment variable to the path that"
+ printf(" *** Please set the VCACHEFS_TARGET environment variable to the path that "
"should be mirrored! ***\n");
return -1;
}
+
+ /* Initialize libevent */
+ ev_base = event_init();
return fuse_main(argc, argv, &vcachefs_oper, NULL);
}

0 comments on commit b157d3d

Please sign in to comment.