diff --git a/C/absmi.c b/C/absmi.c index 78fd4f423..92f79a251 100644 --- a/C/absmi.c +++ b/C/absmi.c @@ -459,7 +459,7 @@ absmi(int inp) GONext(); ENDOp(); - /* profiled_enter_me Label,NArgs */ + /* profiled_retry Label,NArgs */ Op(retry_profiled, l); LOCK(((PredEntry *)(PREG->u.l.l))->StatisticsForPred.lock); ((PredEntry *)(PREG->u.l.l))->StatisticsForPred.NOfRetries++; @@ -523,6 +523,111 @@ absmi(int inp) GONext(); ENDOp(); +/***************************************************************** +* Call count instructions * +*****************************************************************/ + + /* count_enter_me Label,NArgs */ + Op(count_call, l); + ReductionsCounter--; + if (ReductionsCounter == 0 && ReductionsCounterOn) { + Error(CALL_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PredEntriesCounter--; + if (PredEntriesCounter == 0 && PredEntriesCounterOn) { + Error(PRED_ENTRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PREG = NEXTOP(PREG, l); + GONext(); + ENDOp(); + + /* count_retry Label,NArgs */ + Op(count_retry, l); + RetriesCounter--; + if (RetriesCounter == 0 && RetriesCounterOn) { + Error(RETRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PredEntriesCounter--; + if (PredEntriesCounter == 0 && PredEntriesCounterOn) { + Error(PRED_ENTRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PREG = NEXTOP(PREG, l); + GONext(); + ENDOp(); + + /* count_retry_me Label,NArgs */ + Op(count_retry_me, ld); + CACHE_Y(B); + /* After retry, cut should be pointing at the parent + * choicepoint for the current B */ + RetriesCounter--; + if (RetriesCounter == 0 && RetriesCounterOn) { + Error(RETRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PredEntriesCounter--; + if (PredEntriesCounter == 0 && PredEntriesCounterOn) { + Error(PRED_ENTRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + restore_yaam_regs(PREG->u.ld.d); + restore_args(PREG->u.ld.s); +#ifdef FROZEN_STACKS + S_Y = (CELL *)PROTECT_FROZEN_B(B_Y); + set_cut(S_Y, B->cp_b); +#else + set_cut(S_Y, B_Y->cp_b); +#endif /* FROZEN_STACKS */ + SET_BB(B_Y); + ENDCACHE_Y(); + PREG = NEXTOP(PREG, ld); + GONext(); + ENDOp(); + + /* count_trust_me UnusedLabel,NArgs */ + Op(count_trust_me, ld); + CACHE_Y(B); +#ifdef YAPOR + if (SCH_top_shared_cp(B)) { + SCH_last_alternative(PREG, B_Y); + restore_args(PREG->u.ld.s); +#ifdef FROZEN_STACKS + B_Y = PROTECT_FROZEN_B(B_Y); +#endif /* FROZEN_STACKS */ + set_cut(S_Y, B->cp_b); + } + else +#endif /* YAPOR */ + { + pop_yaam_regs(); + pop_args(PREG->u.ld.s); + /* After trust, cut should be pointing at the new top + * choicepoint */ +#ifdef FROZEN_STACKS + S_Y = (CELL *)PROTECT_FROZEN_B(B_Y); +#endif /* FROZEN_STACKS */ + set_cut(S_Y, B); + } + SET_BB(B_Y); + ENDCACHE_Y(); + RetriesCounter--; + if (RetriesCounter == 0) { + Error(RETRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PredEntriesCounter--; + if (PredEntriesCounter == 0) { + Error(PRED_ENTRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PREG = NEXTOP(PREG, ld); + GONext(); + ENDOp(); + /***************************************************************** * Specialised try - retry - trust instructions * *****************************************************************/ @@ -1071,6 +1176,21 @@ absmi(int inp) ENDBOp(); + BOp(count_retry_and_mark, ld); + RetriesCounter--; + if (RetriesCounter == 0) { + Error(RETRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + PredEntriesCounter--; + if (PredEntriesCounter == 0) { + Error(PRED_ENTRY_COUNTER_UNDERFLOW,TermNil,""); + JMPNext(); + } + goto actual_retry_and_mark; + /* enter a retry dynamic */ + ENDBOp(); + BOp(profiled_retry_and_mark, ld); LOCK(((PredEntry *)(PREG->u.ld.p))->StatisticsForPred.lock); ((PredEntry *)(PREG->u.ld.p))->StatisticsForPred.NOfRetries++; @@ -1080,6 +1200,7 @@ absmi(int inp) /* retry_and_mark Label,NArgs */ BOp(retry_and_mark, ld); + actual_retry_and_mark: #ifdef YAPOR CUT_wait_leftmost(); #endif /* YAPOR */ diff --git a/C/amasm.c b/C/amasm.c index 8fa045eb3..49689cf4d 100644 --- a/C/amasm.c +++ b/C/amasm.c @@ -2532,6 +2532,12 @@ do_pass(void) case retry_profiled_op: a_pl(_retry_profiled, (PredEntry *)(cpc->rnd1)); break; + case count_call_op: + a_pl(_count_call, (PredEntry *)(cpc->rnd1)); + break; + case count_retry_op: + a_pl(_count_retry, (PredEntry *)(cpc->rnd1)); + break; case fetch_args_for_bccall: if (cpc->nextInst->op != bccall_op) { Error(SYSTEM_ERROR, TermNil, "compiling binary test", (int) cpc->op); diff --git a/C/cdmgr.c b/C/cdmgr.c index d50d17dbd..583d2adc4 100644 --- a/C/cdmgr.c +++ b/C/cdmgr.c @@ -74,6 +74,10 @@ STATIC_PROTO(Int p_compile_mode, (void)); STATIC_PROTO(Int p_is_profiled, (void)); STATIC_PROTO(Int p_profile_info, (void)); STATIC_PROTO(Int p_profile_reset, (void)); +STATIC_PROTO(Int p_is_call_counted, (void)); +STATIC_PROTO(Int p_call_count_info, (void)); +STATIC_PROTO(Int p_call_count_set, (void)); +STATIC_PROTO(Int p_call_count_reset, (void)); STATIC_PROTO(Int p_toggle_static_predicates_in_use, (void)); #ifdef DEBUG STATIC_PROTO(void list_all_predicates_in_use, (void)); @@ -380,6 +384,8 @@ retract_all(PredEntry *p, int in_use) p->OpcodeOfPred = cpt->opc; if (p->PredFlags & ProfiledPredFlag) { ((yamop *)lclause)->opc = opcode(_profiled_trust_me); + } else if (p->PredFlags & CountPredFlag) { + ((yamop *)lclause)->opc = opcode(_count_trust_me); } else { ((yamop *)lclause)->opc = opcode(TRYCODE(_trust_me, _trust_me0, PredArity(p))); } @@ -520,6 +526,8 @@ add_first_dynamic(PredEntry *p, CODEADDR cp, int spy_flag) * backtrack to the previous block */ if (p->PredFlags & ProfiledPredFlag) ((yamop *)cp)->opc = opcode(_profiled_retry_and_mark); + else if (p->PredFlags & CountPredFlag) + ((yamop *)cp)->opc = opcode(_count_retry_and_mark); else ((yamop *)cp)->opc = opcode(_retry_and_mark); ((yamop *)cp)->u.ld.s = p->ArityOfPE; @@ -567,6 +575,11 @@ asserta_stat_clause(PredEntry *p, CODEADDR cp, int spy_flag) q->opc = opcode(_profiled_trust_me); else q->opc = opcode(_profiled_retry_me); + } else if (p->PredFlags & CountPredFlag) { + if (p->FirstClause == p->LastClause) + q->opc = opcode(_count_trust_me); + else + q->opc = opcode(_count_retry_me); } else { if (p->FirstClause == p->LastClause) { #ifdef TABLING @@ -606,9 +619,11 @@ asserta_dynam_clause(PredEntry *p, CODEADDR cp) q->u.ld.s = p->ArityOfPE; q->u.ld.p = p; if (p->PredFlags & ProfiledPredFlag) - ((yamop *)cp)->opc = opcode(_retry_and_mark); - else ((yamop *)cp)->opc = opcode(_profiled_retry_and_mark); + else if (p->PredFlags & CountPredFlag) + ((yamop *)cp)->opc = opcode(_count_retry_and_mark); + else + ((yamop *)cp)->opc = opcode(_retry_and_mark); ((yamop *)cp)->u.ld.s = p->ArityOfPE; ((yamop *)cp)->u.ld.p = p; p->FirstClause = cp; @@ -630,6 +645,12 @@ assertz_stat_clause(PredEntry *p, CODEADDR cp, int spy_flag) p->TrueCodeOfPred = p->FirstClause; } else pt->opc = opcode(_profiled_retry_me); + } else if (p->PredFlags & CountPredFlag) { + if (p->FirstClause == p->LastClause) { + pt->opc = opcode(TRYCODE(_try_me, _try_me0, PredArity(p))); + p->TrueCodeOfPred = p->FirstClause; + } else + pt->opc = opcode(_count_retry_me); } else { if (p->FirstClause == p->LastClause) { #ifdef TABLING @@ -653,6 +674,8 @@ assertz_stat_clause(PredEntry *p, CODEADDR cp, int spy_flag) pt = (yamop *)cp; if (p->PredFlags & ProfiledPredFlag) { pt->opc = opcode(_profiled_trust_me); + } else if (p->PredFlags & CountPredFlag) { + pt->opc = opcode(_count_trust_me); } else { #ifdef TABLING if (is_tabled(p)) @@ -693,6 +716,8 @@ assertz_dynam_clause(PredEntry *p, CODEADDR cp) q = (yamop *)cp; if (p->PredFlags & ProfiledPredFlag) q->opc = opcode(_profiled_retry_and_mark); + else if (p->PredFlags & CountPredFlag) + q->opc = opcode(_count_retry_and_mark); else q->opc = opcode(_retry_and_mark); q->u.ld.d = p->CodeOfPred; @@ -1779,6 +1804,9 @@ search_for_static_predicate_in_use(PredEntry *p, int check_everything) case _retry_profiled: opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); goto restart_cp; + case _count_retry: + opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); + goto restart_cp; default: pe = (PredEntry *)(b_ptr->cp_ap->u.ld.p); } @@ -1829,7 +1857,6 @@ static char *op_names[_std_top + 1] = #endif - static void list_all_predicates_in_use(void) { @@ -1865,6 +1892,7 @@ list_all_predicates_in_use(void) case _retry_userc: case _trust_logical_pred: case _retry_profiled: + case _count_retry: { Atom at; Int arity; @@ -1890,7 +1918,7 @@ list_all_predicates_in_use(void) YP_fprintf(YP_stderr,"CP %p %d (%s)\n", b_ptr, RepAtom((Atom)(pe->FunctorOfPred))->StrOfAE, op_names[opnum]); } } - if (opnum == _retry_profiled) { + if (opnum == _retry_profiled || opnum == _count_retry) { opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); goto restart_cp; } @@ -1958,6 +1986,9 @@ do_toggle_static_predicates_in_use(int mask) case _retry_profiled: opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); goto restart_cp; + case _count_retry: + opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); + goto restart_cp; default: pe = (PredEntry *)(b_ptr->cp_ap->u.ld.p); } @@ -2171,6 +2202,75 @@ p_profile_reset(void) return(TRUE); } +static Int +p_is_call_counted(void) +{ + Term t = Deref(ARG1); + char *s; + + if (IsVarTerm(t)) { + Term ta; + + if (CALL_COUNTING) ta = MkAtomTerm(LookupAtom("on")); + else ta = MkAtomTerm(LookupAtom("off")); + BIND((CELL *)t,ta,bind_is_call_counted); +#ifdef COROUTINING + DO_TRAIL(CellPtr(t), ta); + if (CellPtr(t) < H0) WakeUp((CELL *)t); + bind_is_call_counted: +#endif + return(TRUE); + } else if (!IsAtomTerm(t)) return(FALSE); + s = RepAtom(AtomOfTerm(t))->StrOfAE; + if (strcmp(s,"on") == 0) { + CALL_COUNTING = TRUE; + return(TRUE); + } else if (strcmp(s,"off") == 0) { + CALL_COUNTING = FALSE; + return(TRUE); + } + return(FALSE); +} + +static Int +p_call_count_info(void) +{ + return(unify(MkIntegerTerm(ReductionsCounter),ARG1) && + unify(MkIntegerTerm(PredEntriesCounter),ARG2) && + unify(MkIntegerTerm(PredEntriesCounter),ARG3)); +} + +static Int +p_call_count_reset(void) +{ + ReductionsCounter = 0; + ReductionsCounterOn = FALSE; + PredEntriesCounter = 0; + PredEntriesCounterOn = FALSE; + RetriesCounter = 0; + RetriesCounterOn = FALSE; + return(TRUE); +} + +static Int +p_call_count_set(void) +{ + int do_calls = IntOfTerm(ARG2); + int do_retries = IntOfTerm(ARG4); + int do_entries = IntOfTerm(ARG6); + + if (do_calls) + ReductionsCounter = IntegerOfTerm(Deref(ARG1)); + ReductionsCounterOn = do_calls; + if (do_retries) + RetriesCounter = IntegerOfTerm(Deref(ARG3)); + RetriesCounterOn = do_retries; + if (do_entries) + PredEntriesCounter = IntegerOfTerm(Deref(ARG5)); + PredEntriesCounterOn = do_entries; + return(TRUE); +} + static Int p_clean_up_dead_clauses(void) { @@ -2393,6 +2493,10 @@ InitCdMgr(void) InitCPred("$is_profiled", 1, p_is_profiled, SafePredFlag|SyncPredFlag); InitCPred("$profile_info", 3, p_profile_info, SafePredFlag|SyncPredFlag); InitCPred("$profile_reset", 2, p_profile_reset, SafePredFlag|SyncPredFlag); + InitCPred("$is_call_counted", 1, p_is_call_counted, SafePredFlag|SyncPredFlag); + InitCPred("$call_count_info", 3, p_call_count_info, SafePredFlag|SyncPredFlag); + InitCPred("$call_count_set", 6, p_call_count_set, SafePredFlag|SyncPredFlag); + InitCPred("$call_count_reset", 0, p_call_count_reset, SafePredFlag|SyncPredFlag); InitCPred("$toggle_static_predicates_in_use", 0, p_toggle_static_predicates_in_use, SafePredFlag|SyncPredFlag); InitCPred("$set_pred_module", 2, p_set_pred_module, SafePredFlag); InitCPred("$parent_pred", 3, p_parent_pred, SafePredFlag); diff --git a/C/compiler.c b/C/compiler.c index 1977a98d5..4759bf03d 100644 --- a/C/compiler.c +++ b/C/compiler.c @@ -73,7 +73,7 @@ static Ventry *vtable; CExpEntry *common_exps; -int n_common_exps, profiling; +int n_common_exps, profiling, call_counting; static int goalno, level, onlast, onhead, onbranch, cur_branch; @@ -1097,6 +1097,8 @@ c_functor(Term Goal, int mod) Prop p0 = PredPropByFunc(f, mod); if (profiling) emit(enter_profiling_op, (CELL)RepPredProp(p0), Zero); + else if (call_counting) + emit(count_call_op, (CELL)RepPredProp(p0), Zero); c_args(Goal); emit(safe_call_op, (CELL)p0 , Zero); emit(empty_call_op, Zero, Zero); @@ -1177,6 +1179,8 @@ c_goal(Term Goal, int mod) if (profiling) emit(enter_profiling_op, (CELL)RepPredProp(PredPropByAtom(AtomCut,0)), Zero); + else if (call_counting) + emit(count_call_op, (CELL)RepPredProp(PredPropByAtom(AtomCut,0)), Zero); if (onlast) { /* never a problem here with a -> b, !, c ; d */ emit(deallocate_op, Zero, Zero); @@ -1208,6 +1212,8 @@ c_goal(Term Goal, int mod) if (profiling) emit(enter_profiling_op, (CELL)RepPredProp(PredPropByAtom(AtomRepeat,0)), Zero); + else if (call_counting) + emit(count_call_op, (CELL)RepPredProp(PredPropByAtom(AtomRepeat,0)), Zero); or_found = 1; push_branch(onbranch, TermNil); cur_branch++; @@ -1245,6 +1251,8 @@ c_goal(Term Goal, int mod) /* if we are profiling, make sure we register we entered this predicate */ if (profiling) emit(enter_profiling_op, (CELL)p, Zero); + if (call_counting) + emit(count_call_op, (CELL)p, Zero); } else { f = FunctorOfTerm(Goal); @@ -1438,6 +1446,8 @@ c_goal(Term Goal, int mod) } else if (f == FunctorEq) { if (profiling) emit(enter_profiling_op, (CELL)p, Zero); + else if (call_counting) + emit(count_call_op, (CELL)p, Zero); c_eq(ArgOfTerm(1, Goal), ArgOfTerm(2, Goal)); if (onlast) { emit(deallocate_op, Zero, Zero); @@ -1457,6 +1467,8 @@ c_goal(Term Goal, int mod) int op = p->PredFlags & 0x7f; if (profiling) emit(enter_profiling_op, (CELL)p, Zero); + else if (call_counting) + emit(count_call_op, (CELL)p, Zero); if (op >= _atom && op <= _primitive) { c_test(op, ArgOfTerm(1, Goal)); if (onlast) { @@ -1574,6 +1586,8 @@ c_goal(Term Goal, int mod) } else { if (profiling) emit(enter_profiling_op, (CELL)p, Zero); + else if (call_counting) + emit(count_call_op, (CELL)p, Zero); c_args(Goal); } } @@ -2820,10 +2834,17 @@ cclause(Term inp_clause, int NOfArgs, int mod) /* insert extra instructions to count calls */ READ_LOCK(CurrentPred->PRWLock); if ((CurrentPred->PredFlags & ProfiledPredFlag) || - (PROFILING && (CurrentPred->FirstClause == NIL))) + (PROFILING && (CurrentPred->FirstClause == NIL))) { profiling = TRUE; - else + call_counting = FALSE; + } else if ((CurrentPred->PredFlags & CountPredFlag) || + (CALL_COUNTING && (CurrentPred->FirstClause == NIL))) { + call_counting = TRUE; profiling = FALSE; + } else { + profiling = FALSE; + call_counting = FALSE; + } READ_UNLOCK(CurrentPred->PRWLock); } /* phase 1 : produce skeleton code and variable information */ diff --git a/C/computils.c b/C/computils.c index 96f95da3e..8eff9c750 100644 --- a/C/computils.c +++ b/C/computils.c @@ -604,6 +604,8 @@ static char *opformat[] = "function_to_al\t%v,%B", "enter_profiling\t\t%g", "retry_profiled\t\t%g", + "count_call_op\t\t%g", + "count_retry_op\t\t%g", "restore_temps\t\t%l", "restore_temps_and_skip\t\t%l", "empty_call\t\t%l,%d", diff --git a/C/errors.c b/C/errors.c index 8bd24d2b0..043445093 100644 --- a/C/errors.c +++ b/C/errors.c @@ -157,6 +157,9 @@ DumpActiveGoals (void) case _retry_profiled: opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); goto restart_cp; + case _count_retry_me: + opnum = op_from_opcode(NEXTOP(b_ptr->cp_ap,l)->opc); + goto restart_cp; default: pe = (PredEntry *)(b_ptr->cp_ap->u.ld.p); } @@ -417,6 +420,26 @@ Error (yap_error_number type, Term where, char *format,...) fun = MkFunctor(LookupAtom("abort"),2); serious = TRUE; break; + case CALL_COUNTER_UNDERFLOW: + /* Do a long jump */ + PredEntriesCounter--; + JumpToEnv(MkAtomTerm(LookupAtom("call_counter"))); + P = (yamop *)FAILCODE; + PrologMode &= ~InErrorMode; + return(P); + case PRED_ENTRY_COUNTER_UNDERFLOW: + /* Do a long jump */ + JumpToEnv(MkAtomTerm(LookupAtom("call_and_retry_counter"))); + P = (yamop *)FAILCODE; + PrologMode &= ~InErrorMode; + return(P); + case RETRY_COUNTER_UNDERFLOW: + /* Do a long jump */ + PredEntriesCounter--; + JumpToEnv(MkAtomTerm(LookupAtom("retry_counter"))); + P = (yamop *)FAILCODE; + PrologMode &= ~InErrorMode; + return(P); case DOMAIN_ERROR_ARRAY_OVERFLOW: { int i; diff --git a/C/heapgc.c b/C/heapgc.c index 3d54f0294..7a64a5b88 100644 --- a/C/heapgc.c +++ b/C/heapgc.c @@ -1462,6 +1462,7 @@ mark_choicepoints(register choiceptr gc_B, tr_fr_ptr saved_TR, int very_verbose) case _retry_userc: case _trust_logical_pred: case _retry_profiled: + case _count_retry: { Atom at; Int arity; @@ -1594,6 +1595,7 @@ mark_choicepoints(register choiceptr gc_B, tr_fr_ptr saved_TR, int very_verbose) break; case _trust_logical_pred: case _retry_profiled: + case _count_retry: rtp = NEXTOP(rtp,l); op = rtp->opc; opnum = op_from_opcode(op); @@ -1706,6 +1708,8 @@ mark_choicepoints(register choiceptr gc_B, tr_fr_ptr saved_TR, int very_verbose) case _trust_me: case _profiled_retry_me: case _profiled_trust_me: + case _count_retry_me: + case _count_trust_me: case _retry_me0: case _trust_me0: case _retry_me1: @@ -1718,6 +1722,7 @@ mark_choicepoints(register choiceptr gc_B, tr_fr_ptr saved_TR, int very_verbose) case _trust_me4: case _retry_and_mark: case _profiled_retry_and_mark: + case _count_retry_and_mark: case _retry: case _trust_in: case _trust: @@ -2201,6 +2206,7 @@ sweep_choicepoints(choiceptr gc_B) break; case _trust_logical_pred: case _retry_profiled: + case _count_retry: rtp = NEXTOP(rtp,l); op = rtp->opc; opnum = op_from_opcode(op); diff --git a/C/index.c b/C/index.c index e9bcd49d1..d237f626b 100644 --- a/C/index.c +++ b/C/index.c @@ -252,6 +252,8 @@ emit_cp_inst(compiler_vm_op op, yamop * Address, int Flag, int NClausesAfter) indexed_code_for_cut = NIL; if (op != try_op && profiling) emit(retry_profiled_op, Unsigned(CurrentPred), Zero); + else if (op != try_op && call_counting) + emit(count_retry_op, Unsigned(CurrentPred), Zero); if (NGroups == 1) Flag = Flag | LoneGroup; else if (Flag & LastGroup) { @@ -1335,6 +1337,8 @@ PredIsIndexable(PredEntry *ap) CurrentPred = ap; if (CurrentPred->PredFlags & ProfiledPredFlag) profiling = TRUE; + else if (CurrentPred->PredFlags & CountPredFlag) + call_counting = TRUE; else profiling = FALSE; IPredArity = ap->ArityOfPE; diff --git a/C/init.c b/C/init.c index 2aa54cc71..a1e241a33 100644 --- a/C/init.c +++ b/C/init.c @@ -852,6 +852,7 @@ InitCodes(void) } heap_regs->consultcapacity = InitialConsultCapacity; heap_regs->profiling = FALSE; + heap_regs->call_counting = FALSE; heap_regs->update_mode = 0; heap_regs->consultbase = heap_regs->consultsp = heap_regs->consultlow + heap_regs->consultcapacity; diff --git a/H/Heap.h b/H/Heap.h index 7631820f6..2323b1431 100644 --- a/H/Heap.h +++ b/H/Heap.h @@ -10,7 +10,7 @@ * File: Heap.h * * mods: * * comments: Heap Init Structure * -* version: $Id: Heap.h,v 1.29 2002-06-05 01:34:06 vsc Exp $ * +* version: $Id: Heap.h,v 1.30 2002-09-03 14:28:07 vsc Exp $ * *************************************************************************/ /* information that can be stored in Code Space */ @@ -27,6 +27,15 @@ typedef struct atom_hash_entry { Atom Entry; } AtomHashEntry; +typedef struct reduction_counters { + YAP_LONG_LONG reductions; + YAP_LONG_LONG reductions_retries; + YAP_LONG_LONG retries; + int reductions_on; + int reductions_retries_on; + int retries_on; +} red_counters; + typedef int (*Agc_hook)(Atom); typedef struct various_codes { @@ -113,6 +122,7 @@ typedef struct various_codes { struct pred_entry *undef_code; struct pred_entry *spy_code; int profiling; + int call_counting; AtomHashEntry invisiblechain; OPCODE dummycode; Int maxdepth, maxlist; @@ -288,6 +298,7 @@ typedef struct various_codes { UInt n_of_file_aliases; UInt sz_of_file_aliases; struct AliasDescS * file_aliases; + struct reduction_counters call_counters; void *foreign_code_loaded; char *yap_lib_dir; Agc_hook agc_hook; @@ -331,6 +342,7 @@ typedef struct various_codes { #define OP_RTABLE heap_regs->op_rtable #endif #define PROFILING heap_regs->profiling +#define CALL_COUNTING heap_regs->call_counting #define UPDATE_MODE heap_regs->update_mode #define RETRY_C_RECORDED_CODE heap_regs->retry_recorded_code #define RETRY_C_RECORDED_K_CODE heap_regs->retry_recorded_k_code @@ -483,6 +495,12 @@ typedef struct various_codes { #define NOfFileAliases heap_regs->n_of_file_aliases #define SzOfFileAliases heap_regs->sz_of_file_aliases #define FileAliases heap_regs->file_aliases +#define ReductionsCounter heap_regs->call_counters.reductions +#define PredEntriesCounter heap_regs->call_counters.reductions_retries +#define RetriesCounter heap_regs->call_counters.retries +#define ReductionsCounterOn heap_regs->call_counters.reductions_on +#define PredEntriesCounterOn heap_regs->call_counters.reductions_retries_on +#define RetriesCounterOn heap_regs->call_counters.retries_on #define ForeignCodeLoaded heap_regs->foreign_code_loaded #define Yap_LibDir heap_regs->yap_lib_dir #define AGCHook heap_regs->agc_hook @@ -491,10 +509,10 @@ typedef struct various_codes { #define SizeOfOverflow heap_regs->size_of_overflow #define LastWtimePtr heap_regs->last_wtime #ifdef COROUTINING -#define WakeUpCode heap_regs->wake_up_code -#define WokenGoals heap_regs->woken_goals -#define MutableList heap_regs->mutable_list -#define AttsMutableList heap_regs->atts_mutable_list +#define WakeUpCode heap_regs->wake_up_code +#define WokenGoals heap_regs->woken_goals +#define MutableList heap_regs->mutable_list +#define AttsMutableList heap_regs->atts_mutable_list #endif #if defined(YAPOR) || defined(THREADS) #define FreeBlocksLock heap_regs->free_blocks_lock diff --git a/H/YapOpcodes.h b/H/YapOpcodes.h index 4387806eb..043fb584a 100644 --- a/H/YapOpcodes.h +++ b/H/YapOpcodes.h @@ -252,6 +252,11 @@ OPCODE(profiled_retry_me ,ld), OPCODE(profiled_trust_me ,ld), OPCODE(profiled_retry_and_mark ,ld), + OPCODE(count_call ,l), + OPCODE(count_retry ,l), + OPCODE(count_retry_me ,ld), + OPCODE(count_trust_me ,ld), + OPCODE(count_retry_and_mark ,ld), OPCODE(try_logical_pred ,l), OPCODE(trust_logical_pred ,l), OPCODE(alloc_for_logical_pred ,EC), diff --git a/H/compile.h b/H/compile.h index ec6bdd942..684244db6 100644 --- a/H/compile.h +++ b/H/compile.h @@ -150,6 +150,8 @@ typedef enum compiler_op { f_val_op, enter_profiling_op, retry_profiled_op, + count_call_op, + count_retry_op, restore_tmps_op, restore_tmps_and_skip_op, empty_call_op, @@ -273,3 +275,5 @@ extern jmp_buf CompilerBotch; extern int profiling; +extern int call_counting; + diff --git a/H/rheap.h b/H/rheap.h index 55e4a489f..779954210 100644 --- a/H/rheap.h +++ b/H/rheap.h @@ -599,6 +599,8 @@ RestoreClause(Clause *Cl, int mode) case _trust_me: case _profiled_retry_me: case _profiled_trust_me: + case _count_retry_me: + case _count_trust_me: case _try_me0: case _retry_me0: case _trust_me0: @@ -617,6 +619,7 @@ RestoreClause(Clause *Cl, int mode) case _spy_or_trymark: case _try_and_mark: case _profiled_retry_and_mark: + case _count_retry_and_mark: case _retry_and_mark: case _try_clause: case _retry: @@ -646,7 +649,9 @@ RestoreClause(Clause *Cl, int mode) break; /* instructions type l */ case _enter_profiling: + case _count_call: case _retry_profiled: + case _count_retry: case _try_logical_pred: case _trust_logical_pred: case _execute: diff --git a/Makefile.in b/Makefile.in index 5822a0f37..cad80959f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -156,6 +156,7 @@ C_SOURCES= \ PL_SOURCES= \ $(srcdir)/pl/arith.yap $(srcdir)/pl/arrays.yap $(srcdir)/pl/boot.yap \ + $(srcdir)/pl/callcount.yap\ $(srcdir)/pl/checker.yap $(srcdir)/pl/consult.yap \ $(srcdir)/pl/corout.yap $(srcdir)/pl/debug.yap \ $(srcdir)/pl/directives.yap \ diff --git a/docs/yap.tex b/docs/yap.tex index e7e793dfc..97d3fa395 100644 --- a/docs/yap.tex +++ b/docs/yap.tex @@ -155,6 +155,7 @@ Built In Predicates * OS:: Access to Operating System Functionality * Term Modification:: Updating Prolog Terms * Profiling:: Profiling Prolog Execution +* Calls Execution Limits:: Limiting the Maximum Number of Reductions * Arrays:: Supporting Global and Local Arrays * Preds:: Information on Predicates * Misc:: Miscellaneous Predicates @@ -2034,6 +2035,7 @@ Builtins, Debugging, Syntax, Top * OS:: Access to Operating System Functionality * Term Modification:: Updating Prolog Terms * Profiling:: Profiling Prolog Execution +* Calls Execution Limits:: Limiting the Maximum Number of Reductions * Arrays:: Supporting Global and Local Arrays * Preds:: Information on Predicates * Misc:: Miscellaneous Predicates @@ -5646,7 +5648,7 @@ Unify the current value of mutable term @var{M} with term @var{D}. Set the current value of mutable term @var{M} to term @var{D}. @end table -@node Profiling, Arrays, Term Modification, Top +@node Profiling, Call Counting, Term Modification, Top @section Profiling Prolog Programs @cindex profiling @@ -5723,6 +5725,61 @@ Reset all profiling information. @end table +@node Call Counting, Arrays, Profiling, Top +@section Counting Calls + +@cindex Counting Calls +Predicates compiled with YAP's flag @code{call_counting} set to +@code{on} update counters on the numbers of calls and of +retries. Counters are actually decreasing counters, so that they can be +used as timers. Three counters are available: +@itemize @bullet +@item @code{calls}: number of predicate calls since execution started or since +system was reset; +@item @code{retries}: number of retries for predicates called since +execution started or since counters were reset; +@item @code{calls_and_retries}: count both on predicate calls and +retries. +@end itemize +These counters can be used to find out how many calls a certain +goal takes to execute. They can also be used as timers. + +These are the predicates that access and manipulate the call counters: + +@table @code +@item call_count_data(-@var{Calls}, -@var{Retries}, -@var{CallsAndRetries}) +@findex call_count_data/3 +@snindex call_count_data/3 +@cnindex call_count_data/3 +Give current call count data. The first argument gives the current value +for the @var{Calls} counter, next the @var{Retries} counter, and last +the @var{CallsAndRetries} counter. + +@item call_count_reset +@findex call_count_data/0 +@snindex call_count_data/0 +@cnindex call_count_data/0 +Reset call count counters. All timers are also reset. + +@item call_count(?@var{CallsMax}, ?@var{RetriesMax}, ?@var{CallsAndRetriesMax}) +@findex call_count_data/3 +@snindex call_count_data/3 +@cnindex call_count_data/3 +Set call count counter as timers. YAP will generate an exception +if one of the instantiated call counters decreases to 0. YAP will ignore +unbound arguments: +@itemize @bullet +@item @var{CallsMax}: throw the exception @code{call_counter} when the +counter @code{calls} reaches 0; +@item @var{RetriesMax}: throw the exception @code{retry_counter} when the +counter @code{retries} reaches 0; +@item @var{CallsAndRetriesMax}: throw the exception +@code{call_and_retry_counter} when the counter @code{calls_and_retries} +reaches 0. +@end itemize + +@end table + @node Arrays, Preds, Profiling , Top @section Arrays @@ -6036,6 +6093,14 @@ arguments to Yap after @code{--}. Read-only flag telling whether integers are bounded. The value depends on whether YAP uses the GMP library or not. +@item profiling +@findex call_counting (yap_flag/2 option) +@* +If @code{off} (default) do not compile call counting information for +procedures. If @code{on} compile predicates so that they calls and +retries to the predicate may be counted. Profiling data can be read through the +@code{call_count_data/3} built-in. + @item char_conversion [ISO] @findex char_conversion (yap_flag/2 option) @* diff --git a/m4/Yap.h.m4 b/m4/Yap.h.m4 index 3e9d87400..5eea2d0cc 100644 --- a/m4/Yap.h.m4 +++ b/m4/Yap.h.m4 @@ -10,7 +10,7 @@ * File: Yap.h.m4 * * mods: * * comments: main header file for YAP * -* version: $Id: Yap.h.m4,v 1.29 2002-06-17 15:28:00 vsc Exp $ * +* version: $Id: Yap.h.m4,v 1.30 2002-09-03 14:28:08 vsc Exp $ * *************************************************************************/ #include "config.h" @@ -102,7 +102,7 @@ #undef USE_THREADED_CODE #endif #define inline __inline -#define YAP_VERSION "Yap-4.3.21" +#define YAP_VERSION "Yap-4.3.23" #define BIN_DIR "c:\\Program Files\\Yap\\bin" #define LIB_DIR "c:\\Program Files\\Yap\\lib\\Yap" #define SHARE_DIR "c:\\Program Files\\Yap\\share\\Yap" @@ -220,6 +220,19 @@ #define SHORT_INTS 0 #endif +#ifdef USE_GMP +#ifdef __GNUC__ +typedef long long int SIGNED_YAP_LONG_LONG; +typedef unsigned long long int YAP_LONG_LONG; +#else +typedef long int SIGNED_YAP_LONG_LONG; +typedef unsigned long int YAP_LONG_LONG; +#endif +#else +typedef long int SIGNED_YAP_LONG_LONG; +typedef unsigned long int YAP_LONG_LONG; +#endif + #if DEBUG extern char Option[20]; #endif @@ -390,6 +403,7 @@ typedef enum { FATAL_ERROR, INTERNAL_ERROR, PURE_ABORT, + CALL_COUNTER_UNDERFLOW, /* ISO_ERRORS */ DOMAIN_ERROR_ARRAY_OVERFLOW, DOMAIN_ERROR_ARRAY_TYPE, @@ -435,9 +449,11 @@ typedef enum { PERMISSION_ERROR_OUTPUT_TEXT_STREAM, PERMISSION_ERROR_RESIZE_ARRAY, PERMISSION_ERROR_REPOSITION_STREAM, + PRED_ENTRY_COUNTER_UNDERFLOW, REPRESENTATION_ERROR_CHARACTER, REPRESENTATION_ERROR_CHARACTER_CODE, REPRESENTATION_ERROR_MAX_ARITY, + RETRY_COUNTER_UNDERFLOW, SYNTAX_ERROR, SYSTEM_ERROR, TYPE_ERROR_ARRAY, diff --git a/m4/Yatom.h.m4 b/m4/Yatom.h.m4 index d0cb7deaf..da26e534b 100644 --- a/m4/Yatom.h.m4 +++ b/m4/Yatom.h.m4 @@ -162,6 +162,7 @@ Inline(IsValProperty, PropFlags, int, flags, (flags == ValProperty) ) CodeOfPred holds the address of the correspondent C-function. */ typedef enum { + CountPredFlag = 0x4000000L, /* count calls to pred */ HiddenPredFlag = 0x2000000L, /* ! should ! across */ CArgsPredFlag = 0x1000000L, /* ! should ! across */ CutTransparentPredFlag = 0x800000L, /* ! should ! across */ diff --git a/pl/callcount.yap b/pl/callcount.yap new file mode 100644 index 000000000..d945abc49 --- /dev/null +++ b/pl/callcount.yap @@ -0,0 +1,36 @@ +/************************************************************************* +* * +* YAP Prolog * +* * +* Yap Prolog was developed at NCCUP - Universidade do Porto * +* * +* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * +* * +************************************************************************** +* * +* File: callcount.yap * +* Last rev: 8/2/02 * +* mods: * +* comments: Some profiling predicates available in yap * +* * +*************************************************************************/ + +call_count_data(Calls, Retries, Both) :- + '$call_count_info'(Calls, Retries, Both). + +call_count_reset :- + '$call_count_reset'. + +call_count(Calls, Retries, Both) :- + '$check_if_call_count_on'(Calls, CallsOn), + '$check_if_call_count_on'(Retries, RetriesOn), + '$check_if_call_count_on'(Both, BothOn), + '$call_count_set'(Calls, CallsOn, Retries, RetriesOn, Both, BothOn). + +'$check_if_call_count_on'(Calls, 1) :- integer(Calls), !. +'$check_if_call_count_on'(Calls, 0) :- var(Calls), !. +'$check_if_call_count_on'(Calls, _) :- + throw(error(type_error(integer,Calls),call_count(A))). + + + diff --git a/pl/directives.yap b/pl/directives.yap index a3fc51850..e3a44f17e 100644 --- a/pl/directives.yap +++ b/pl/directives.yap @@ -181,6 +181,9 @@ yap_flag(dollar_as_lower_case,off) :- yap_flag(profiling,X) :- (var(X); X = on; X = off), !, '$is_profiled'(X). +yap_flag(call_counting,X) :- (var(X); X = on; X = off), !, + '$is_call_counted'(X). + yap_flag(bounded,X) :- var(X), !, '$access_yap_flags'(0, X1), diff --git a/pl/init.yap b/pl/init.yap index f8be620a2..25806efd5 100644 --- a/pl/init.yap +++ b/pl/init.yap @@ -58,6 +58,7 @@ false :- fail. % with meta-predicate expansion being invoked 'modules.yap', 'profile.yap', + 'callcount.yap', 'load_foreign.yap', 'sockets.yap', 'sort.yap',