/*  CPU_TIME.PL  */
 
 
/*
This file defines predicates for obtaining CPU time and timing how long
goals take to execute.
 
cpu_time( Time- ):
    Unify Time with the accumulated CPU time for the current run of the
    POP-11 Prolog system in seconds.
 
cpu_time( Goal+, Duration- ):
    Unifies Duration with the CPU time taken to call Goal once until it
    either succeeds or fails. Any variables in Goal should be (or be
    thought of as) existentially quantified, as alternative solutions
    will be pruned away, and cpu_time/2 will succeed either when Goal
    fails. cpu_time/2 should only be used when Goal takes a long time.
 
cpu_time( N+, Goal+, Duration- ):
    Unifies Duration with the CPU time taken to (call Goal until it
    either succeeds or fails) N times. Any variables in Goal should be
    (or be thought of as) existentially quantified, as there is a
    failure-driven loop inside cpu_time/3 and variables in Goal will not
    be left bound. If Goal takes a short time, you should use cpu_time/3
    with a large value of N to time it.
 
The predicates are taken from Chapter 3 of "The Craft of Prolog" by
Richard O'Keefe. I have adapted them to Poplog: they obtain the CPU time
by calling the built-in function 'systime' which returns the accumulated
CPU time for the current run of the POP-11 system in hundredths of a
second.
*/
 
 
cpu_time( Time ) :-
    prolog_eval( apply(valof(systime)), HundredthSecs ),
    Time is HundredthSecs * 0.01.
 
 
cpu_time( Goal, Duration ) :-
    prolog_eval( apply(valof(systime)), Start ),
    ( call(Goal) -> true ; true ),
    prolog_eval( apply(valof(systime)), End ),
    Duration is (End-Start) * 0.01.
 
 
cpu_time( N, Goal, Duration ) :-
    prolog_eval( apply(valof(systime)), T0 ),
    ( call(( repeat(N), (Goal -> fail ; fail) )) ; true ),
    prolog_eval( apply(valof(systime)), T1 ),
    ( call(( repeat(N), (true -> fail ; fail) )) ; true ),
    prolog_eval( apply(valof(systime)), T2 ),
    Duration is ( (T1-T0) - (T2-T1) ) * 0.01.
 
 
repeat(N) :-
    integer(N), N > 0,
    repeat_1(N).
 
 
repeat_1(1) :- !.
 
repeat_1(_).
 
repeat_1(N) :-
    M is N-1,
    repeat_1(M).                    
