a few more fixes to support timing and to improve message queues.

git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1012 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
vsc 2004-03-02 16:44:58 +00:00
parent 4eeceb6549
commit ddc7b3a0bc
13 changed files with 136 additions and 134 deletions

View File

@ -359,7 +359,7 @@ atom_gc(void)
int gc_trace = 0;
Int time_start, agc_time;
UInt time_start, agc_time;
if (Yap_GetValue(AtomGcTrace) != TermNil)
gc_trace = 1;
agc_calls++;

View File

@ -502,7 +502,7 @@ Yap_AdjustRegs(int n)
static int
static_growheap(long size, int fix_code, struct intermediates *cip)
{
Int start_growth_time, growth_time;
UInt start_growth_time, growth_time;
int gc_verbose;
UInt hole = 0L;
@ -566,7 +566,7 @@ static_growheap(long size, int fix_code, struct intermediates *cip)
static int
static_growglobal(long size, CELL **ptr)
{
Int start_growth_time, growth_time;
UInt start_growth_time, growth_time;
int gc_verbose;
/* adjust to a multiple of 256) */
@ -804,7 +804,7 @@ execute_growstack(long size, int from_trail)
static int
growstack(long size)
{
Int start_growth_time, growth_time;
UInt start_growth_time, growth_time;
int gc_verbose;
/* adjust to a multiple of 256) */
@ -909,7 +909,7 @@ AdjustScannerStacks(TokEntry **tksp, VarEntry **vep)
int
Yap_growstack_in_parser(tr_fr_ptr *old_trp, TokEntry **tksp, VarEntry **vep)
{
Int start_growth_time, growth_time;
UInt start_growth_time, growth_time;
int gc_verbose;
long size = sizeof(CELL)*(LCL0-(CELL *)Yap_GlobalBase);
@ -966,7 +966,7 @@ Yap_growstack_in_parser(tr_fr_ptr *old_trp, TokEntry **tksp, VarEntry **vep)
static int do_growtrail(long size)
{
Int start_growth_time = Yap_cputime(), growth_time;
UInt start_growth_time = Yap_cputime(), growth_time;
int gc_verbose = Yap_is_gc_verbose();
/* adjust to a multiple of 256) */
@ -1054,7 +1054,7 @@ Yap_growatomtable(void)
{
AtomHashEntry *ntb;
UInt nsize = 4*AtomHashTableSize-1, i;
Int start_growth_time = Yap_cputime(), growth_time;
UInt start_growth_time = Yap_cputime(), growth_time;
int gc_verbose = Yap_is_gc_verbose();
LOCK(SignalLock);

View File

@ -3025,7 +3025,7 @@ do_gc(Int predarity, CELL *current_env, yamop *nextop)
Int heap_cells = H-H0;
int gc_verbose = is_gc_verbose();
tr_fr_ptr old_TR;
Int m_time, c_time, time_start, gc_time;
UInt m_time, c_time, time_start, gc_time;
#if COROUTINING
CELL *max = (CELL *)Yap_ReadTimedVar(DelayedVars);
#else

View File

@ -783,6 +783,9 @@ InitCodes(void)
heap_regs->thread_handle[0].handle = pthread_self();
heap_regs->thread_handle[0].handle = pthread_self();
pthread_mutex_init(&ThreadHandle[0].tlock, NULL);
heap_regs->n_of_threads = 1;
heap_regs->n_of_threads_created = 1;
heap_regs->threads_total_time = 0;
#endif
#if defined(YAPOR) || defined(THREADS)
INIT_LOCK(heap_regs->bgl);
@ -790,7 +793,6 @@ InitCodes(void)
INIT_LOCK(heap_regs->heap_used_lock);
INIT_LOCK(heap_regs->heap_top_lock);
INIT_LOCK(heap_regs->dead_clauses_lock);
heap_regs->n_of_threads = 1;
heap_regs->heap_top_owner = -1;
{
int i;
@ -1168,6 +1170,8 @@ Yap_InitWorkspace(int Heap,
#else /* Yap */
Yap_InitMemory (Trail, Heap, Stack);
#endif /* YAPOR || TABLING */
Yap_InitTime ();
AtomHashTableSize = MaxHash;
HashChain = (AtomHashEntry *)Yap_AllocAtomSpace(sizeof(AtomHashEntry) * MaxHash);
if (HashChain == NULL) {

View File

@ -705,7 +705,7 @@ get_num(char *t)
return(TermNil);
}
static Int
static UInt
runtime(void)
{
return(Yap_cputime()-Yap_total_gc_time()-Yap_total_stack_shift_time());

View File

@ -233,11 +233,16 @@ bla bla
#include <sys/resource.h>
#endif
#if THREADS
#define StartOfTimes (*(ThreadHandle[worker_id].start_of_timesp))
#define last_time (*(ThreadHandle[worker_id].last_timep))
#else
/* since the point YAP was started */
static struct timeval StartOfTimes;
/* since last call to runtime */
static struct timeval last_time;
#endif
/* store user time in this variable */
static void
@ -245,13 +250,17 @@ InitTime (void)
{
struct rusage rusage;
#if THREADS
ThreadHandle[worker_id].start_of_timesp = (struct timeval *)malloc(sizeof(struct timeval));
ThreadHandle[worker_id].last_timep = (struct timeval *)malloc(sizeof(struct timeval));
#endif
getrusage(RUSAGE_SELF, &rusage);
last_time.tv_sec = StartOfTimes.tv_sec = rusage.ru_utime.tv_sec;
last_time.tv_usec = StartOfTimes.tv_usec = rusage.ru_utime.tv_usec;
}
Int
UInt
Yap_cputime (void)
{
struct rusage rusage;
@ -324,7 +333,7 @@ InitTime (void)
}
}
Int
UInt
Yap_cputime (void)
{
HANDLE hProcess = GetCurrentProcess();
@ -434,7 +443,7 @@ InitTime (void)
last_time = StartOfTimes = t.tms_utime;
}
Int
UInt
Yap_cputime (void)
{
struct tms t;
@ -475,7 +484,7 @@ InitTime (void)
}
Int
UInt
Yap_cputime (void)
{
struct timeval tp;
@ -2089,13 +2098,18 @@ Yap_InitSysbits (void)
}
#endif
InitPageSize();
InitTime ();
InitWTime ();
InitRandom ();
/* let the caller control signals as it sees fit */
InitSignals ();
}
void
Yap_InitTime(void)
{
InitTime();
}
void
Yap_ReInitWallTime (void)
{

View File

@ -76,6 +76,10 @@ thread_die(int wid, int always_die)
Prop p0;
LOCK(ThreadHandlesLock);
if (!always_die) {
/* called by thread itself */
ThreadsTotalTime += Yap_cputime();
}
if (ThreadHandle[wid].tdetach == MkAtomTerm(AtomTrue) ||
always_die) {
p0 = AbsPredProp(heap_regs->thread_handle[wid].local_preds);
@ -88,8 +92,11 @@ thread_die(int wid, int always_die)
}
Yap_KillStacks(wid);
heap_regs->wl[wid].active_signals = 0L;
heap_regs->wl[wid].active_signals = 0L;
free(heap_regs->wl[wid].scratchpad.ptr);
free(ThreadHandle[wid].default_yaam_regs);
free(ThreadHandle[wid].start_of_timesp);
free(ThreadHandle[wid].last_timep);
ThreadHandle[wid].in_use = FALSE;
pthread_mutex_destroy(&(ThreadHandle[wid].tlock));
}
@ -109,8 +116,11 @@ thread_run(void *widp)
ThreadHandle[myworker_id].default_yaam_regs = standard_regs;
pthread_setspecific(Yap_yaamregs_key, (void *)standard_regs);
worker_id = myworker_id;
/* I exist */
NOfThreadsCreated++;
Yap_InitExStacks(ThreadHandle[myworker_id].ssize, ThreadHandle[myworker_id].tsize);
CurrentModule = ThreadHandle[myworker_id].cmod;
Yap_InitTime();
Yap_InitYaamRegs();
{
Yap_ReleasePreAllocCodeSpace(Yap_PreAllocCodeSpace());
@ -176,10 +186,8 @@ p_thread_join(void)
UNLOCK(ThreadHandlesLock);
if (pthread_join(ThreadHandle[tid].handle, NULL) < 0) {
/* ERROR */
fprintf(stderr, "join error %d %d\n", tid, errno);
return FALSE;
}
fprintf(stderr, "join %d\n", tid);
return TRUE;
}
@ -406,6 +414,31 @@ p_no_threads(void)
return FALSE;
}
static Int
p_nof_threads(void)
{ /* '$nof_threads'(+P) */
int i = 0, wid;
LOCK(ThreadHandlesLock);
for (wid = 0; wid < MAX_WORKERS; wid++) {
if (ThreadHandle[wid].in_use)
i++;
}
UNLOCK(ThreadHandlesLock);
return Yap_unify(ARG1,MkIntegerTerm(i));
}
static Int
p_nof_threads_created(void)
{ /* '$nof_threads'(+P) */
return Yap_unify(ARG1,MkIntTerm(NOfThreadsCreated));
}
static Int
p_thread_runtime(void)
{ /* '$thread_runtime'(+P) */
return Yap_unify(ARG1,MkIntegerTerm(ThreadsTotalTime));
}
void Yap_InitThreadPreds(void)
{
Yap_InitCPred("$no_threads", 0, p_no_threads, 0);
@ -430,6 +463,9 @@ void Yap_InitThreadPreds(void)
Yap_InitCPred("$cond_broadcast", 1, p_cond_broadcast, SafePredFlag);
Yap_InitCPred("$cond_wait", 2, p_cond_wait, SafePredFlag);
Yap_InitCPred("$signal_thread", 1, p_thread_signal, SafePredFlag);
Yap_InitCPred("$nof_threads", 1, p_nof_threads, SafePredFlag);
Yap_InitCPred("$nof_threads_created", 1, p_nof_threads_created, SafePredFlag);
Yap_InitCPred("$thread_runtime", 1, p_thread_runtime, SafePredFlag);
}
#else
@ -440,9 +476,30 @@ p_no_threads(void)
return TRUE;
}
static Int
p_nof_threads(void)
{ /* '$nof_threads'(+P) */
return Yap_unify(ARG1,MkIntTerm(1));
}
static Int
p_nof_threads_created(void)
{ /* '$nof_threads'(+P) */
return Yap_unify(ARG1,MkIntTerm(1));
}
static Int
p_thread_runtime(void)
{ /* '$thread_runtime'(+P) */
return Yap_unify(ARG1,MkIntTerm(0));
}
void Yap_InitThreadPreds(void)
{
Yap_InitCPred("$no_threads", 0, p_no_threads, 0);
Yap_InitCPred("$no_threads", 0, p_no_threads, SafePredFlag);
Yap_InitCPred("$nof_threads", 1, p_nof_threads, SafePredFlag);
Yap_InitCPred("$nof_threads_created", 1, p_nof_threads_created, SafePredFlag);
Yap_InitCPred("$thread_runtime", 1, p_thread_runtime, SafePredFlag);
}

View File

@ -10,7 +10,7 @@
* File: Heap.h *
* mods: *
* comments: Heap Init Structure *
* version: $Id: Heap.h,v 1.60 2004-02-25 19:06:31 rslopes Exp $ *
* version: $Id: Heap.h,v 1.61 2004-03-02 16:44:55 vsc Exp $ *
*************************************************************************/
/* information that can be stored in Code Space */
@ -76,6 +76,10 @@ typedef struct thandle {
struct pred_entry *local_preds;
pthread_t handle;
pthread_mutex_t tlock;
#if HAVE_GETRUSAGE
struct timeval *start_of_timesp;
struct timeval *last_timep;
#endif
} yap_thandle;
#endif
@ -192,12 +196,16 @@ typedef struct various_codes {
Int yap_flags_field[NUMBER_OF_YAP_FLAGS];
char *char_conversion_table;
char *char_conversion_table2;
#if THREADS
unsigned int n_of_threads; /* number of threads and processes in system */
unsigned int n_of_threads_created; /* number of threads created since start */
UInt threads_total_time; /* total run time for dead threads */
#endif
#if defined(YAPOR) || defined(THREADS)
lockvar heap_used_lock; /* protect HeapUsed */
lockvar heap_top_lock; /* protect HeapTop */
lockvar dead_clauses_lock; /* protect DeadClauses */
int heap_top_owner;
unsigned int n_of_threads; /* number of threads and processes in system */
#ifdef LOW_LEVEL_TRACER
lockvar low_level_trace_lock;
#endif
@ -670,6 +678,8 @@ struct various_codes *heap_regs;
#define HeapTopLock heap_regs->heap_top_lock
#define HeapTopOwner heap_regs->heap_top_owner
#define NOfThreads heap_regs->n_of_threads
#define NOfThreadsCreated heap_regs->n_of_threads_created
#define ThreadsTotalTime heap_regs->threads_total_time
#define HeapUsedLock heap_regs->heap_used_lock
#define DeadClausesLock heap_regs->dead_clauses_lock
#endif

View File

@ -10,7 +10,7 @@
* File: Yap.proto *
* mods: *
* comments: Function declarations for YAP *
* version: $Id: Yapproto.h,v 1.48 2004-02-25 19:06:31 rslopes Exp $ *
* version: $Id: Yapproto.h,v 1.49 2004-03-02 16:44:58 vsc Exp $ *
*************************************************************************/
/* prototype file for Yap */
@ -266,7 +266,7 @@ void STD_PROTO(Yap_signal,(yap_signals));
/* sysbits.c */
void STD_PROTO(Yap_set_fpu_exceptions,(int));
Int STD_PROTO(Yap_cputime,(void));
UInt STD_PROTO(Yap_cputime,(void));
Int STD_PROTO(Yap_walltime,(void));
int STD_PROTO(Yap_dir_separator,(int));
int STD_PROTO(Yap_volume_header,(char *));
@ -278,6 +278,7 @@ void STD_PROTO(Yap_cputime_interval,(Int *,Int *));
void STD_PROTO(Yap_walltime_interval,(Int *,Int *));
void STD_PROTO(Yap_InitSysbits,(void));
void STD_PROTO(Yap_InitSysPreds,(void));
void STD_PROTO(Yap_InitTime,(void));
int STD_PROTO(Yap_TrueFileName, (char *, char *, int));
int STD_PROTO(Yap_ProcessSIGINT,(void));
double STD_PROTO(Yap_random, (void));

View File

@ -172,6 +172,7 @@ PL_SOURCES= \
$(srcdir)/pl/protect.yap $(srcdir)/pl/setof.yap \
$(srcdir)/pl/signals.yap \
$(srcdir)/pl/sockets.yap $(srcdir)/pl/sort.yap \
$(srcdir)/pl/statistics.yap \
$(srcdir)/pl/strict_iso.yap \
$(srcdir)/pl/tabling.yap $(srcdir)/pl/threads.yap \
$(srcdir)/pl/utils.yap \

View File

@ -66,6 +66,7 @@ not(G) :- '$current_module'(Module), '$meta_call'(not(G),Module).
'sockets.yap',
'sort.yap',
'setof.yap',
'statistics.yap',
'strict_iso.yap',
'tabling.yap',
'threads.yap',

View File

@ -277,7 +277,8 @@ message_queue_create(Cond) :-
var(Cond), !,
mutex_create(Mutex),
'$cond_create'(Cond),
recorda('$queue',q(Cond,Mutex,Cond), _).
'$mq_iname'(Cond, CName),
recorda('$queue',q(Cond,Mutex,Cond,CName), _).
message_queue_create(Name) :-
atom(Name),
recorded('$thread_alias',[Name|_],_), !,
@ -291,18 +292,26 @@ message_queue_create(Name) :-
'$create_mq'(Name) :-
mutex_create(Mutex),
'$cond_create'(Cond),
recorda('$queue',q(Name,Mutex,Cond),_).
'$mq_iname'(Name, CName),
recorda('$queue',q(Name,Mutex,Cond, CName),_).
'$mq_iname'(I,X) :-
integer(I), !,
number_codes(I,Codes),
atom_codes(X, [0'$,0'M,0'Q,0'_|Codes]).
'$mq_iname'(A,X) :-
atom_concat('$MQ_NAME_KEY_',A,X).
message_queue_destroy(Name) :-
var(Name), !,
'$do_error'(instantiation_error,message_queue_destroy(Name)).
message_queue_destroy(Queue) :-
recorded('$queue',q(Queue,Mutex,Cond),R), !,
recorded('$queue',q(Queue,Mutex,Cond,CName),R), !,
erase(R),
'$cond_destroy'(Cond),
mutex_destroy(Mutex),
'$clean_mqueue'(Queue).
'$clean_mqueue'(CName).
message_queue_destroy(Queue) :-
atom(Queue), !,
'$do_error'(existence_error(queue,Queue),message_queue_destroy(QUeue)).
@ -310,7 +319,7 @@ message_queue_destroy(Name) :-
'$do_error'(type_error(atom,Name),message_queue_destroy(Name)).
'$clean_mqueue'(Queue) :-
recorded('$msg_queue',q(Queue,_),R),
recorded(Queue,_,R),
erase(R),
fail.
'$clean_mqueue'(_).
@ -319,9 +328,9 @@ thread_send_message(Queue, Term) :-
recorded('$thread_alias',[Queue|Id],_), !,
thread_send_message(Id, Term).
thread_send_message(Queue, Term) :-
recorded('$queue',q(Queue,Mutex,Cond),_),
recorded('$queue',q(Queue,Mutex,Cond,Key),_),
mutex_lock(Mutex),
recordz('$msg_queue',q(Queue,Term),_),
recordz(Key,Term,_),
'$cond_broadcast'(Cond),
mutex_unlock(Mutex).
@ -330,29 +339,29 @@ thread_get_message(Term) :-
thread_get_message(Id, Term).
thread_get_message(Queue, Term) :-
recorded('$queue',q(Queue,Mutex,Cond),_),
recorded('$queue',q(Queue,Mutex,Cond,Key),_),
mutex_lock(Mutex),
'$thread_get_message_loop'(Queue, Term, Mutex, Cond).
'$thread_get_message_loop'(Key, Term, Mutex, Cond).
'$thread_get_message_loop'(Queue, Term, Mutex, _) :-
recorded('$msg_queue',q(Queue,Term),R), !,
'$thread_get_message_loop'(Key, Term, Mutex, _) :-
recorded(Key,Term,R), !,
erase(R),
mutex_unlock(Mutex).
'$thread_get_message_loop'(Queue, Term, Mutex, Cond) :-
'$thread_get_message_loop'(Key, Term, Mutex, Cond) :-
'$cond_wait'(Cond, Mutex),
'$thread_get_message_loop'(Queue, Term, Mutex, Cond).
'$thread_get_message_loop'(Key, Term, Mutex, Cond).
thread_peek_message(Term) :-
'$thread_self'(Id),
thread_peek_message(Id, Term).
thread_peek_message(Queue, Term) :-
recorded('$queue',q(Queue,Mutex,_),_),
recorded('$queue',q(Queue,Mutex,_,Key),_),
mutex_lock(Mutex),
'$thread_peek_message2'(Queue, Term, Mutex).
'$thread_peek_message2'(Key, Term, Mutex).
'$thread_peek_message2'(Queue, Term, Mutex) :-
recorded('$msg_queue',q(Queue,Term),_), !,
'$thread_peek_message2'(Key, Term, Mutex) :-
recorded(Key,Term,_), !,
mutex_unlock(Mutex).
'$thread_peek_message2'(_, _, Mutex) :-
mutex_unlock(Mutex),

View File

@ -371,101 +371,6 @@ current_key(A,K) :-
'$current_immediate_key'(A,K).
%%% User interface for statistics
statistics :-
'$runtime'(Runtime,_),
'$cputime'(CPUtime,_),
'$walltime'(Walltime,_),
'$statistics_heap_info'(HpSpa, HpInUse),
'$statistics_heap_max'(HpMax),
'$statistics_trail_info'(TrlSpa, TrlInUse),
'$statistics_trail_max'(TrlMax),
'$statistics_stacks_info'(StkSpa, GlobInU, LocInU),
'$statistics_global_max'(GlobMax),
'$statistics_local_max'(LocMax),
'$inform_heap_overflows'(NOfHO,TotHOTime),
'$inform_stack_overflows'(NOfSO,TotSOTime),
'$inform_trail_overflows'(NOfTO,TotTOTime),
'$inform_gc'(NOfGC,TotGCTime,TotGCSize),
'$inform_agc'(NOfAGC,TotAGCTime,TotAGCSize),
'$statistics'(Runtime,CPUtime,Walltime,HpSpa,HpInUse,HpMax,TrlSpa, TrlInUse,TrlMax,StkSpa, GlobInU, LocInU,GlobMax,LocMax,NOfHO,TotHOTime,NOfSO,TotSOTime,NOfTO,TotTOTime,NOfGC,TotGCTime,TotGCSize,NOfAGC,TotAGCTime,TotAGCSize).
'$statistics'(Runtime,CPUtime,Walltime,HpSpa,HpInUse,HpMax,TrlSpa, TrlInUse,_TrlMax,StkSpa, GlobInU, LocInU,GlobMax,LocMax,NOfHO,TotHOTime,NOfSO,TotSOTime,NOfTO,TotTOTime,NOfGC,TotGCTime,TotGCSize,NOfAGC,TotAGCTime,TotAGCSize) :-
TotalMemory is HpSpa+StkSpa+TrlSpa,
'$format'(user_error,"memory (total)~t~d bytes~35+~n", [TotalMemory]),
'$format'(user_error," program space~t~d bytes~35+", [HpSpa]),
'$format'(user_error,":~t ~d in use~19+", [HpInUse]),
HpFree is HpSpa-HpInUse,
'$format'(user_error,",~t ~d free~19+~n", [HpFree]),
'$format'(user_error,"~t ~d max~73+~n", [HpMax]),
'$format'(user_error," stack space~t~d bytes~35+", [StkSpa]),
StackInUse is GlobInU+LocInU,
'$format'(user_error,":~t ~d in use~19+", [StackInUse]),
StackFree is StkSpa-StackInUse,
'$format'(user_error,",~t ~d free~19+~n", [StackFree]),
'$format'(user_error," global stack:~t~35+", []),
'$format'(user_error," ~t ~d in use~19+", [GlobInU]),
'$format'(user_error,",~t ~d max~19+~n", [GlobMax]),
'$format'(user_error," local stack:~t~35+", []),
'$format'(user_error," ~t ~d in use~19+", [LocInU]),
'$format'(user_error,",~t ~d max~19+~n", [LocMax]),
'$format'(user_error," trail stack~t~d bytes~35+", [TrlSpa]),
'$format'(user_error,":~t ~d in use~19+", [TrlInUse]),
TrlFree is TrlSpa-TrlInUse,
'$format'(user_error,",~t ~d free~19+~n", [TrlFree]),
OvfTime is (TotHOTime+TotSOTime+TotTOTime)/1000,
'$format'(user_error,"~n~t~3f~12+ sec. for ~w code, ~w stack, and ~w trail space overflows~n",
[OvfTime,NOfHO,NOfSO,NOfTO]),
TotGCTimeF is float(TotGCTime)/1000,
'$format'(user_error,"~t~3f~12+ sec. for ~w garbage collections which collected ~d bytes~n",
[TotGCTimeF,NOfGC,TotGCSize]),
TotAGCTimeF is float(TotAGCTime)/1000,
'$format'(user_error,"~t~3f~12+ sec. for ~w atom garbage collections which collected ~d bytes~n",
[TotAGCTimeF,NOfAGC,TotAGCSize]),
RTime is float(Runtime)/1000,
'$format'(user_error,"~t~3f~12+ sec. runtime~n", [RTime]),
CPUTime is float(CPUtime)/1000,
'$format'(user_error,"~t~3f~12+ sec. cputime~n", [CPUTime]),
WallTime is float(Walltime)/1000,
'$format'(user_error,"~t~3f~12+ sec. elapsed time~n~n", [WallTime]),
fail.
'$statistics'(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_).
statistics(runtime,[T,L]) :-
'$runtime'(T,L).
statistics(cputime,[T,L]) :-
'$cputime'(T,L).
statistics(walltime,[T,L]) :-
'$walltime'(T,L).
%statistics(core,[_]).
%statistics(memory,[_]).
statistics(heap,[Hp,HpF]) :-
'$statistics_heap_info'(HpM, Hp),
HpF is HpM-Hp.
statistics(program,Info) :-
statistics(heap,Info).
statistics(global_stack,[GlobInU,GlobFree]) :-
'$statistics_stacks_info'(StkSpa, GlobInU, LocInU),
GlobFree is StkSpa-GlobInU-LocInU.
statistics(local_stack,[LocInU,LocFree]) :-
'$statistics_stacks_info'(StkSpa, GlobInU, LocInU),
LocFree is StkSpa-GlobInU-LocInU.
statistics(trail,[TrlInUse,TrlFree]) :-
'$statistics_trail_info'(TrlSpa, TrlInUse),
TrlFree is TrlSpa-TrlInUse.
statistics(garbage_collection,[NOfGC,TotGCSize,TotGCTime]) :-
'$inform_gc'(NOfGC,TotGCTime,TotGCSize).
statistics(stack_shifts,[NOfHO,NOfSO,NOfTO]) :-
'$inform_heap_overflows'(NOfHO,_),
'$inform_stack_overflows'(NOfSO,_),
'$inform_trail_overflows'(NOfTO,_).
key_statistics(Key, NOfEntries, TotalSize) :-
key_statistics(Key, NOfEntries, ClSize, IndxSize),
TotalSize is ClSize+IndxSize.
%%% The unknown predicate,
% informs about what the user wants to be done when
% there are no clauses for a certain predicate */