123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135(* Signature & type definition *)(* ************************************************************************ *)exceptionOut_of_timeexceptionOut_of_spacemoduletypeS=sigtypetvalsetup:time:float->size:float->tvaldelete:t->unitendtypet=(moduleS)(* Dummy alarms *)(* ************************************************************************ *)moduleDummy:S=structtypet=unitletsetup~time:_~size:_=()letdelete()=()endletdummy:t=(moduleDummy)(* helper functions *)(* ************************************************************************ *)letcheck_timetime_limit=letstart_time=Unix.gettimeofday()infunction()->lett=Unix.gettimeofday()-.start_timeinift>time_limitthenraiseOut_of_time(* This function analyze the current size of the heap
TODO: take into account the minor heap size + stack size
TODO: should we only consider the live words ? *)letcheck_sizesize_limit()=letheap_size=(Gc.quick_stat()).Gc.heap_wordsinlets=floatheap_size*.floatSys.word_size/.8.inifs>size_limitthenraiseOut_of_space(* Linux alarms *)(* ************************************************************************ *)moduleLinux:S=structtypet=Gc.alarmoption(* There are two kinds of limits we want to enforce:
- a size limit: we use the Gc's alarm function to enforce the limit
on the size of the RAM used
- a time limit: the Gc alarm is not reliable to enforce this, so instead
we use the Unix.timer facilities *)letsetup~time:t~size:s=(* The Unix.timer works by sending a Sys.sigalrm, so in order to use it,
we catch it and raise the Out_of_time exception. *)Sys.set_signalSys.sigalrm(Sys.Signal_handle(fun_->raiseOut_of_time));ift<>infinitythenignore(Unix.setitimerUnix.ITIMER_REALUnix.{it_value=t;it_interval=0.01});ifs<>infinitythen(Some(Gc.create_alarm(check_sizes)))elseNoneletdeletealarm=(* it's alwyas safe to delete the timer here,
even if none was present before. *)ignore(Unix.setitimerUnix.ITIMER_REALUnix.{it_value=0.;it_interval=0.});matchalarmwithNone->()|Somealarm->Gc.delete_alarmalarmendletlinux:t=(moduleLinux)(* Windows alarms *)(* ************************************************************************ *)moduleWindows:S=structtypet=Gc.alarmoption(* This function analyze the current size of the heap
TODO: take into account the minor heap size + stack size
TODO: should we only consider the live words ? *)letchecktime_limitsize_limit=letcheck_t=check_timetime_limitinfunction()->check_t();check_sizesize_limit()(* There are two kinds of limits we want to enforce:
- a size limit: we use the Gc's alarm function to enforce the limit
on the size of the RAM used
- a time limit: the Gc alarm is not reliable to enforce this, but the
Unix.timer facilities are not emulated on windows, so we still use
the GC alarm for this, even if it's not that great.
TODO: allow to use the time limit only for some passes *)letsetup~time:t~size:s=ifs<>infinity||t<>infinitythen(Some(Gc.create_alarm(checkts)))elseNoneletdelete=function|None->()|Somealarm->Gc.delete_alarmalarmendletwindows:t=(moduleWindows)(* Default alarms *)(* ************************************************************************ *)letdefault=matchSys.os_typewith|"Unix"->linux|"Win32"->windows|"Cygwin"->windows(* maybe linux would work, but better safe than sorry *)|_->dummy