* contrib/vmlog/vmlogfilter.c: Added a tool that filters a vmlog log file the same...
authorpm <none@none>
Sat, 2 Jun 2007 17:47:30 +0000 (17:47 +0000)
committerpm <none@none>
Sat, 2 Jun 2007 17:47:30 +0000 (17:47 +0000)
* contrib/vmlog/vmlog.c,
contrib/vmlog/vmlog.h (vmlog_thread_log_append): Made not-static.

* contrib/vmlog/Makefile.am,
configure.ac: Conditional building of vmlogfilter if ENABLE_VMLOG is set and regex.h present.

configure.ac
contrib/vmlog/Makefile.am
contrib/vmlog/vmlog.c
contrib/vmlog/vmlog.h
contrib/vmlog/vmlogfilter.c [new file with mode: 0644]

index 932e74ebae6da8cb135fe4fc80489b91b8e530c3..852e2df3b02f1c0beb1073aef1e8d3eaeda9b1d3 100644 (file)
@@ -22,7 +22,7 @@ dnl along with this program; if not, write to the Free Software
 dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 dnl 02110-1301, USA.
 dnl 
-dnl $Id: configure.ac 7996 2007-05-31 23:05:51Z twisti $
+dnl $Id: configure.ac 8001 2007-06-02 17:47:30Z pm $
 
 dnl Process this file with autoconf to produce a configure script.
 
@@ -893,10 +893,19 @@ dnl check for some programs we need
 AC_PROG_JAVAC
 AC_PROG_JAR
 
-dnl If debug build, check for regex.h. If found enable debug filter
-if test x"${NDEBUG}" = "xno"; then
-       AC_CHECK_HEADERS([regex.h], [AC_DEFINE(ENABLE_DEBUG_FILTER, 1, [debug filter])])
-fi
+AC_CHECK_HEADERS(
+       [regex.h], 
+       [
+               dnl If debug build and regex.h available, enable debug filter
+               if test x"${NDEBUG}" = "xno"; then
+                       AC_DEFINE(ENABLE_DEBUG_FILTER, 1, [debug filter])
+               fi
+               dnl If vmlog enambled and regex.h available, enable vmlogfilter
+               if test x"${ENABLE_VMLOG}" = "xyes"; then
+                       AM_CONDITIONAL([ENABLE_VMLOGFILTER], true)
+               fi
+       ]
+)
 
 dnl finally pass CFLAGS to Makefiles via AM_CFLAGS
 CFLAGS=$OPT_CFLAGS
index 0bb339c8c872c6388f75adf9592721f5b6654d80..b722a8ef54ab8dedbc3eb0524f48b8a5612153d6 100644 (file)
@@ -10,6 +10,9 @@ AM_CPPFLAGS = \
 
 if ENABLE_VMLOG
 noinst_PROGRAMS = vmlogdump vmlogindex vmlogdiff
+if ENABLE_VMLOGFILTER
+noinst_PROGRAMS += vmlogfilter
+endif
 endif
 
 COMMON_SOURCES = \
@@ -28,6 +31,10 @@ vmlogdiff_SOURCES = \
        $(COMMON_SOURCES) \
        vmlogdiff.c
 
+vmlogfilter_SOURCES = \
+       $(COMMON_SOURCES) \
+       vmlogfilter.c
+
 EXTRA_DIST = \
        COPYING \
        maintain.mk \
index c9b446133da935bc003b9102ec5c63a64ea4befe..8cfa0bc8cce9e39b0d87836792725b137ee20408 100644 (file)
@@ -490,7 +490,7 @@ static void vmlog_thread_log_realloc_frames(vmlog_thread_log *tlog,int cap)
        tlog->framescap = cap;
 }
 
-static void vmlog_thread_log_append(vmlog_thread_log *tlog,vmlog_log_entry *logent)
+void vmlog_thread_log_append(vmlog_thread_log *tlog,vmlog_log_entry *logent)
 {
 #if defined(VMLOG_ENDIAN_CONVERT_WRITE)
        unsigned int tmp;
index f93481f80847238afb9969374501c2b96ed918b8..478717eb7453ba3cb5925198df2d61e5966e8076 100644 (file)
@@ -222,6 +222,7 @@ vmlog_thread_log *vmlog_thread_log_new(vmlog_log *vml,void *threadid,int index);
 void vmlog_thread_log_free(vmlog_thread_log *tlog);
 vmlog_frame * vmlog_thread_log_enter(vmlog_thread_log *tlog,int index,vmlog_seq_t seq);
 vmlog_frame * vmlog_thread_log_leave(vmlog_thread_log *tlog,int index,vmlog_seq_t seq);
+void vmlog_thread_log_append(vmlog_thread_log *tlog,vmlog_log_entry *logent);
 
 /* string/index handling */
 int vmlog_get_string_index(vmlog_log *vml,const char *data,int len);
diff --git a/contrib/vmlog/vmlogfilter.c b/contrib/vmlog/vmlogfilter.c
new file mode 100644 (file)
index 0000000..c6944c9
--- /dev/null
@@ -0,0 +1,321 @@
+/* vmlog - high-speed logging for free VMs                  */
+/* Copyright (C) 2006 Edwin Steiner <edwin.steiner@gmx.net> */
+/*               2007 Peter Molnar <peter.molnar@wm.sk>     */
+
+/* This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "vmlog.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <regex.h>
+#include <getopt.h>
+
+char *g_idxfname;
+char *g_strfname;
+char *g_logfname;
+int g_idxlen;
+int g_strlen;
+int g_nstrings;
+vmlog_string_entry *g_idxmap;
+char *g_strmap;
+unsigned char *g_matches;
+vmlog_ringbuf *g_ringbuf = NULL;
+vmlog_log *g_log = NULL;
+vmlog_thread_log *g_thread_log = NULL;
+
+char *g_cmd = "vmlogfilter";
+
+char *opt_src_prefix = NULL;
+char *opt_dest_prefix = NULL;
+char *opt_filter_include = NULL;
+char *opt_filter_exclude = NULL;
+char *opt_src_threadidx = "0";
+char *opt_dest_threadidx = "100";
+
+#define VMLOGDUMP_RINGBUF_SIZE (16 * 1024)
+#define VMLOGDUMP_PREFETCH 1024
+#if 0
+#      define LOG(...) fprintf(stderr, "LOG: " __VA_ARGS__)
+#else
+#      define LOG(...)
+#endif
+
+#define USAGE \
+       "Usage: %s <options>\n" \
+       "\n" \
+       "Mandatory options include:\n" \
+       "\n" \
+       "\t-p <prefix>      Source prefix.\n" \
+       "\n" \
+       "Optional options include:\n" \
+       "\n" \
+       "\t-t <threadidx>   Source thread index. Defaults to 0.\n" \
+       "\t-P <prefix>      Destination prefix, defaults to source prefix.\n" \
+       "\t-T <threadidx>   Destination thread index. Defaults to 100.\n" \
+       "\t-i <regex>       Filter include.\n" \
+       "\t-x <regex>       Filter exclude.\n" \
+       "\n" 
+
+static void *xmalloc(int size) {
+       void *ret = malloc(size);
+       if (ret == NULL) {
+               vmlog_die("Malloc of size %d failed.", size);
+       }
+       return ret;
+}
+
+static void usage(int exit_status) {
+       fprintf(stderr, USAGE, g_cmd);
+       exit(exit_status);
+}
+
+static void parse_options(int argc, char **argv) {
+       int ret;
+
+       while ((ret = getopt(argc, argv, "i:x:p:t:P:T:h")) != -1) {
+               switch (ret) {
+                       case 'i':
+                               opt_filter_include = optarg;
+                               break;
+                       case 'x':
+                               opt_filter_exclude = optarg;
+                               break;
+                       case 't':
+                               opt_src_threadidx = optarg;
+                               break;
+                       case 'p':
+                               opt_src_prefix = optarg;
+                               if (opt_dest_prefix == NULL) {
+                                       opt_dest_prefix = optarg;
+                               }
+                       case 'T':
+                               opt_dest_threadidx = optarg;
+                               break;
+                       case 'P':
+                               opt_dest_prefix = optarg;
+                               break;
+                       case 'h':
+                               usage(EXIT_SUCCESS);
+                               break;
+                       default:
+                               usage(EXIT_FAILURE);
+                               break;
+               }
+       }
+
+       if ((opt_src_prefix == NULL) || (opt_dest_prefix == NULL)) {
+               usage(EXIT_FAILURE);
+       }
+}
+
+static void match_strings() {
+       regex_t regex[2];
+       char *filter[2];
+       int default_match[2] = { 1, 0 };
+       int i, err, res;
+       char err_buf[128];
+       char *str = NULL;
+       int str_size = 0;
+       vmlog_string_entry *strent;
+       unsigned char *match;
+
+       /* Initialize */
+
+       filter[0] = opt_filter_include;
+       filter[1] = opt_filter_exclude;
+
+       /* Compile regexes */
+
+       for (i = 0; i < 2; ++i) {
+               if (filter[i] != NULL) {
+                       err = regcomp(&regex[i], filter[i], REG_EXTENDED | REG_NOSUB);
+                       if (err != 0) {
+                               regerror(err, &regex[i], err_buf, sizeof(err_buf));
+                               vmlog_die(
+                                       "Invalid regex %s: %s",
+                                       filter[i], err_buf
+                               );
+                       }
+               }
+       }
+
+       /* Allocate array. For each string one byte with flags. */
+
+       g_matches = (unsigned char *)xmalloc(g_nstrings * sizeof(unsigned char));
+
+       /* Traverse strings and match */
+
+       for (strent = g_idxmap, match = g_matches; strent != g_idxmap + g_nstrings; ++strent, ++match) {
+               *match = 0;
+
+               if ((strent->len + 1) > str_size) {
+                       str_size = strent->len + 1;
+                       free(str);
+                       str = (char *)xmalloc(str_size);
+               }
+               memcpy(str, g_strmap + strent->ofs, strent->len);
+               str[strent->len] = '\0';
+
+               for (i = 0; i < 2; ++i) {
+                       if (filter[i] != NULL) {
+                               res = regexec(&regex[i], str, 0, NULL, 0);
+                               if (res == 0) {
+                                       *match |= (1 << i);
+                                       LOG("String `%s' matches regex `%d (%s)'\n", str, i, filter[i]);
+                               }
+                       } else {
+                               *match |= (default_match[i] << i);
+                       }
+               }
+       }
+}
+
+/* see src/vm/jit/show.c in the cacao source tree for documentation on the below. */
+
+#define MATCHFLAGS match_flags
+#define FILTERVERBOSECALLCTR g_ctr
+#define STATE_IS_INITIAL() ((FILTERVERBOSECALLCTR[0] == 0) && (FILTERVERBOSECALLCTR[1] == 0))
+#define STATE_IS_INCLUDE() ((FILTERVERBOSECALLCTR[0] > 0) && (FILTERVERBOSECALLCTR[1] == 0))
+#define STATE_IS_EXCLUDE() (FILTERVERBOSECALLCTR[1] > 0)
+#define EVENT_INCLUDE() (MATCHFLAGS & (1 << 0))
+#define EVENT_EXCLUDE() (MATCHFLAGS & (1 << 1))
+#define TRANSITION_NEXT_INCLUDE() ++FILTERVERBOSECALLCTR[0]
+#define TRANSITION_PREV_INCLUDE() --FILTERVERBOSECALLCTR[0]
+#define TRANSITION_NEXT_EXCLUDE() ++FILTERVERBOSECALLCTR[1]
+#define TRANSITION_PREV_EXCLUDE() --FILTERVERBOSECALLCTR[1]
+
+int g_ctr[2] = { 0, 0 };
+
+static int test_enter(unsigned char match_flags) {
+
+       int force_show = 0;
+
+       if (STATE_IS_INITIAL()) {
+               if (EVENT_INCLUDE()) {
+                       TRANSITION_NEXT_INCLUDE();
+               }
+       } else if (STATE_IS_INCLUDE()) {
+               if (EVENT_EXCLUDE()) {
+                       TRANSITION_NEXT_EXCLUDE();
+                       /* just entered exclude, show this method */
+                       force_show = 1;
+               } else if (EVENT_INCLUDE()) {
+                       TRANSITION_NEXT_INCLUDE();
+               }
+       } else if (STATE_IS_EXCLUDE()) {
+               if (EVENT_EXCLUDE()) {
+                       TRANSITION_NEXT_EXCLUDE();
+               }
+       }
+
+       return STATE_IS_INCLUDE() || force_show;
+}
+
+static int test_exit(unsigned char match_flags) {
+
+       int force_show = 0;
+
+       if (STATE_IS_INCLUDE()) {
+               if (EVENT_INCLUDE()) {
+                       TRANSITION_PREV_INCLUDE();
+                       /* just entered initial, show this method */
+                       if (STATE_IS_INITIAL()) force_show = 1;
+               }
+       } else if (STATE_IS_EXCLUDE()) {
+               if (EVENT_EXCLUDE()) {
+                       TRANSITION_PREV_EXCLUDE();
+               }
+       }
+
+       return STATE_IS_INCLUDE() || force_show;
+}
+
+static int test_other() {
+       return STATE_IS_INCLUDE();
+}
+
+static void do_filter() {
+       vmlog_log_entry *logent;
+       while ((logent = vmlog_ringbuf_next(g_ringbuf, VMLOGDUMP_PREFETCH)) != NULL) {
+               switch (logent->tag) {
+                       case VMLOG_TAG_ENTER:
+                               if (test_enter(g_matches[logent->index])) {
+                                       vmlog_thread_log_append(g_thread_log, logent);
+                                       g_thread_log->seq++;
+                               }
+                               break;
+                       case VMLOG_TAG_LEAVE:
+                               if (test_exit(g_matches[logent->index])) {
+                                       vmlog_thread_log_append(g_thread_log, logent);
+                                       g_thread_log->seq++;
+                               }
+                               break;
+                       default:
+                               if (test_other()) {
+                                       vmlog_thread_log_append(g_thread_log, logent);
+                                       g_thread_log->seq++;
+                               }
+                               break;
+               }
+       }
+}
+
+int main(int argc,char **argv) {
+
+       if (argc) {
+               vmlog_set_progname(argv[0]);
+               g_cmd = argv[0];
+       }
+
+       parse_options(argc, argv);
+
+       g_idxfname = vmlog_concat3(opt_src_prefix,"",".idx",NULL);
+       g_strfname = vmlog_concat3(opt_src_prefix,"",".str",NULL);
+       g_logfname = vmlog_concat4len(
+               opt_src_prefix, strlen(opt_src_prefix),
+               ".", 1, 
+               opt_src_threadidx, strlen(opt_src_threadidx),
+               ".log", 4,
+               NULL
+       );
+
+       g_ringbuf = vmlog_ringbuf_new(g_logfname, VMLOGDUMP_RINGBUF_SIZE);
+       g_idxmap = (vmlog_string_entry *) vmlog_file_mmap(g_idxfname,&g_idxlen);
+       g_nstrings = g_idxlen / sizeof(vmlog_string_entry);
+       g_strmap = (char *) vmlog_file_mmap(g_strfname,&g_strlen);
+
+       g_log = vmlog_log_new(opt_dest_prefix, 0);
+       g_thread_log = vmlog_thread_log_new(
+               g_log, 
+               (void *)atoi(opt_dest_threadidx), 
+               atoi(opt_dest_threadidx) 
+       );
+
+       match_strings();        
+       do_filter();
+
+       vmlog_thread_log_free(g_thread_log);
+       vmlog_log_free(g_log);
+       
+       vmlog_ringbuf_free(g_ringbuf);
+       g_ringbuf = NULL;
+       vmlog_file_munmap(g_strmap,g_strlen);
+       vmlog_file_munmap(g_idxmap,g_idxlen);
+
+       return 0;
+}
+