Skip to content

Instantly share code, notes, and snippets.

@ddk50
Created February 18, 2012 13:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ddk50/1859316 to your computer and use it in GitHub Desktop.
Save ddk50/1859316 to your computer and use it in GitHub Desktop.
Bayse統計をつかった統計的デバッグ支援ツール
diff --git a/Makefile.in b/Makefile.in
index 6b12187..9a6e1b8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -59,7 +59,7 @@ CPPFLAGS = @CPPFLAGS@ $(INCFLAGS)
LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
EXTLDFLAGS =
XLDFLAGS = @XLDFLAGS@ $(EXTLDFLAGS)
-EXTLIBS =
+EXTLIBS = -lgsl -lgslcblas
LIBS = @LIBS@ $(EXTLIBS)
MISSING = @LIBOBJS@ @ALLOCA@
LDSHARED = @LIBRUBY_LDSHARED@
diff --git a/eval.c b/eval.c
index ddbe31a..ae6c0ea 100644
--- a/eval.c
+++ b/eval.c
@@ -1174,6 +1174,8 @@ rb_f_method_name(void)
}
}
+void ruby_bayse_define_class(void);
+
void
Init_eval(void)
{
@@ -1213,3 +1215,121 @@ Init_eval(void)
OBJ_TAINT(exception_error);
OBJ_FREEZE(exception_error);
}
+
+VALUE bayse_hash_sfn_to_ler;
+VALUE cBayse;
+
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_sf.h>
+#include <gsl/gsl_rng.h>
+#include <gsl/gsl_randist.h>
+
+double
+kl_divergence(double a, double b,
+ double c, double d)
+{
+ double val = gsl_sf_beta(a, b) / gsl_sf_beta(c, d);
+ double ret =
+ log(val) + ((c - a) * (gsl_sf_psi_int(c) - gsl_sf_psi_int(c + d)))
+ + ((d - b) * (gsl_sf_psi_int(d) - gsl_sf_psi_int(c + d)));
+ return ret;
+}
+
+VALUE
+bayse_func_m_kl_divergence(VALUE self,
+ VALUE a,
+ VALUE b,
+ VALUE c,
+ VALUE d)
+{
+ double ret;
+ ret = kl_divergence(NUM2DBL(a), NUM2DBL(b), NUM2DBL(c), NUM2DBL(d));
+ return DBL2NUM(ret);
+}
+
+VALUE
+bayse_func_m_results(VALUE self)
+{
+ return bayse_hash_sfn_to_ler;
+}
+
+VALUE
+bayse_func_m_clearlog(VALUE self)
+{
+ bayse_hash_sfn_to_ler = Qnil;
+ bayse_hash_sfn_to_ler = rb_hash_new();
+ rb_gc_register_mark_object(bayse_hash_sfn_to_ler);
+}
+
+VALUE
+bayse_func_m_start_logging(VALUE self)
+{
+ ID prof_id = 0;
+ prof_id = rb_intern("BayseProf");
+}
+
+VALUE
+bayse_func_m_stop_logging(VALUE self)
+{
+ ID prof_id = 0;
+ prof_id = rb_intern("BayseProf");
+}
+
+/*
+ a = Bayse.results
+ a.each do |bayse|
+ # do something
+ end
+*/
+
+void
+Init_Bayse(void)
+{
+ bayse_hash_sfn_to_ler = rb_hash_new();
+ rb_gc_register_mark_object(bayse_hash_sfn_to_ler);
+
+ cBayse = rb_define_class("Bayse", rb_cObject);
+
+ rb_define_singleton_method(cBayse, "start", bayse_func_m_start_logging, 0);
+ rb_define_singleton_method(cBayse, "stop", bayse_func_m_stop_logging, 0);
+ rb_define_singleton_method(cBayse, "results", bayse_func_m_results, 0);
+ rb_define_singleton_method(cBayse, "clearlog", bayse_func_m_clearlog, 0);
+ rb_define_singleton_method(cBayse, "kldivergence", bayse_func_m_kl_divergence, 4);
+}
+
+/* kazushi addition */
+VALUE
+ruby_logging_branch(int unless, rb_control_frame_t *reg_cfp)
+{
+ static ID prof_id = 0;
+ VALUE sfn_to_ler, conds, ret;
+
+ prof_id = rb_intern("BayseProf");
+
+ /* rb_const_defは遅いhashを引いている */
+ /* 例えば:ProfileをONにすると、定義されているbranchunlessを全部俺のブランチアクセスバイトコードに変える */
+ /* 2種類ある:すでに生成されているバイトコードを書き換える方法と、これから生成されるやるも書き換える。 */
+
+ if (rb_const_defined(rb_cObject, prof_id) == Qfalse ||
+ rb_const_get(rb_cObject, prof_id) == Qfalse) {
+ return;
+ } else {
+ sfn_to_ler = rb_hash_lookup(bayse_hash_sfn_to_ler, reg_cfp->iseq->filename);
+ if (sfn_to_ler == Qnil) {
+ sfn_to_ler = rb_hash_new();
+ rb_gc_register_mark_object(sfn_to_ler);
+ rb_hash_aset(bayse_hash_sfn_to_ler, reg_cfp->iseq->filename, sfn_to_ler);
+ }
+
+ conds = rb_hash_lookup(sfn_to_ler, LONG2FIX(rb_vm_get_sourceline(reg_cfp)));
+ if (conds == Qnil) {
+ conds = rb_ary_new();
+ rb_gc_register_mark_object(conds);
+ rb_hash_aset(sfn_to_ler, LONG2FIX(rb_vm_get_sourceline(reg_cfp)), conds);
+ }
+
+ ret = unless ? INT2FIX(0) : INT2FIX(1);
+ rb_ary_push(conds, ret);
+ }
+}
+
diff --git a/inits.c b/inits.c
index 73b9eb4..bf81e6d 100644
--- a/inits.c
+++ b/inits.c
@@ -60,5 +60,6 @@ rb_call_inits(void)
CALL(Rational);
CALL(Complex);
CALL(version);
+ CALL(Bayse);
}
#undef CALL
diff --git a/insns.def b/insns.def
index 2b4c3db..87149eb 100644
--- a/insns.def
+++ b/insns.def
@@ -1164,9 +1164,12 @@ branchif
()
{
if (RTEST(val)) {
+ ruby_logging_branch(0, GET_CFP());
RUBY_VM_CHECK_INTS();
JUMP(dst);
- }
+ } else {
+ ruby_logging_branch(1, GET_CFP());
+ }
}
/**
@@ -1180,9 +1183,12 @@ branchunless
(VALUE val)
()
{
- if (!RTEST(val)) {
+ if (!RTEST(val)) {
+ ruby_logging_branch(1, GET_CFP());
RUBY_VM_CHECK_INTS();
JUMP(dst);
+ } else {
+ ruby_logging_branch(0, GET_CFP());
}
}
diff --git a/vm_core.h b/vm_core.h
index d44bd25..ba11a5d 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -749,6 +749,9 @@ extern VALUE rb_get_coverages(void);
extern void rb_set_coverages(VALUE);
extern void rb_reset_coverages(void);
+extern VALUE ruby_logging_branch(int unless,
+ rb_control_frame_t *reg_cfp);
+
#if defined __GNUC__ && __GNUC__ >= 4
#pragma GCC visibility pop
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment