aboutsummaryrefslogtreecommitdiff
path: root/gfsm/gfsm/src/libgfsm/tests/seek3test.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfsm/gfsm/src/libgfsm/tests/seek3test.c')
-rw-r--r--gfsm/gfsm/src/libgfsm/tests/seek3test.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/gfsm/gfsm/src/libgfsm/tests/seek3test.c b/gfsm/gfsm/src/libgfsm/tests/seek3test.c
new file mode 100644
index 0000000..8c3e8af
--- /dev/null
+++ b/gfsm/gfsm/src/libgfsm/tests/seek3test.c
@@ -0,0 +1,611 @@
+#include <gfsm.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/*======================================================================
+ * Globals
+ */
+const char *prog = "seek2test";
+
+gfsmStateId qid_test = 0;
+guint out_degree_test;
+gulong count_test_max =
+//1024UL //==2^10
+//1048576UL //==2^20
+2097152UL //==2^21
+//4194304UL //==2^22
+//16777216UL //==2^24
+//67108864UL //==2^26
+//268435456UL //==2^28
+;
+gulong count_test=0; //-- count_test_max/out_degree
+
+/*======================================================================
+ * Label population
+ */
+
+//--------------------------------------------------------------
+// globals
+GRand *grand = NULL;
+const guint32 grand_seed = 42;
+#define GRAND_USE_SEED 1
+//#undef GRAND_USE_SEED
+
+const guint32 n_labels = 128;
+const guint32 n_states = 8192;
+
+GArray *seekus = NULL; /*-- lab = g_array_index(seekus,i); 1<=i<=count_test --*/
+GArray *seekfrom = NULL; /*-- qid = g_array_index(seekus,i); 1<=i<=count_test --*/
+
+//--------------------------------------------------------------
+// random_label()
+gfsmLabelId random_label(void) {
+ if (!grand) {
+ grand = g_rand_new();
+#ifdef GRAND_USE_SEED
+ g_rand_set_seed(grand,grand_seed);
+#endif
+ }
+ return g_rand_int_range(grand,0,n_labels);
+}
+
+//--------------------------------------------------------------
+// populate_seek_labels()
+void populate_seek_labels(void) {
+ int i;
+ gfsmLabelId lab;
+ seekus = g_array_sized_new(FALSE,TRUE,sizeof(gfsmLabelId),count_test_max);
+ for (i=0; i < count_test_max; i++) {
+ lab = random_label();
+ g_array_append_val(seekus,lab);
+ }
+}
+
+//--------------------------------------------------------------
+// random_state()
+gfsmStateId random_state(void) {
+ if (!grand) { grand = g_rand_new_with_seed(grand_seed); }
+ return g_rand_int_range(grand,0,n_states);
+}
+
+//--------------------------------------------------------------
+// populate_seek_states()
+void populate_seek_states(void) {
+ int i;
+ seekfrom = g_array_sized_new(FALSE,TRUE,sizeof(gfsmStateId),count_test_max);
+ for (i=0; i < count_test_max; i++) {
+ gfsmStateId qid = random_state();
+ g_array_append_val(seekfrom,qid);
+ }
+}
+
+
+/*======================================================================
+ * bench_seek_vanilla()
+ */
+double bench_seek_vanilla(gfsmAutomaton *fsm) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId, i);
+ gfsmLabelId lab = g_array_index(seekus, gfsmLabelId, i);
+ gfsmArcIter ai;
+ ary->len=0;
+ for (gfsm_arciter_open(&ai,fsm,qid); gfsm_arciter_ok(&ai); gfsm_arciter_next(&ai)) {
+ gfsmArc *a = gfsm_arciter_arc(&ai);
+ if (a->lower != lab) continue;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arciter_close(&ai);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_sorted()
+ */
+double bench_seek_sorted(gfsmAutomaton *fsm) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcIter ai;
+ ary->len=0;
+ for (gfsm_arciter_open(&ai,fsm,qid); gfsm_arciter_ok(&ai); gfsm_arciter_next(&ai)) {
+ gfsmArc *a = gfsm_arciter_arc(&ai);
+ if (a->lower < lab) continue;
+ if (a->lower > lab) break;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arciter_close(&ai);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_vanilla()
+ */
+double bench_seek_tabx_vanilla(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid); gfsm_arcrange_ok(&range); gfsm_arcrange_next(&range)) {
+ gfsmArc *a = gfsm_arcrange_arc(&range);
+ if (a->lower != lab) continue;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_sorted() : linear search
+ */
+double bench_seek_tabx_sorted(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid); gfsm_arcrange_ok(&range); gfsm_arcrange_next(&range)) {
+ gfsmArc *a = gfsm_arcrange_arc(&range);
+ if (a->lower < lab) continue;
+ if (a->lower > lab) break;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_sorted_2() : linear search (v2) [identical to v1]
+ */
+double bench_seek_tabx_sorted_2(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid); range.min<range.max; ++range.min) {
+ if (range.min->lower < lab) continue;
+ if (range.min->lower > lab) break;
+ g_ptr_array_add(ary, range.min);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_seek_lib() : binary search: library function
+ */
+inline void gfsm_arcrange_seek_lower(gfsmArcRange *range, gfsmLabelId find)
+{
+ g_assert(range != NULL);
+ while (gfsm_arcrange_ok(range) && gfsm_arcrange_arc(range)->lower < find)
+ gfsm_arcrange_next(range);
+}
+
+double bench_seek_tabx_seek_lib(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid), gfsm_arcrange_seek_lower(&range,lab);
+ gfsm_arcrange_ok(&range);
+ gfsm_arcrange_next(&range))
+ {
+ gfsmArc *a = gfsm_arcrange_arc(&range);
+ if (a->lower > lab) break;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_bsearch_inl() : binary search: inline function
+ */
+#define BSEARCH_CUTOFF 16
+static inline gfsmArc *bsearch_lower(gfsmArc *min, gfsmArc *max, gfsmLabelId find)
+{
+ while (min < max) {
+ gint diff = max-min;
+ if (diff < BSEARCH_CUTOFF) {
+ do {
+ if (min->lower >= find) break;
+ min++;
+ } while (min < max);
+ return min;
+ }
+ else {
+ gfsmArc *mid = min + diff/2;
+ if (mid->lower < find) min = mid+1;
+ else max = mid;
+ }
+ }
+ return min;
+}
+
+double bench_seek_tabx_bsearch_inl(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid), range.min=bsearch_lower(range.min,range.max,lab);
+ gfsm_arcrange_ok(&range);
+ gfsm_arcrange_next(&range))
+ {
+ gfsmArc *a = gfsm_arcrange_arc(&range);
+ if (a->lower > lab) break;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+/*======================================================================
+ * bench_seek_tabx_bsearch_func() : binary search: inline function
+ */
+static void bsearch_range_func(gfsmArcRange *range, gfsmLabelId find)
+{
+ gfsmArc *min=range->min, *max=range->max;
+ while (min < max) {
+ gfsmArc *mid = min + (max-min)/2;
+ if (mid->lower < find) min = mid+1;
+ else max = mid;
+ }
+ range->min = min;
+}
+
+double bench_seek_tabx_bsearch_func(gfsmArcTableIndex *tabx) {
+ guint i;
+ double elapsed;
+ GPtrArray *ary = g_ptr_array_sized_new(out_degree_test);
+ GTimer *timer = g_timer_new();
+
+ g_timer_start(timer);
+ for (i=0; i < count_test; i++) {
+ //-- BEGIN TEST CODE
+ gfsmStateId qid = g_array_index(seekfrom,gfsmStateId,i);
+ gfsmLabelId lab = g_array_index(seekus,gfsmLabelId,i);
+ gfsmArcRange range;
+ ary->len=0;
+ for (gfsm_arcrange_open_table_index(&range,tabx,qid), bsearch_range_func(&range,lab);
+ gfsm_arcrange_ok(&range);
+ gfsm_arcrange_next(&range))
+ {
+ gfsmArc *a = gfsm_arcrange_arc(&range);
+ if (a->lower > lab) break;
+ g_ptr_array_add(ary, a);
+ }
+ gfsm_arcrange_close(&range);
+ //-- END TEST CODE
+ }
+ elapsed = g_timer_elapsed(timer,NULL);
+
+ //-- cleanup
+ g_ptr_array_free(ary,TRUE);
+ g_timer_destroy(timer);
+
+ return elapsed;
+}
+
+
+/*======================================================================
+ * Report
+ */
+GString *dat_header=NULL;
+GString *dat_data=NULL;
+gint dat_row=0;
+gint dat_col=0;
+
+void report_new_row(void) {
+ fprintf(stderr, "%s: n_states=%u, n_labels=%u, out_degree=%u\n", prog, n_states, n_labels, out_degree_test);
+ //
+ //-- save data for gnuplot output
+ dat_col=0;
+ if (!dat_header) dat_header = g_string_new("");
+ if (!dat_data) dat_data = g_string_new("");
+ if (dat_row==0) {
+ g_string_append(dat_header,"#1:out_deg");
+ }
+ g_string_append_printf(dat_data, "%u", out_degree_test);
+}
+
+void report_column(char *label, double elapsed) {
+ double iters_per_sec = ((double)count_test)/elapsed;
+ //
+ //-- to stderr
+ fprintf(stderr, "BENCH[%24s]: %ld iters in %5.3f sec: %7.2e iters/sec\n",
+ label, count_test, elapsed, iters_per_sec);
+ fflush(stderr);
+ //
+ //-- to data strings
+ if (dat_row==0) {
+ g_string_append_printf(dat_header, "\t%d:%s_secs\t%d:%s_ips", (2*dat_col+2),label, (2*dat_col+3),label);
+ }
+ g_string_append_c(dat_data,'\t');
+ g_string_append_printf(dat_data,"\t%g\t%g", elapsed,iters_per_sec);
+ ++dat_col;
+}
+
+void report_end_row(void) {
+ ++dat_row;
+ g_string_append(dat_data,"\n");
+}
+
+void report_gnuplot(void) {
+ fflush(stderr);
+ printf("%s\n%s", dat_header->str, dat_data->str);
+}
+
+
+/*======================================================================
+ * Main
+ */
+//#define BENCH_VANILLA 1
+//#define BENCH_SORTED 1
+//#define BENCH_TABX_VANILLA 1
+#define BENCH_TABX_SORTED 1
+//#define BENCH_TABX_SORTED_2 1
+//#define BENCH_TABX_SEEK_LIB 1
+#define BENCH_TABX_BSEARCH_FUNC 1
+//#define BENCH_TABX_BSEARCH_INL 1
+int main(int argc, char **argv)
+{
+ char *out_degree_str="32";
+ int argi, arci, qi;
+ //
+ gfsmAutomaton *fsm=NULL;
+ double elapsed_vanilla=0;
+ //
+ gfsmAutomaton *fsm_sorted=NULL;
+ double elapsed_sorted=0;
+ //
+ gfsmArcTableIndex *tabx=NULL;
+ double elapsed_tabx_vanilla=0;
+ //
+ gfsmArcTableIndex *tabx_sorted=NULL;
+ double elapsed_tabx_sorted=0;
+ //
+ gfsmArcTableIndex *tabx_sorted_2=NULL;
+ double elapsed_tabx_sorted_2=0;
+ //
+ gfsmArcTableIndex *tabx_seek_lib=NULL;
+ double elapsed_tabx_seek_lib=0;
+ //
+ gfsmArcTableIndex *tabx_bsearch_func=NULL;
+ double elapsed_tabx_bsearch_func=0;
+ //
+ gfsmArcTableIndex *tabx_bsearch_inl=NULL;
+ double elapsed_tabx_bsearch_inl=0;
+
+ //-- sanity check
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [OUT_DEGREE(s)...]\n", prog);
+ exit(1);
+ }
+
+ //-- initialize labels to seek
+ populate_seek_labels();
+ populate_seek_states();
+
+ //-- report
+ fprintf(stderr, "%s: count_test_max=%lu\n", prog, count_test_max);
+ fflush(stderr);
+
+ //-- create: vanilla
+ fsm = gfsm_automaton_new();
+
+ //-- main loop
+ for (argi=1; argi < argc; argi++) {
+ out_degree_str = argv[argi];
+ out_degree_test = strtol(out_degree_str,NULL,0);
+ //count_test = count_test_max / out_degree_test;
+ count_test = count_test_max;
+
+ //-- populate: vanilla
+ gfsm_automaton_clear(fsm);
+ gfsm_automaton_set_root(fsm,gfsm_automaton_ensure_state(fsm,0));
+ gfsm_automaton_set_final_state_full(fsm,0,TRUE,fsm->sr->one);
+ for (qi=1; qi < n_states; qi++) {
+ gfsm_automaton_ensure_state(fsm,qi);
+ for (arci=0; arci < out_degree_test; arci++) {
+ gfsmLabelId lo = random_label();
+ gfsmLabelId hi = random_label();
+ gfsmWeight w = arci + 1.0;
+ gfsm_automaton_add_arc(fsm,qi,qi, lo,hi, w);
+ }
+ }
+
+ //-------- bench
+ report_new_row();
+
+ //-- benchmark: vanilla (twice for cache optimization)
+#ifdef BENCH_VANILLA
+ elapsed_vanilla = bench_seek_vanilla(fsm);
+ elapsed_vanilla = bench_seek_vanilla(fsm);
+ report_column("vanilla", elapsed_vanilla);
+#endif
+
+#ifdef BENCH_SORTED
+ //-- benchmark: vanilla+sorted
+ fsm_sorted = gfsm_automaton_clone(fsm);
+ gfsm_automaton_arcsort(fsm_sorted,gfsmASMLower);
+ elapsed_sorted = bench_seek_sorted(fsm_sorted);
+ elapsed_sorted = bench_seek_sorted(fsm_sorted);
+ report_column("sorted", elapsed_sorted);
+#endif
+
+#ifdef BENCH_TABX_VANILLA
+ //-- benchmark: table: vanilla
+ tabx = gfsm_automaton_to_arc_table_index(fsm,tabx);
+ elapsed_tabx_vanilla = bench_seek_tabx_vanilla(tabx);
+ elapsed_tabx_vanilla = bench_seek_tabx_vanilla(tabx);
+ report_column("tabx_vanilla", elapsed_tabx_vanilla);
+#endif
+
+#ifdef BENCH_TABX_SORTED
+ //-- benchmark: table: sorted linear
+ tabx_sorted = gfsm_automaton_to_arc_table_index(fsm,tabx_sorted);
+ gfsm_arc_table_index_priority_sort(tabx_sorted, gfsmASP_LU, fsm->sr);
+ elapsed_tabx_sorted = bench_seek_tabx_sorted(tabx_sorted);
+ elapsed_tabx_sorted = bench_seek_tabx_sorted(tabx_sorted);
+ report_column("tabx_sorted", elapsed_tabx_sorted);
+#endif
+
+#ifdef BENCH_TABX_SORTED_2
+ //-- benchmark: table: sorted linear (v2)
+ tabx_sorted_2 = gfsm_automaton_to_arc_table_index(fsm,tabx_sorted_2);
+ gfsm_arc_table_index_priority_sort(tabx_sorted_2, gfsmASP_LU, fsm->sr);
+ elapsed_tabx_sorted_2 = bench_seek_tabx_sorted_2(tabx_sorted_2);
+ elapsed_tabx_sorted_2 = bench_seek_tabx_sorted_2(tabx_sorted_2);
+ report_column("tabx_sorted_2", elapsed_tabx_sorted_2);
+#endif
+
+#ifdef BENCH_TABX_SEEK_LIB
+ //-- benchmark: table: binary search: lib
+ tabx_seek_lib = gfsm_automaton_to_arc_table_index(fsm,tabx_seek_lib);
+ gfsm_arc_table_index_priority_sort(tabx_seek_lib, gfsmASP_LU, fsm->sr);
+ elapsed_tabx_seek_lib = bench_seek_tabx_seek_lib(tabx_seek_lib);
+ elapsed_tabx_seek_lib = bench_seek_tabx_seek_lib(tabx_seek_lib);
+ report_column("tabx_seek_lib", elapsed_tabx_seek_lib);
+#endif
+
+#ifdef BENCH_TABX_BSEARCH_FUNC
+ //-- benchmark: table: binary search: func
+ tabx_bsearch_func = gfsm_automaton_to_arc_table_index(fsm,tabx_bsearch_func);
+ gfsm_arc_table_index_priority_sort(tabx_bsearch_func, gfsmASP_LU, fsm->sr);
+ elapsed_tabx_bsearch_func = bench_seek_tabx_bsearch_func(tabx_bsearch_func);
+ elapsed_tabx_bsearch_func = bench_seek_tabx_bsearch_func(tabx_bsearch_func);
+ report_column("tabx_bsearch_func", elapsed_tabx_bsearch_func);
+#endif
+
+#ifdef BENCH_TABX_BSEARCH_INL
+ //-- benchmark: table: binary search: inline
+ tabx_bsearch_inl = gfsm_automaton_to_arc_table_index(fsm,tabx_bsearch_inl);
+ gfsm_arc_table_index_priority_sort(tabx_bsearch_inl, gfsmASP_LU, fsm->sr);
+ elapsed_tabx_bsearch_inl = bench_seek_tabx_bsearch_inl(tabx_bsearch_inl);
+ elapsed_tabx_bsearch_inl = bench_seek_tabx_bsearch_inl(tabx_bsearch_inl);
+ report_column("tabx_bsearch_inl", elapsed_tabx_bsearch_inl);
+#endif
+
+ report_end_row();
+ }
+
+ //-- gnuplot output
+ report_gnuplot();
+
+ //-- cleanup
+ if (fsm) gfsm_automaton_free(fsm);
+ if (fsm_sorted) gfsm_automaton_free(fsm_sorted);
+ if (tabx) gfsm_arc_table_index_free(tabx);
+ if (tabx_sorted) gfsm_arc_table_index_free(tabx_sorted);
+ if (tabx_sorted_2) gfsm_arc_table_index_free(tabx_sorted_2);
+
+ return 0;
+}