Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file landmark.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817(* This file is released under the terms of an MIT-like license. *)(* See the attached LICENSE file. *)(* Copyright 2016 by LexiFi. *)externalclock:unit->Int64.t="caml_highres_clock"exceptionLandmarkFailureofstringmoduleGraph=GraphmoduleSparseArray=structtype'at={mutablekeys:intarray;mutabledata:'aarray;mutablesize:int;}(* /!\ Dummy cannot be resized. *)letdummy()={keys=[||];data=[||];size=0}letmakenulln=letn=maxn1in{keys=Array.maken0;data=Array.makennull;size=0;}letresetsparse_array=sparse_array.size<-0letget{keys;data;size}id=letmin=ref0inletmax=ref(size-1)inwhile!min<!maxdoletmiddle=(!min+!max)/2inifArray.unsafe_getkeysmiddle<idthenmin:=middle+1elsemax:=middledone;letidx=!mininifidx=!max&&Array.unsafe_getkeysidx=idthenArray.unsafe_getdataidxelseraiseNot_foundletswapaij=lett=a.(i)ina.(i)<-a.(j);a.(j)<-tletvalues{data;size;_}=letresult=ref[]infork=0tosize-1doresult:=data.(k)::!result;done;List.rev!resultletbubble{keys;data;size}=letpos=refsizeinletkey=keys.(size)inwhileletp=!posinletq=p-1inifkey<keys.(q)thenbeginswapkeyspq;swapdatapq;pos:=q;q>0endelsefalsedo()doneletis_full({keys;size;_})=Array.lengthkeys=sizeletresize({keys;data;size}assparse_array)=ifis_fullsparse_arraythenbeginassert(size>0);letnew_length=(2*(size+1))-1insparse_array.keys<-Array.makenew_length0;sparse_array.data<-Array.makenew_lengthsparse_array.data.(0);Array.blitkeys0sparse_array.keys0size;Array.blitdata0sparse_array.data0size;endletsetsparse_arrayidnode=resizesparse_array;letsize=sparse_array.sizeinsparse_array.keys.(size)<-id;sparse_array.data.(size)<-node;ifsize>0thenbubblesparse_array;sparse_array.size<-sparse_array.size+1endmoduleStack=structtype'at={mutabledata:'aarray;mutablesize:int}(* /!\ Dummy cannot be resized. *)letdummy()={data=[||];size=0}letmakenulln={data=Array.make(max1n)null;size=0}letsize{size;_}=sizeletresize({size;data}asstack)=ifsize=Array.lengthdatathenbeginassert(size>0);letnew_length=(2*(size+1))-1instack.data<-Array.makenew_lengthdata.(0);Array.blitdata0stack.data0size;endletpush({size;_}asstack)x=resizestack;stack.data.(size)<-x;stack.size<-size+1letpopstack=stack.size<-stack.size-1;stack.data.(stack.size)letto_array{data;size;_}=Array.subdata0sizeendtypelandmark={id:int;kind:Graph.kind;name:string;location:string;mutablelast_parent:node;mutablelast_son:node;mutablelast_self:node;}andnode={landmark:landmark;id:int;sons:nodeSparseArray.t;fathers:nodeStack.t;mutablecalls:int;mutablerecursive_calls:int;mutabletimestamp:Int64.t;distrib:floatStack.t;floats:floats;}andfloats={mutabletime:float;mutableallocated_bytes:float;mutableallocated_bytes_stamp:float;mutablesys_time:float;mutablesys_timestamp:float;}andcounter=landmarkandsampler=landmarkletnew_floats()={time=0.0;allocated_bytes=0.0;allocated_bytes_stamp=0.0;sys_time=0.0;sys_timestamp=0.0}letreclandmark_root={kind=Graph.Root;id=0;name="ROOT";location=__FILE__;last_parent=dummy_node;last_son=dummy_node;last_self=dummy_node;}anddummy_node={landmark=landmark_root;id=0;sons=SparseArray.dummy();fathers=Stack.dummy();floats=new_floats();calls=0;recursive_calls=0;distrib=Stack.dummy();timestamp=Int64.zero}(** STATE **)typeprofile_output=|Silent|Temporaryofstringoption|Channelofout_channeltypetextual_option={threshold:float}typeprofile_format=|JSON|Textualoftextual_optionletprofiling_ref=reffalseletprofile_with_debug=reffalseletprofile_with_allocated_bytes=reffalseletprofile_with_sys_time=reffalseletprofile_output=refSilentletprofile_format=ref(Textual{threshold=1.0})letprofile_recursive=reffalseletprofiling()=!profiling_ref(** REGISTERING **)letlast_landmark_id=ref1letnew_landmarknamelocationkind=letid=!last_landmark_idinincrlast_landmark_id;{id;name;location;kind;last_parent=dummy_node;last_self=dummy_node;last_son=dummy_node;}letnode_id_ref=ref0letallocated_nodes=ref[]letnew_nodelandmark=if!profile_with_debugthenPrintf.eprintf"[Profiling] Allocating new node for %s...\n%!"landmark.name;letid=!node_id_refinincrnode_id_ref;letnode={landmark;id;fathers=Stack.makedummy_node1;distrib=Stack.make0.00;sons=SparseArray.makedummy_node7;calls=0;recursive_calls=0;timestamp=Int64.zero;floats=new_floats();}inallocated_nodes:=node::!allocated_nodes;nodeletcurrent_root_node=ref(new_nodelandmark_root)letregistered_landmarks=ref[landmark_root]letlandmark_of_idid=List.nth!registered_landmarks((List.length!registered_landmarks)-(id+1))letregister_generic?locationkindnamecall_stack=letlocation=matchlocationwith|Somename->name|None->letbacktrace_slots=Printexc.backtrace_slotscall_stackinmatchbacktrace_slotswith|Some[||]|None->"unknown"|Someslots->letlast_slot=slots.(Array.lengthslots-1)inmatchPrintexc.Slot.locationlast_slotwith|Some{Printexc.filename;line_number;_}->Printf.sprintf"%s:%d"filenameline_number|None->"internal"inletlandmark=new_landmarknamelocationkindinregistered_landmarks:=landmark::!registered_landmarks;if!profile_with_debugthenPrintf.eprintf"[Profiling] registering(%s)\n%!"name;landmarkletregister?locationname=letcall_stack=Printexc.get_callstack4inregister_generic?locationGraph.Normalnamecall_stackletregister_countername=letcall_stack=Printexc.get_callstack4inregister_genericGraph.Counternamecall_stackletregister_samplername=letcall_stack=Printexc.get_callstack4inregister_genericGraph.Samplernamecall_stackletcurrent_node_ref=ref!current_root_nodeletcache_miss_ref=ref0letstamp_root()=!current_root_node.timestamp<-clock();if!profile_with_allocated_bytesthen!current_root_node.floats.allocated_bytes<-Gc.allocated_bytes();if!profile_with_sys_timethen!current_root_node.floats.sys_time<-Sys.time()letclear_cache()=letreset_landmarklandmark=landmark.last_son<-dummy_node;landmark.last_parent<-dummy_node;landmark.last_self<-dummy_node;inList.iterreset_landmark!registered_landmarkstypeprofiling_state={root:node;nodes:nodelist;nodes_len:int;current:node;cache_miss:int}letprofiling_stack=letdummy={root=dummy_node;current=dummy_node;nodes=[dummy_node];cache_miss=0;nodes_len=1}inStack.makedummy7letpush_profiling_state()=letstate={root=!current_root_node;nodes=!allocated_nodes;nodes_len=!node_id_ref;current=!current_node_ref;cache_miss=!cache_miss_ref;}inclear_cache();current_root_node:=new_nodelandmark_root;current_node_ref:=!current_root_node;cache_miss_ref:=0;allocated_nodes:=[!current_root_node];node_id_ref:=1;Stack.pushprofiling_stackstateletpop_profiling_state()=ifprofiling_stack.size>0thenlet{root;nodes;nodes_len;current;cache_miss}=Stack.popprofiling_stackincurrent_root_node:=root;current_node_ref:=current;cache_miss_ref:=cache_miss;allocated_nodes:=nodes;node_id_ref:=nodes_lenletreset()=if!profile_with_debugthenPrintf.eprintf"[Profiling] resetting ...\n%!";(* reset dummy_node *)letfloats=!current_root_node.floatsinfloats.time<-0.0;floats.allocated_bytes<-0.0;floats.sys_time<-0.0;!current_root_node.calls<-0;!current_root_node.recursive_calls<-0;stamp_root();SparseArray.reset!current_root_node.sons;allocated_nodes:=[!current_root_node];current_node_ref:=!current_root_node;cache_miss_ref:=0;clear_cache();node_id_ref:=1let()=reset()letunroll_untilnode=whileletcurrent_node=!current_node_refincurrent_node!=node&&Stack.sizecurrent_node.fathers>0&&(current_node_ref:=Stack.popcurrent_node.fathers;true)do()doneletlandmark_failuremsg=unroll_until!current_root_node;if!current_node_ref!=!current_root_nodethenreset();if!profile_with_debugthen(Printf.eprintf"Landmark error: %s\n%!"msg;Stdlib.exit2)elseraise(LandmarkFailuremsg)letget_entering_node({id;_}aslandmark)=letcurrent_node=!current_node_refin(* Read the "cache". *)ifcurrent_node==landmark.last_parent&&landmark.last_son!=dummy_nodethenlandmark.last_sonelsebeginincrcache_miss_ref;(* We fetch the son or create it. *)letsons=current_node.sonsinletson=trySparseArray.getsonsidwithNot_found->letson=new_nodelandmarkinSparseArray.setcurrent_node.sonsidson;sonin(* Fill the "cache". *)landmark.last_parent<-current_node;landmark.last_son<-son;sonendletget_exiting_nodecurrent_node=ifStack.sizecurrent_node.fathers=0thenlandmark_failure"Stack underflow"elseStack.popcurrent_node.fathersletincrement?(times=1)counter=letnode=get_entering_nodecounterinnode.calls<-node.calls+timesletincrement?timescounter=if!profiling_refthenincrement?timescounterletsamplesamplerx=letnode=get_entering_nodesamplerinnode.calls<-node.calls+1;Stack.pushnode.distribxletsamplesamplerx=if!profiling_refthensamplesamplerxletenterlandmark=if!profile_with_debugthenPrintf.eprintf"[Profiling] enter%s(%s)\n%!"(iflandmark.last_self!=dummy_nodethen" recursive "else"")landmark.name;iflandmark.last_self==dummy_node||!profile_recursivethenbeginletnode=get_entering_nodelandmarkinnode.calls<-node.calls+1;Stack.pushnode.fathers!current_node_ref;current_node_ref:=node;landmark.last_self<-node;node.timestamp<-clock();if!profile_with_allocated_bytesthennode.floats.allocated_bytes_stamp<-Gc.allocated_bytes();if!profile_with_sys_timethennode.floats.sys_timestamp<-Sys.time()endelsebeginletlast_self=landmark.last_selfinlast_self.recursive_calls<-last_self.recursive_calls+1;last_self.calls<-last_self.calls+1endletmismatch_recoveringlandmarkcurrent_node=letexpected_landmark=current_node.landmarkinifexpected_landmark!=landmarkthenbeginletmsg=Printf.sprintf"landmark failure when closing '%s' (%s), expecting '%s' (%s)."landmark.namelandmark.locationexpected_landmark.nameexpected_landmark.locationinPrintf.eprintf"Warning: %s\n%!"msg;unroll_untillandmark.last_self;iflandmark!=!current_node_ref.landmarkthenbeginreset();landmark_failure("unable to recover from "^msg)endendletaggregate_stat_forcurrent_node=letfloats=current_node.floatsinfloats.time<-floats.time+.Int64.(to_float(sub(clock())current_node.timestamp));if!profile_with_allocated_bytesthenfloats.allocated_bytes<-floats.allocated_bytes+.((Gc.allocated_bytes())-.floats.allocated_bytes_stamp);if!profile_with_sys_timethenfloats.sys_time<-floats.sys_time+.(Sys.time()-.floats.sys_timestamp)letexitlandmark=if!profile_with_debugthenPrintf.eprintf"[Profiling] exit%s(%s)\n%!"(iflandmark.last_self!=!current_node_refthen" recursive "else"")landmark.name;letcurrent_node=!current_node_refinletlast_self=landmark.last_selfiniflast_self.recursive_calls=0||!profile_recursivethenbeginmismatch_recoveringlandmarkcurrent_node;ifStack.sizecurrent_node.fathers=1thenbeginlandmark.last_self<-dummy_node;aggregate_stat_forcurrent_node;end;current_node_ref:=get_exiting_nodecurrent_nodeendelseifnot!profile_recursivethenlast_self.recursive_calls<-last_self.recursive_calls-1(* These two functions should be inlined. *)letenterlandmark=if!profiling_refthenenterlandmarkletexitlandmark=if!profiling_refthenexitlandmark(** HELPERS **)letwrapnodefx=enternode;tryletres=fxinexitnode;reswithLandmarkFailure_ase->raisee|e->exitnode;raiseeletunsafe_wrapnodefx=enternode;letres=fxinexitnode;res(** PROFILERS **)typeprofiling_options={debug:bool;allocated_bytes:bool;sys_time:bool;recursive:bool;output:profile_output;format:profile_format}letdefault_options={debug=false;allocated_bytes=true;sys_time=false;recursive=false;output=Channelstderr;format=Textual{threshold=1.0};}letset_profiling_options{debug;allocated_bytes;sys_time;output;format;recursive}=profile_with_allocated_bytes:=allocated_bytes;profile_with_sys_time:=sys_time;profile_with_debug:=debug;profile_output:=output;profile_format:=format;profile_recursive:=recursiveletprofiling_options()={debug=!profile_with_debug;allocated_bytes=!profile_with_allocated_bytes;sys_time=!profile_with_sys_time;recursive=!profile_recursive;output=!profile_output;format=!profile_format}letstart_profiling?(profiling_options=default_options)()=if!profiling_refthenfailwith"In profiling: it is not allowed to nest profilings.";set_profiling_optionsprofiling_options;if!profile_with_debugthenPrintf.eprintf"[Profiling] Start profiling %s...\n%!"(match!profile_with_allocated_bytes,!profile_with_sys_timewith|true,true->"with garbage collection statistics and system time"|true,false->"with garbage collection statistics"|false,true->"with system time"|false,false->"");profiling_ref:=trueletrecexit_until_root()=if!current_node_ref!=!current_root_nodethenbeginletlandmark=!current_node_ref.landmarkinexitlandmark;exit_until_root();endletstop_profiling()=ifnot!profiling_refthenfailwith"In profiling: cannot stop since profiling is not on-going";exit_until_root();letcurrent_node=!current_node_refinassert(current_node==!current_root_node);aggregate_stat_forcurrent_node;if!profile_with_debugthenPrintf.eprintf"[Profiling] Stop profiling.\n%!";profiling_ref:=false(** EXPORTING / IMPORTING SLAVE PROFILINGS **)letarray_list_mapfl=letsize=List.lengthlinmatchlwith|[]->[||]|hd::tl->letres=Array.makesize(fhd)inList.iteri(funkx->res.(k+1)<-fx)tl;resletexport?(label="")()=letexport_node{landmark;id;calls;floats;sons;distrib;_}=let{id=landmark_id;name;location;kind;_}=landmarkinlet{time;allocated_bytes;sys_time;_}=floatsinletsons=List.map(fun({id;_}:node)->id)(SparseArray.valuessons)in{Graph.landmark_id;id;name;location;calls;time;kind;allocated_bytes;sys_time;sons;distrib=Stack.to_arraydistrib}inif!profiling_refthenbeginaggregate_stat_for!current_root_node;stamp_root()end;letall_nodes=List.rev!allocated_nodesinletnodes=array_list_mapexport_nodeall_nodesin{Graph.nodes;label}letexport_and_reset?label()=letprofiling=!profiling_refinifprofilingthenstop_profiling();letres=export?label()inreset();ifprofilingthenstart_profiling();resletrecmerge_branchnodegraph(imported:Graph.node)=letfloats=node.floatsinfloats.time<-imported.time+.floats.time;floats.sys_time<-imported.sys_time+.floats.sys_time;floats.allocated_bytes<-imported.allocated_bytes+.floats.allocated_bytes;node.calls<-imported.calls+node.calls;Array.iter(Stack.pushnode.distrib)imported.distrib;letsons=Graph.sonsgraphimportedinList.iter(fun(imported_son:Graph.node)->matchSparseArray.getnode.sonsimported_son.landmark_idwith|exceptionNot_found->new_branchnodegraphimported_son|son->merge_branchsongraphimported_son)sonsandnew_branchparentgraph({landmark_id;_}asimported:Graph.node)=letlandmark=matchlandmark_of_idlandmark_idwith|exceptionNot_found->letmsg=Printf.sprintf"%sThe landmark with id %d has not been registered in master process."inconsistency_msglandmark_idinfailwithmsg|x->xincheck_landmarklandmarkimported;letnode=new_nodelandmarkinnode.calls<-imported.calls;letfloats=node.floatsinfloats.time<-imported.time;floats.allocated_bytes<-imported.allocated_bytes;floats.sys_time<-imported.sys_time;Array.iter(Stack.pushnode.distrib)imported.distrib;SparseArray.setparent.sonslandmark_idnode;List.iter(new_branchnodegraph)(Graph.sonsgraphimported);andinconsistency_msg="Inconsistency while importing profiling information of slaves processes:\n"andcheck_landmarklandmarkimported=iflandmark.name<>imported.name||landmark.location<>imported.locationthenletmsg=Printf.sprintf"%sThe 'master' landmark '%s' ('%s') has the same id (%d) than the \
'slave' landmark'%s' ('%s')"inconsistency_msglandmark.namelandmark.locationlandmark.idimported.nameimported.locationinfailwithmsgletmerge(graph:Graph.graph)=if!profile_with_debugthenPrintf.eprintf"[Profiling] merging foreign graph\n%!";merge_branch!current_root_nodegraph(Graph.rootgraph)letexit_hook()=if!profile_with_debugthenPrintf.eprintf"[Profiling] exit_hook\n%!";if!profiling_refthenbeginstop_profiling();letlabel=String.concat" "(Array.to_listSys.argv)inletcg=export~label()inmatch!profile_output,!profile_formatwith|Silent,_->()|Channelout,Textual{threshold}->Graph.output~thresholdoutcg|Channelout,JSON->Graph.output_jsonoutcg|Temporarytemp_dir,format->lettmp_file,oc=Filename.open_temp_file?temp_dir"profile_at_exit"".tmp"inPrintf.eprintf"[Profiling] Dumping profiling information in file '%s'.\n"tmp_file;flushstdout;(matchformatwith|Textual{threshold}->Graph.output~thresholdoccg|JSON->Graph.output_jsonoccg);close_outocendlet()=Stdlib.at_exitexit_hookletparse_env_optionss=letopenPrintfinletdebug=reffalseinletformat=ref(Textual{threshold=1.0})inletoutput=ref(Channelstderr)inletsys_time=reffalseinletrecursive=reffalseinletallocated_bytes=reffalseinletsplit_trimcs=List.mapString.trim(Misc.splitcs)inletwarnings=eprintf"[LANDMARKS] %s.\n%!"sinletparse_options=letinvalid_foroptgiven=warning(sprintf"The argument '%s' in not valid for the option '%s'"givenopt)inletexpect_no_argumentopt=warning(sprintf"The option '%s' expects no argument"opt)inmatchsplit_trim'='swith|[]->()|["debug"]->debug:=true|"debug"::_->expect_no_argument"debug"|["threshold";percent]->beginmatch!formatwith|Textual_->letthreshold=trySome(float_of_stringpercent)with_->Noneinbeginmatchthresholdwith|None->warning(Printf.sprintf"Unable to parse threshold '%s'"percent)|Somethreshold->format:=Textual{threshold}end|_->warning(Printf.sprintf"The option threshold only makes sense with the 'textual' format.")end|["format";"textual"]->beginmatch!formatwith|Textual_->()|_->format:=Textual{threshold=1.0};end|["format";"json"]->format:=JSON;|["format";unknown]->invalid_for"format"unknown|["output";"stderr"]->output:=Channelstderr|["output";"stdout"]->output:=Channelstdout|["output";temporary]whenMisc.starts_with~prefix:"temporary"temporary->beginmatchsplit_trim':'temporarywith|["temporary"]->output:=TemporaryNone|["temporary";dir_spec]->beginmatchsplit_trim'"'dir_specwith|["";dir;""]->output:=Temporary(Somedir)|[dir]->output:=Temporary(Somedir)|_->invalid_for"output"temporaryend|_->invalid_for"output"temporaryend|["output";file_spec]->(matchsplit_trim'"'file_specwith|["";file;""]|[file]->(tryoutput:=Channel(open_outfile)with_->warning(sprintf"Unable to open '%s'"file))|_->invalid_for"output"file_spec)|["time"]->sys_time:=true|"time"::_->expect_no_argument"time"|["recursive"]->recursive:=true|"recursive"::_->expect_no_argument"recursive"|["allocation"]->allocated_bytes:=true|"allocation"::_->expect_no_argument"allocation"|["off"]->raiseExit|"off"::_->expect_no_argument"off"|["auto"]|["remove"]|["threads"]->()(* read by the ppx extension *)|"auto"::_->expect_no_argument"auto"|"remove"::_->expect_no_argument"remove"|"threads"::_->expect_no_argument"threads"|[""]|["on"]|["1"]->()|opt::_::_->warning(Printf.sprintf"To many '=' after '%s'"opt)|unknown::_->warning(sprintf"Unknown option '%s'"unknown)inList.iterparse_option(split_trim','s);{debug=!debug;allocated_bytes=!allocated_bytes;sys_time=!sys_time;output=!output;format=!format;recursive=!recursive}let()=matchSys.getenv"OCAML_LANDMARKS"with|exceptionNot_found->()|str->trystart_profiling~profiling_options:(parse_env_optionsstr)()withExit->()externalraise:exn->'a="%raise"