/************************************************************************ ** ** ** The YapTab/YapOr/OPTYap systems ** ** ** ** YapTab extends the Yap Prolog engine to support sequential tabling ** ** YapOr extends the Yap Prolog engine to support or-parallelism ** ** OPTYap extends the Yap Prolog engine to support or-parallel tabling ** ** ** ** ** ** Yap Prolog was developed at University of Porto, Portugal ** ** ** ************************************************************************/ /************************************ ** Includes & Prototypes ** ************************************/ #include "Yap.h" #if defined(YAPOR) || defined(TABLING) #include "Yatom.h" #include "YapHeap.h" #include "SWI-Prolog.h" #ifdef YAPOR #if HAVE_STRING_H #include #endif /* HAVE_STRING_H */ #if HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ #include "or.macros.h" #endif /* YAPOR */ #ifdef TABLING #include "tab.macros.h" #endif /* TABLING */ #ifdef TABLING static Int p_freeze_choice_point( USES_REGS1 ); static Int p_wake_choice_point( USES_REGS1 ); static Int p_abolish_frozen_choice_points_until( USES_REGS1 ); static Int p_abolish_frozen_choice_points_all( USES_REGS1 ); static Int p_table( USES_REGS1 ); static Int p_tabling_mode( USES_REGS1 ); static Int p_abolish_table( USES_REGS1 ); static Int p_abolish_all_tables( USES_REGS1 ); static Int p_show_tabled_predicates( USES_REGS1 ); static Int p_show_table( USES_REGS1 ); static Int p_show_all_tables( USES_REGS1 ); static Int p_show_global_trie( USES_REGS1 ); static Int p_show_statistics_table( USES_REGS1 ); static Int p_show_statistics_tabling( USES_REGS1 ); static Int p_show_statistics_global_trie( USES_REGS1 ); #endif /* TABLING */ #ifdef YAPOR static Int p_parallel_mode( USES_REGS1 ); static Int p_yapor_start( USES_REGS1 ); static Int p_yapor_workers( USES_REGS1 ); static Int p_worker( USES_REGS1 ); static Int p_parallel_new_answer( USES_REGS1 ); static Int p_parallel_get_answers( USES_REGS1 ); static Int p_show_statistics_or( USES_REGS1 ); #endif /* YAPOR */ #if defined(YAPOR) && defined(TABLING) static Int p_show_statistics_opt( USES_REGS1 ); #endif /* YAPOR && TABLING */ static Int p_get_optyap_statistics( USES_REGS1 ); #ifdef YAPOR static inline realtime current_time(void); #endif /* YAPOR */ #ifdef TABLING static inline struct page_statistics show_statistics_table_entries(IOSTREAM *out); #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) static inline struct page_statistics show_statistics_subgoal_entries(IOSTREAM *out); #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ static inline struct page_statistics show_statistics_subgoal_frames(IOSTREAM *out); static inline struct page_statistics show_statistics_dependency_frames(IOSTREAM *out); static inline struct page_statistics show_statistics_subgoal_trie_nodes(IOSTREAM *out); static inline struct page_statistics show_statistics_subgoal_trie_hashes(IOSTREAM *out); static inline struct page_statistics show_statistics_answer_trie_nodes(IOSTREAM *out); static inline struct page_statistics show_statistics_answer_trie_hashes(IOSTREAM *out); #if defined(THREADS_FULL_SHARING) static inline struct page_statistics show_statistics_answer_ref_nodes(IOSTREAM *out); #endif /* THREADS_FULL_SHARING */ static inline struct page_statistics show_statistics_global_trie_nodes(IOSTREAM *out); static inline struct page_statistics show_statistics_global_trie_hashes(IOSTREAM *out); #endif /* TABLING */ #ifdef YAPOR static inline struct page_statistics show_statistics_or_frames(IOSTREAM *out); static inline struct page_statistics show_statistics_query_goal_solution_frames(IOSTREAM *out); static inline struct page_statistics show_statistics_query_goal_answer_frames(IOSTREAM *out); #endif /* YAPOR */ #if defined(YAPOR) && defined(TABLING) static inline struct page_statistics show_statistics_suspension_frames(IOSTREAM *out); #ifdef TABLING_INNER_CUTS static inline struct page_statistics show_statistics_table_subgoal_solution_frames(IOSTREAM *out); static inline struct page_statistics show_statistics_table_subgoal_answer_frames(IOSTREAM *out); #endif /* TABLING_INNER_CUTS */ #endif /* YAPOR && TABLING */ /************************************ ** Macros & Declarations ** ************************************/ struct page_statistics { #ifdef USE_PAGES_MALLOC long pages_in_use; /* same as struct pages (opt.structs.h) */ #endif /* USE_PAGES_MALLOC */ long structs_in_use; /* same as struct pages (opt.structs.h) */ long bytes_in_use; }; #define PgEnt_bytes_in_use(STATS) STATS.bytes_in_use #ifdef USE_PAGES_MALLOC #ifdef DEBUG_TABLING #define CHECK_PAGE_FREE_STRUCTS(STR_TYPE, PAGE) \ { pg_hd_ptr pg_hd; \ STR_TYPE *aux_ptr; \ long cont = 0; \ pg_hd = PgEnt_first(PAGE); \ while (pg_hd) { \ aux_ptr = PgHd_first_str(pg_hd); \ while (aux_ptr) { \ cont++; \ aux_ptr = aux_ptr->next; \ } \ pg_hd = PgHd_next(pg_hd); \ } \ TABLING_ERROR_CHECKING(CHECK_PAGE_FREE_STRUCTS, PgEnt_strs_free(PAGE) != cont); \ } #else #define CHECK_PAGE_FREE_STRUCTS(STR_TYPE, PAGE) #endif /* DEBUG_TABLING */ #define INIT_PAGE_STATS(STATS) \ PgEnt_pages_in_use(STATS) = 0; \ PgEnt_strs_in_use(STATS) = 0 #define INCREMENT_PAGE_STATS(STATS, PAGE) \ PgEnt_pages_in_use(STATS) += PgEnt_pages_in_use(PAGE); \ PgEnt_strs_in_use(STATS) += PgEnt_strs_in_use(PAGE) #define INCREMENT_AUX_STATS(STATS, BYTES, PAGES) \ BYTES += PgEnt_bytes_in_use(STATS); \ PAGES += PgEnt_pages_in_use(STATS) #define SHOW_PAGE_STATS_MSG(STR_NAME) " " STR_NAME " %10ld bytes (%ld pages and %ld structs in use)\n" #define SHOW_PAGE_STATS_ARGS(STATS, STR_TYPE) PgEnt_strs_in_use(STATS) * sizeof(STR_TYPE), PgEnt_pages_in_use(STATS), PgEnt_strs_in_use(STATS) #else /* !USE_PAGES_MALLOC */ #define CHECK_PAGE_FREE_STRUCTS(STR_TYPE, PAGE) #define INIT_PAGE_STATS(STATS) \ PgEnt_strs_in_use(STATS) = 0 #define INCREMENT_PAGE_STATS(STATS, PAGE) \ PgEnt_strs_in_use(STATS) += PgEnt_strs_in_use(PAGE) #define INCREMENT_AUX_STATS(STATS, BYTES, PAGES) \ BYTES += PgEnt_bytes_in_use(STATS) #define SHOW_PAGE_STATS_MSG(STR_NAME) " " STR_NAME " %10ld bytes (%ld structs in use)\n" #define SHOW_PAGE_STATS_ARGS(STATS, STR_TYPE) PgEnt_strs_in_use(STATS) * sizeof(STR_TYPE), PgEnt_strs_in_use(STATS) #endif /* USE_PAGES_MALLOC */ #ifdef THREADS #define GET_ALL_PAGE_STATS(STATS, STR_TYPE, _PAGES) \ LOCK(GLOBAL_ThreadHandlesLock); \ CHECK_PAGE_FREE_STRUCTS(STR_TYPE, GLOBAL##_PAGES); \ INCREMENT_PAGE_STATS(STATS, GLOBAL##_PAGES); \ { int wid; \ for (wid = 0; wid < MAX_THREADS; wid++) { \ if (! Yap_local[wid]) \ break; \ if (REMOTE_ThreadHandle(wid).in_use) { \ CHECK_PAGE_FREE_STRUCTS(STR_TYPE, REMOTE##_PAGES(wid)); \ INCREMENT_PAGE_STATS(STATS, REMOTE##_PAGES(wid)); \ } \ } \ } \ UNLOCK(GLOBAL_ThreadHandlesLock) #else #define GET_ALL_PAGE_STATS(STATS, STR_TYPE, _PAGES) \ CHECK_PAGE_FREE_STRUCTS(STR_TYPE, GLOBAL##_PAGES); \ INCREMENT_PAGE_STATS(STATS, GLOBAL##_PAGES) #endif #define GET_PAGE_STATS(STATS, STR_TYPE, _PAGES) \ INIT_PAGE_STATS(STATS); \ GET_ALL_PAGE_STATS(STATS, STR_TYPE, _PAGES); \ PgEnt_bytes_in_use(STATS) = PgEnt_strs_in_use(STATS) * sizeof(STR_TYPE) #define SHOW_PAGE_STATS(OUT_STREAM, STR_TYPE, _PAGES, STR_NAME) \ { struct page_statistics stats; \ GET_PAGE_STATS(stats, STR_TYPE, _PAGES); \ Sfprintf(OUT_STREAM, SHOW_PAGE_STATS_MSG(STR_NAME), SHOW_PAGE_STATS_ARGS(stats, STR_TYPE)); \ return stats; \ } /******************************* ** Global functions ** *******************************/ void Yap_init_optyap_preds(void) { #ifdef TABLING Yap_InitCPred("freeze_choice_point", 1, p_freeze_choice_point, SafePredFlag|SyncPredFlag); Yap_InitCPred("wake_choice_point", 1, p_wake_choice_point, SafePredFlag|SyncPredFlag); Yap_InitCPred("abolish_frozen_choice_points", 1, p_abolish_frozen_choice_points_until, SafePredFlag|SyncPredFlag); Yap_InitCPred("abolish_frozen_choice_points", 0, p_abolish_frozen_choice_points_all, SafePredFlag|SyncPredFlag); Yap_InitCPred("$c_table", 3, p_table, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_tabling_mode", 3, p_tabling_mode, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_abolish_table", 2, p_abolish_table, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("abolish_all_tables", 0, p_abolish_all_tables, SafePredFlag|SyncPredFlag); Yap_InitCPred("show_tabled_predicates", 1, p_show_tabled_predicates, SafePredFlag|SyncPredFlag); Yap_InitCPred("$c_show_table", 3, p_show_table, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("show_all_tables", 1, p_show_all_tables, SafePredFlag|SyncPredFlag); Yap_InitCPred("show_global_trie", 1, p_show_global_trie, SafePredFlag|SyncPredFlag); Yap_InitCPred("$c_table_statistics", 3, p_show_statistics_table, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("tabling_statistics", 1, p_show_statistics_tabling, SafePredFlag|SyncPredFlag); Yap_InitCPred("global_trie_statistics", 1, p_show_statistics_global_trie, SafePredFlag|SyncPredFlag); #endif /* TABLING */ #ifdef YAPOR Yap_InitCPred("parallel_mode", 1, p_parallel_mode, SafePredFlag|SyncPredFlag); Yap_InitCPred("$c_yapor_start", 0, p_yapor_start, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_yapor_workers", 1, p_yapor_workers, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_worker", 0, p_worker, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_parallel_new_answer", 1, p_parallel_new_answer, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("$c_parallel_get_answers", 1, p_parallel_get_answers, SafePredFlag|SyncPredFlag|HiddenPredFlag); Yap_InitCPred("or_statistics", 1, p_show_statistics_or, SafePredFlag|SyncPredFlag); #endif /* YAPOR */ #if defined(YAPOR) && defined(TABLING) Yap_InitCPred("opt_statistics", 1, p_show_statistics_opt, SafePredFlag|SyncPredFlag); #endif /* YAPOR && TABLING */ Yap_InitCPred("$c_get_optyap_statistics", 3, p_get_optyap_statistics, SafePredFlag|SyncPredFlag|HiddenPredFlag); } #ifdef YAPOR void finish_yapor(void) { GLOBAL_execution_time = current_time() - GLOBAL_execution_time; GLOBAL_parallel_mode = PARALLEL_MODE_ON; return; } #endif /* YAPOR */ /*********************************** ** Tabling C Predicates ** ***********************************/ #ifdef TABLING static Int p_freeze_choice_point( USES_REGS1 ) { if (IsVarTerm(Deref(ARG1))) { Int offset = freeze_current_cp(); return Yap_unify(ARG1, MkIntegerTerm(offset)); } return (FALSE); } static Int p_wake_choice_point( USES_REGS1 ) { Term term_offset = Deref(ARG1); if (IsIntegerTerm(term_offset)) wake_frozen_cp(IntegerOfTerm(term_offset)); return (FALSE); } static Int p_abolish_frozen_choice_points_until( USES_REGS1 ) { Term term_offset = Deref(ARG1); if (IsIntegerTerm(term_offset)) abolish_frozen_cps_until(IntegerOfTerm(term_offset)); return (TRUE); } static Int p_abolish_frozen_choice_points_all( USES_REGS1 ) { abolish_frozen_cps_all(); return (TRUE); } static Int p_table( USES_REGS1 ) { Term mod, t, list; PredEntry *pe; Atom at; int arity; tab_ent_ptr tab_ent; #ifdef MODE_DIRECTED_TABLING int* mode_directed = NULL; #endif /* MODE_DIRECTED_TABLING */ mod = Deref(ARG1); t = Deref(ARG2); list = Deref(ARG3); if (IsAtomTerm(t)) { at = AtomOfTerm(t); pe = RepPredProp(PredPropByAtom(at, mod)); arity = 0; } else if (IsApplTerm(t)) { at = NameOfFunctor(FunctorOfTerm(t)); pe = RepPredProp(PredPropByFunc(FunctorOfTerm(t), mod)); arity = ArityOfFunctor(FunctorOfTerm(t)); } else return (FALSE); if (list != TermNil) { /* non-empty list */ #ifndef MODE_DIRECTED_TABLING Yap_Error(INTERNAL_COMPILER_ERROR, TermNil, "invalid tabling declaration for %s/%d (mode directed tabling not enabled)", AtomName(at), arity); return(FALSE); #else int pos_index = 0; int pos_agreg = 0; /* min/max */ int pos_first = 0; int pos_all = 0; int pos_last = 0; int i; int *aux_mode_directed; aux_mode_directed = malloc(arity * sizeof(int)); ALLOC_BLOCK(mode_directed, arity * sizeof(int), int); for (i = 0; i < arity; i++) { int mode = IntOfTerm(HeadOfTerm(list)); if (mode == MODE_DIRECTED_INDEX) pos_index++; else if (mode == MODE_DIRECTED_ALL) pos_all++; else if (mode == MODE_DIRECTED_LAST) pos_last++; else if (mode == MODE_DIRECTED_MIN || mode == MODE_DIRECTED_MAX) pos_agreg++; aux_mode_directed[i] = mode; list = TailOfTerm(list); } pos_first = pos_index + pos_agreg + pos_all + pos_last; pos_last = pos_index + pos_agreg + pos_all; pos_all = pos_index + pos_agreg; pos_agreg = pos_index; pos_index = 0; for (i = 0; i < arity; i++) { int aux_pos = 0; if (aux_mode_directed[i] == MODE_DIRECTED_MAX) aux_pos = pos_agreg++; else if (aux_mode_directed[i] == MODE_DIRECTED_MIN) aux_pos = pos_agreg++; else if (aux_mode_directed[i] == MODE_DIRECTED_INDEX) aux_pos = pos_index++; else if(aux_mode_directed[i] == MODE_DIRECTED_FIRST) aux_pos = pos_first++; else if (aux_mode_directed[i] == MODE_DIRECTED_ALL) aux_pos = pos_all++; else if (aux_mode_directed[i] == MODE_DIRECTED_LAST) aux_pos = pos_last++; mode_directed[aux_pos] = MODE_DIRECTED_SET(i, aux_mode_directed[i]); } free(aux_mode_directed); #endif /* MODE_DIRECTED_TABLING */ } if (pe->PredFlags & TabledPredFlag) return (TRUE); /* predicate already tabled */ if (pe->cs.p_code.FirstClause) return (FALSE); /* predicate already compiled */ pe->PredFlags |= TabledPredFlag; new_table_entry(tab_ent, pe, at, arity, mode_directed); pe->TableOfPred = tab_ent; return (TRUE); } static Int p_tabling_mode( USES_REGS1 ) { Term mod, t, tvalue; tab_ent_ptr tab_ent; mod = Deref(ARG1); t = Deref(ARG2); if (IsAtomTerm(t)) tab_ent = RepPredProp(PredPropByAtom(AtomOfTerm(t), mod))->TableOfPred; else if (IsApplTerm(t)) tab_ent = RepPredProp(PredPropByFunc(FunctorOfTerm(t), mod))->TableOfPred; else return (FALSE); tvalue = Deref(ARG3); if (IsVarTerm(tvalue)) { t = TermNil; if (IsMode_LocalTrie(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLocalTrie), t); else if (IsMode_GlobalTrie(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomGlobalTrie), t); if (IsMode_ExecAnswers(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomExecAnswers), t); else if (IsMode_LoadAnswers(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLoadAnswers), t); if (IsMode_Batched(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomBatched), t); else if (IsMode_Local(TabEnt_flags(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLocal), t); t = MkPairTerm(MkAtomTerm(AtomDefault), t); t = MkPairTerm(t, TermNil); if (IsMode_LocalTrie(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLocalTrie), t); else if (IsMode_GlobalTrie(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomGlobalTrie), t); if (IsMode_ExecAnswers(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomExecAnswers), t); else if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLoadAnswers), t); if (IsMode_Batched(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomBatched), t); else if (IsMode_Local(TabEnt_mode(tab_ent))) t = MkPairTerm(MkAtomTerm(AtomLocal), t); Bind((CELL *) tvalue, t); return(TRUE); } else if (IsIntTerm(tvalue)) { Int value = IntOfTerm(tvalue); if (value == 1) { /* batched */ SetMode_Batched(TabEnt_flags(tab_ent)); if (! IsMode_Local(yap_flags[TABLING_MODE_FLAG])) { SetMode_Batched(TabEnt_mode(tab_ent)); return(TRUE); } } else if (value == 2) { /* local */ SetMode_Local(TabEnt_flags(tab_ent)); if (! IsMode_Batched(yap_flags[TABLING_MODE_FLAG])) { SetMode_Local(TabEnt_mode(tab_ent)); return(TRUE); } } else if (value == 3) { /* exec_answers */ SetMode_ExecAnswers(TabEnt_flags(tab_ent)); if (! IsMode_LoadAnswers(yap_flags[TABLING_MODE_FLAG])) { SetMode_ExecAnswers(TabEnt_mode(tab_ent)); return(TRUE); } } else if (value == 4) { /* load_answers */ SetMode_LoadAnswers(TabEnt_flags(tab_ent)); if (! IsMode_ExecAnswers(yap_flags[TABLING_MODE_FLAG])) { SetMode_LoadAnswers(TabEnt_mode(tab_ent)); return(TRUE); } } else if (value == 5) { /* local_trie */ SetMode_LocalTrie(TabEnt_flags(tab_ent)); if (! IsMode_GlobalTrie(yap_flags[TABLING_MODE_FLAG])) { SetMode_LocalTrie(TabEnt_mode(tab_ent)); return(TRUE); } } else if (value == 6) { /* global_trie */ SetMode_GlobalTrie(TabEnt_flags(tab_ent)); if (! IsMode_LocalTrie(yap_flags[TABLING_MODE_FLAG])) { SetMode_GlobalTrie(TabEnt_mode(tab_ent)); return(TRUE); } } } return (FALSE); } static Int p_abolish_table( USES_REGS1 ) { Term mod, t; tab_ent_ptr tab_ent; mod = Deref(ARG1); t = Deref(ARG2); if (IsAtomTerm(t)) tab_ent = RepPredProp(PredPropByAtom(AtomOfTerm(t), mod))->TableOfPred; else if (IsApplTerm(t)) tab_ent = RepPredProp(PredPropByFunc(FunctorOfTerm(t), mod))->TableOfPred; else return (FALSE); abolish_table(tab_ent); return (TRUE); } static Int p_abolish_all_tables( USES_REGS1 ) { tab_ent_ptr tab_ent; tab_ent = GLOBAL_root_tab_ent; while (tab_ent) { abolish_table(tab_ent); tab_ent = TabEnt_next(tab_ent); } return (TRUE); } static Int p_show_tabled_predicates( USES_REGS1 ) { IOSTREAM *out; tab_ent_ptr tab_ent; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; tab_ent = GLOBAL_root_tab_ent; Sfprintf(out, "Tabled predicates\n"); if (tab_ent == NULL) Sfprintf(out, " NONE\n"); else while(tab_ent) { Sfprintf(out, " %s/%d\n", AtomName(TabEnt_atom(tab_ent)), TabEnt_arity(tab_ent)); tab_ent = TabEnt_next(tab_ent); } PL_release_stream(out); return (TRUE); } static Int p_show_table( USES_REGS1 ) { IOSTREAM *out; Term mod, t; tab_ent_ptr tab_ent; Term t1 = Deref(ARG1); if (IsVarTerm(t1) || !IsAtomTerm(t1)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t1)))) return FALSE; mod = Deref(ARG2); t = Deref(ARG3); if (IsAtomTerm(t)) tab_ent = RepPredProp(PredPropByAtom(AtomOfTerm(t), mod))->TableOfPred; else if (IsApplTerm(t)) tab_ent = RepPredProp(PredPropByFunc(FunctorOfTerm(t), mod))->TableOfPred; else { PL_release_stream(out); return (FALSE); } show_table(tab_ent, SHOW_MODE_STRUCTURE, out); PL_release_stream(out); return (TRUE); } static Int p_show_all_tables( USES_REGS1 ) { IOSTREAM *out; tab_ent_ptr tab_ent; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; tab_ent = GLOBAL_root_tab_ent; while(tab_ent) { show_table(tab_ent, SHOW_MODE_STRUCTURE, out); tab_ent = TabEnt_next(tab_ent); } PL_release_stream(out); return (TRUE); } static Int p_show_global_trie( USES_REGS1 ) { IOSTREAM *out; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; show_global_trie(SHOW_MODE_STRUCTURE, out); PL_release_stream(out); return (TRUE); } static Int p_show_statistics_table( USES_REGS1 ) { IOSTREAM *out; Term mod, t; tab_ent_ptr tab_ent; Term t1 = Deref(ARG1); if (IsVarTerm(t1) || !IsAtomTerm(t1)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t1)))) return FALSE; mod = Deref(ARG2); t = Deref(ARG3); if (IsAtomTerm(t)) tab_ent = RepPredProp(PredPropByAtom(AtomOfTerm(t), mod))->TableOfPred; else if (IsApplTerm(t)) tab_ent = RepPredProp(PredPropByFunc(FunctorOfTerm(t), mod))->TableOfPred; else { PL_release_stream(out); return (FALSE); } show_table(tab_ent, SHOW_MODE_STATISTICS, out); PL_release_stream(out); return (TRUE); } static Int p_show_statistics_tabling( USES_REGS1 ) { struct page_statistics stats; long bytes, total_bytes = 0; #ifdef USE_PAGES_MALLOC long total_pages = 0; #endif /* USE_PAGES_MALLOC */ IOSTREAM *out; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; bytes = 0; Sfprintf(out, "Execution data structures\n"); stats = show_statistics_table_entries(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) stats = show_statistics_subgoal_entries(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ stats = show_statistics_subgoal_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_dependency_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (I): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Local trie data structures\n"); stats = show_statistics_subgoal_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_answer_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_subgoal_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_answer_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #if defined(THREADS_FULL_SHARING) stats = show_statistics_answer_ref_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #endif /* THREADS_FULL_SHARING */ Sfprintf(out, " Memory in use (II): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Global trie data structures\n"); stats = show_statistics_global_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_global_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (III): %10ld bytes\n\n", bytes); total_bytes += bytes; #ifdef USE_PAGES_MALLOC Sfprintf(out, "Total memory in use (I+II+III): %10ld bytes (%ld pages in use)\n", total_bytes, total_pages); Sfprintf(out, "Total memory allocated: %10ld bytes (%ld pages in total)\n", PgEnt_pages_in_use(GLOBAL_pages_alloc) * Yap_page_size, PgEnt_pages_in_use(GLOBAL_pages_alloc)); #else Sfprintf(out, "Total memory in use (I+II+III): %10ld bytes\n", total_bytes); #endif /* USE_PAGES_MALLOC */ PL_release_stream(out); return (TRUE); } static Int p_show_statistics_global_trie( USES_REGS1 ) { IOSTREAM *out; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; show_global_trie(SHOW_MODE_STATISTICS, out); PL_release_stream(out); return (TRUE); } #endif /* TABLING */ /********************************* ** YapOr C Predicates ** *********************************/ #ifdef YAPOR static Int p_parallel_mode( USES_REGS1 ) { Term t; t = Deref(ARG1); if (IsVarTerm(t)) { Term ta; if (GLOBAL_parallel_mode == PARALLEL_MODE_OFF) ta = MkAtomTerm(Yap_LookupAtom("off")); else if (GLOBAL_parallel_mode == PARALLEL_MODE_ON) ta = MkAtomTerm(Yap_LookupAtom("on")); else /* PARALLEL_MODE_RUNNING */ ta = MkAtomTerm(Yap_LookupAtom("running")); Bind((CELL *)t, ta); return(TRUE); } if (IsAtomTerm(t) && GLOBAL_parallel_mode != PARALLEL_MODE_RUNNING) { char *s; s = RepAtom(AtomOfTerm(t))->StrOfAE; if (strcmp(s,"on") == 0) { GLOBAL_parallel_mode = PARALLEL_MODE_ON; return(TRUE); } if (strcmp(s,"off") == 0) { GLOBAL_parallel_mode = PARALLEL_MODE_OFF; return(TRUE); } return(FALSE); /* PARALLEL_MODE_RUNNING */ } return(FALSE); } static Int p_yapor_start( USES_REGS1 ) { #ifdef TIMESTAMP_CHECK GLOBAL_timestamp = 0; #endif /* TIMESTAMP_CHECK */ BITMAP_delete(GLOBAL_bm_idle_workers, 0); BITMAP_clear(GLOBAL_bm_invisible_workers); BITMAP_clear(GLOBAL_bm_requestable_workers); #ifdef TABLING_INNER_CUTS BITMAP_clear(GLOBAL_bm_pruning_workers); #endif /* TABLING_INNER_CUTS */ make_root_choice_point(); GLOBAL_parallel_mode = PARALLEL_MODE_RUNNING; GLOBAL_execution_time = current_time(); BITMAP_clear(GLOBAL_bm_finished_workers); PUT_IN_EXECUTING(worker_id); return (TRUE); } static Int p_yapor_workers( USES_REGS1 ) { #ifdef YAPOR_THREADS return Yap_unify(MkIntegerTerm(GLOBAL_number_workers),ARG1); #else return FALSE; #endif /* YAPOR_THREADS */ } static Int p_worker( USES_REGS1 ) { CurrentModule = USER_MODULE; P = GETWORK_FIRST_TIME; return TRUE; } static Int p_parallel_new_answer( USES_REGS1 ) { qg_ans_fr_ptr actual_answer; or_fr_ptr leftmost_or_fr; ALLOC_QG_ANSWER_FRAME(actual_answer); AnsFr_answer(actual_answer) = Deref(ARG1); AnsFr_next(actual_answer) = NULL; leftmost_or_fr = CUT_leftmost_or_frame(); LOCK_OR_FRAME(leftmost_or_fr); if (Get_LOCAL_prune_request()) { UNLOCK_OR_FRAME(leftmost_or_fr); FREE_QG_ANSWER_FRAME(actual_answer); } else { CUT_store_answer(leftmost_or_fr, actual_answer); UNLOCK_OR_FRAME(leftmost_or_fr); } return (TRUE); } static Int p_parallel_get_answers( USES_REGS1 ){ Term t = TermNil; if (OrFr_qg_solutions(LOCAL_top_or_fr)) { qg_ans_fr_ptr aux_answer1, aux_answer2; aux_answer1 = SolFr_first(OrFr_qg_solutions(LOCAL_top_or_fr)); while (aux_answer1) { t = MkPairTerm(AnsFr_answer(aux_answer1), t); aux_answer2 = aux_answer1; aux_answer1 = AnsFr_next(aux_answer1); FREE_QG_ANSWER_FRAME(aux_answer2); } FREE_QG_SOLUTION_FRAME(OrFr_qg_solutions(LOCAL_top_or_fr)); OrFr_qg_solutions(LOCAL_top_or_fr) = NULL; } Yap_unify(ARG1, t); return (TRUE); } static Int p_show_statistics_or( USES_REGS1 ) { struct page_statistics stats; long bytes, total_bytes = 0; #ifdef USE_PAGES_MALLOC long total_pages = 0; #endif /* USE_PAGES_MALLOC */ IOSTREAM *out; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; bytes = 0; Sfprintf(out, "Execution data structures\n"); stats = show_statistics_or_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (I): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Cut support data structures\n"); stats = show_statistics_query_goal_solution_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_query_goal_answer_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (II): %10ld bytes\n\n", bytes); total_bytes += bytes; #ifdef USE_PAGES_MALLOC Sfprintf(out, "Total memory in use (I+II): %10ld bytes (%ld pages in use)\n", total_bytes, total_pages); Sfprintf(out, "Total memory allocated: %10ld bytes (%ld pages in total)\n", PgEnt_pages_in_use(GLOBAL_pages_alloc) * Yap_page_size, PgEnt_pages_in_use(GLOBAL_pages_alloc)); #else Sfprintf(out, "Total memory in use (I+II): %10ld bytes\n", total_bytes); #endif /* USE_PAGES_MALLOC */ PL_release_stream(out); return (TRUE); } #endif /* YAPOR */ /********************************** ** OPTYap C Predicates ** **********************************/ #if defined(YAPOR) && defined(TABLING) static Int p_show_statistics_opt( USES_REGS1 ) { struct page_statistics stats; long bytes, total_bytes = 0; #ifdef USE_PAGES_MALLOC long total_pages = 0; #endif /* USE_PAGES_MALLOC */ IOSTREAM *out; Term t = Deref(ARG1); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (!(out = Yap_GetStreamHandle(AtomOfTerm(t)))) return FALSE; bytes = 0; Sfprintf(out, "Execution data structures\n"); stats = show_statistics_table_entries(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) stats = show_statistics_subgoal_entries(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ stats = show_statistics_subgoal_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_dependency_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_or_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_suspension_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (I): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Local trie data structures\n"); stats = show_statistics_subgoal_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_answer_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_subgoal_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_answer_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #if defined(THREADS_FULL_SHARING) stats = show_statistics_answer_ref_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #endif /* THREADS_FULL_SHARING */ Sfprintf(out, " Memory in use (II): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Global trie data structures\n"); stats = show_statistics_global_trie_nodes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_global_trie_hashes(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); Sfprintf(out, " Memory in use (III): %10ld bytes\n\n", bytes); total_bytes += bytes; bytes = 0; Sfprintf(out, "Cut support data structures\n"); stats = show_statistics_query_goal_solution_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_query_goal_answer_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #ifdef TABLING_INNER_CUTS stats = show_statistics_table_subgoal_solution_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); stats = show_statistics_table_subgoal_answer_frames(out); INCREMENT_AUX_STATS(stats, bytes, total_pages); #endif /* TABLING_INNER_CUTS */ Sfprintf(out, " Memory in use (IV): %10ld bytes\n\n", bytes); total_bytes += bytes; #ifdef USE_PAGES_MALLOC Sfprintf(out, "Total memory in use (I+II+III+IV): %10ld bytes (%ld pages in use)\n", total_bytes, total_pages); Sfprintf(out, "Total memory allocated: %10ld bytes (%ld pages in total)\n", PgEnt_pages_in_use(GLOBAL_pages_alloc) * Yap_page_size, PgEnt_pages_in_use(GLOBAL_pages_alloc)); #else Sfprintf(out, "Total memory in use (I+II+III+IV): %10ld bytes\n", total_bytes); #endif /* USE_PAGES_MALLOC */ PL_release_stream(out); return (TRUE); } #endif /* YAPOR && TABLING */ static Int p_get_optyap_statistics( USES_REGS1 ) { struct page_statistics stats; Int value, bytes = 0, structs = -1; Term tbytes, tstructs; value = IntOfTerm(Deref(ARG1)); #ifdef TABLING if (value == 0 || value == 1) { /* table_entries */ GET_PAGE_STATS(stats, struct table_entry, _pages_tab_ent); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (value == 0 || value == 16) { /* subgoal_entries */ GET_PAGE_STATS(stats, struct subgoal_entry, _pages_sg_ent); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #endif if (value == 0 || value == 2) { /* subgoal_frames */ GET_PAGE_STATS(stats, struct subgoal_frame, _pages_sg_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 3) { /* dependency_frames */ GET_PAGE_STATS(stats, struct dependency_frame, _pages_dep_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 6) { /* subgoal_trie_nodes */ GET_PAGE_STATS(stats, struct subgoal_trie_node, _pages_sg_node); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 8) { /* subgoal_trie_hashes */ GET_PAGE_STATS(stats, struct subgoal_trie_hash, _pages_sg_hash); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 7) { /* answer_trie_nodes */ GET_PAGE_STATS(stats, struct answer_trie_node, _pages_ans_node); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 9) { /* answer_trie_hashes */ GET_PAGE_STATS(stats, struct answer_trie_hash, _pages_ans_hash); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #if defined(THREADS_FULL_SHARING) if (value == 0 || value == 17) { /* answer_ref_nodes */ GET_PAGE_STATS(stats, struct answer_ref_node, _pages_ans_ref_node); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #endif if (value == 0 || value == 10) { /* global_trie_nodes */ GET_PAGE_STATS(stats, struct global_trie_node, _pages_gt_node); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 11) { /* global_trie_hashes */ GET_PAGE_STATS(stats, struct global_trie_hash, _pages_gt_hash); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #endif /* TABLING */ #ifdef YAPOR if (value == 0 || value == 4) { /* or_frames */ GET_PAGE_STATS(stats, struct or_frame, _pages_or_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 12) { /* query_goal_solution_frames */ GET_PAGE_STATS(stats, struct query_goal_solution_frame, _pages_qg_sol_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 13) { /* query_goal_answer_frames */ GET_PAGE_STATS(stats, struct query_goal_answer_frame, _pages_qg_ans_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #endif /* YAPOR */ #if defined(YAPOR) && defined(TABLING) if (value == 0 || value == 5) { /* suspension_frames */ GET_PAGE_STATS(stats, struct suspension_frame, _pages_susp_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #ifdef TABLING_INNER_CUTS if (value == 0 || value == 14) { /* table_subgoal_solution_frames */ GET_PAGE_STATS(stats, struct table_subgoal_solution_frame, _pages_tg_sol_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } if (value == 0 || value == 15) { /* table_subgoal_answer_frames */ GET_PAGE_STATS(stats, struct table_subgoal_answer_frame, _pages_tg_ans_fr); bytes += PgEnt_bytes_in_use(stats); if (value != 0) structs = PgEnt_strs_in_use(stats); } #endif /* TABLING_INNER_CUTS */ #endif /* YAPOR && TABLING */ if (value == 0) { /* total_memory */ #ifdef USE_PAGES_MALLOC structs = PgEnt_pages_in_use(GLOBAL_pages_alloc) * Yap_page_size; #else structs = bytes; #endif /* USE_PAGES_MALLOC */ } if (structs == -1) return (FALSE); tbytes = Deref(ARG2); tstructs = Deref(ARG3); if (IsVarTerm(tbytes)) { Bind((CELL *) tbytes, MkIntTerm(bytes)); } else if (IsIntTerm(tbytes) && IntOfTerm(tbytes) != bytes) return (FALSE); if (IsVarTerm(tstructs)) { Bind((CELL *) tstructs, MkIntTerm(structs)); } else if (IsIntTerm(tstructs) && IntOfTerm(tstructs) != structs) return (FALSE); return (TRUE); } /****************************** ** Local functions ** ******************************/ #ifdef YAPOR static inline realtime current_time(void) { #define TIME_RESOLUTION 1000000 struct timeval tempo; gettimeofday(&tempo, NULL); return ((realtime)tempo.tv_sec + (realtime)tempo.tv_usec / TIME_RESOLUTION); /* to get time as Yap */ /* double now, interval; Yap_cputime_interval(&now, &interval); return ((realtime)now); */ } #endif /* YAPOR */ #ifdef TABLING static inline struct page_statistics show_statistics_table_entries(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct table_entry, _pages_tab_ent, "Table entries: "); } #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) static inline struct page_statistics show_statistics_subgoal_entries(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct subgoal_entry, _pages_sg_ent, "Subgoal entries: "); } #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ static inline struct page_statistics show_statistics_subgoal_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct subgoal_frame, _pages_sg_fr, "Subgoal frames: "); } static inline struct page_statistics show_statistics_dependency_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct dependency_frame, _pages_dep_fr, "Dependency frames: "); } static inline struct page_statistics show_statistics_subgoal_trie_nodes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct subgoal_trie_node, _pages_sg_node, "Subgoal trie nodes: "); } static inline struct page_statistics show_statistics_subgoal_trie_hashes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct subgoal_trie_hash, _pages_sg_hash, "Subgoal trie hashes: "); } static inline struct page_statistics show_statistics_answer_trie_nodes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct answer_trie_node, _pages_ans_node, "Answer trie nodes: "); } static inline struct page_statistics show_statistics_answer_trie_hashes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct answer_trie_hash, _pages_ans_hash, "Answer trie hashes: "); } #if defined(THREADS_FULL_SHARING) static inline struct page_statistics show_statistics_answer_ref_nodes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct answer_ref_node, _pages_ans_ref_node, "Answer ref nodes: "); } #endif /* THREADS_FULL_SHARING */ static inline struct page_statistics show_statistics_global_trie_nodes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct global_trie_node, _pages_gt_node, "Global trie nodes: "); } static inline struct page_statistics show_statistics_global_trie_hashes(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct global_trie_hash, _pages_gt_hash, "Global trie hashes: "); } #endif /* TABLING */ #ifdef YAPOR static inline struct page_statistics show_statistics_or_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct or_frame, _pages_or_fr, "Or-frames: "); } static inline struct page_statistics show_statistics_query_goal_solution_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct query_goal_solution_frame, _pages_qg_sol_fr, "Query goal solution frames: "); } static inline struct page_statistics show_statistics_query_goal_answer_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct query_goal_answer_frame, _pages_qg_ans_fr, "Query goal answer frames: "); } #endif /* YAPOR */ #if defined(YAPOR) && defined(TABLING) static inline struct page_statistics show_statistics_suspension_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct suspension_frame, _pages_susp_fr, "Suspension frames: "); } #ifdef TABLING_INNER_CUTS static inline struct page_statistics show_statistics_table_subgoal_solution_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct table_subgoal_solution_frame, _pages_tg_sol_fr, "Table subgoal solution frames:"); } static inline struct page_statistics show_statistics_table_subgoal_answer_frames(IOSTREAM *out) { SHOW_PAGE_STATS(out, struct table_subgoal_answer_frame, _pages_tg_ans_fr, "Table subgoal answer frames: "); } #endif /* TABLING_INNER_CUTS */ #endif /* YAPOR && TABLING */ #endif /* YAPOR || TABLING */