123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574(*
* Copyright (c) 2018 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)moduleKeys=Set.Make(String)typekey=stringtype'aty=|String:stringty|Bool:boolty|Float:floatty|Int:intty|Int32:int32ty|Int64:int64ty|Uint:intty|Uint32:int32ty|Uint64:int64ty|Other:'aFmt.t->'atytype'av={ty:'aty;v:'a}typegraph=inttypefield=|F:{key:string;unit:stringoption;doc:stringoption;graphs:intlistoption;v:'av;}->fieldmoduleTags=structtype'av={k:string;pp:Format.formatter->'a->unit}letvppk={k;pp}letstring=vFmt.stringletfloat=vFmt.floatletint=vFmt.intletuint=vFmt.uintletint32=vFmt.int32letuint32=vFmt.uint32letint64=vFmt.int64letuint64=vFmt.uint64letbool=vFmt.booltype'at=[]:fieldlistt|(::):'av*'bt->('a->'b)tletrecdomain:typea.at->Keys.t=function|[]->Keys.empty|h::t->Keys.addh.k(domaint)endletkey(F{key;_})=keyletdoc(F{doc;_})=docletunit(F{unit;_})=unitletgraphs(F{graphs;_})=graphsmoduleData=structtypetimestamp=stringtypet={timestamp:stringoption;fields:fieldlist}letkeyst=List.mapkeyt.fieldslettimestampt=t.timestampletfieldst=t.fieldsletconsht={twithfields=h::t.fields}letv?timestampfields={timestamp;fields}endletindex_key~fieldsf=letrecauxn=function|[]->raiseNot_found|h::t->ifh=fthennelseaux(n+1)tinaux0fieldsletindex~fields(Ff)=index_key~fieldsf.keytypetags=fieldlisttypedata=Data.tmoduleSrc=struct(* inspiration from From logs/Src *)typepredicate={mutableall:bool;mutabletags:Keys.t}let_tags={all=false;tags=Keys.empty}type('a,'b)src={uid:int;name:string;doc:string;dom:Keys.t;tags:'aTags.t;data:'b;mutableactive:bool;duration:bool;status:bool;mutabledata_fields:stringlistoption;}typet=Src:('a,'b)src->tletuid=letid=ref(-1)infun()->incrid;!idletlist=ref[]letactivetags=if_tags.allthentrueelsenot(Keys.is_empty(Keys.inter_tags.tagstags))letv?(doc="undocumented")?(duration=false)?(status=false)~tags~dataname=letdom=Tags.domaintagsinletactive=activedominletsrc={duration;status;dom;uid=uid();name;doc;tags;data;active;data_fields=None;}inlist:=Srcsrc::!list;srcletis_active(Srcs)=s.activeletenable(Srcs)=s.active<-trueletdisable(Srcs)=s.active<-falseletname(Srcs)=s.nameletdoc(Srcs)=s.doclettags(Srcs)=Keys.elementss.domletequal(Srcsrc0)(Srcsrc1)=src0.uid=src1.uidletcompare(Srcsrc0)(Srcsrc1)=comparesrc0.uidsrc1.uidletduration(Srcs)=s.durationletstatus(Srcs)=s.statusletdata(Srcs)=matchs.data_fieldswithNone->[]|Somel->lletpp_stringsppfl=Fmt.pfppf"@[<1>(%a)@]"Fmt.(list~sep:(any" ")string)lletppppf(Srcsrc)=lettags=Keys.elements(Tags.domainsrc.tags)inletdata=matchsrc.data_fieldswithNone->[]|Somel->linFormat.fprintfppf"@[<1>(src@ @[<1>(name %S)@]@ @[<1>(uid %d)@] @[<1>(doc %S)@]) \
@[<1>(tags (%a))@] @[<1>(data (%a))@] @]"src.namesrc.uidsrc.docpp_stringstagspp_stringsdataletlist()=!listletupdate()=List.iter(fun(Srcs)->s.active<-actives.dom)(list())endmoduleFields=Set.Make(structtypet=Src.t*fieldletcompare(a,Fx)(b,Fy)=matchSrc.compareabwith0->String.comparex.keyy.key|i->iend)type('a,'b)src=('a,'b)Src.srcmoduleGraph=structtypet=inttypev={title:stringoption;ylabel:stringoption;yunit:stringoption;id:int;mutableactive:bool;mutablefields:Fields.t;}lettbl=Hashtbl.create27letv?title?ylabel?yunit()=letid=Oo.id(objectend)inlett={id;yunit;title;ylabel;active=false;fields=Fields.empty}inHashtbl.addtblidt;idletgetid=Hashtbl.findtblidlettitlet=(gett).titleletylabelt=(gett).ylabelletyunitt=(gett).yunitletidt=(gett).idletenablet=(gett).active<-trueletdisablet=(gett).active<-falseletis_activet=(gett).activeletlist()=Hashtbl.fold(funx_acc->x::acc)tbl[]letfieldsg=Fields.fold(funfacc->f::acc)(getg).fields[]letadd_fieldgsrcf=letg=getging.fields<-Fields.add(src,f)g.fieldsletremove_fieldgsrcf=letg=getging.fields<-Fields.filter(fun(x,y)->not(Src.equalxsrc&&String.equalf(keyy)))g.fieldsendletinittdata=matcht.Src.data_fieldswith|Some_->()|None->letdf=List.mapkeydata.Data.fieldsint.data_fields<-Somedf;List.iter(fun(Ff)->matchf.graphswith|None->()|Somegs->List.iter(fung->Graph.add_fieldg(Srct)(Ff))gs)data.Data.fieldstype'afield_f=?doc:string->?unit:string->?graph:graph->?graphs:graphlist->key->'a->fieldletfield?doc?unit?graph?graphskeytyv=letgraphs=match(graph,graphs)with|None,None->None|Someg,None->Some[g]|None,Somegs->Somegs|Someg,Somegs->Some(g::gs)inF{key;doc;unit;v={ty;v};graphs}letffty?doc?unit?graph?graphskv=field?doc?unit?graph?graphsktyvletstring=ffStringletbool=ffBoolletfloat=ffFloatletint=ffIntletint32=ffInt32letint64=ffInt64letuint=ffUintletuint32=ffUint32letuint64=ffUint64typestatus=[`Ok|`Error]letstring_of_status=function`Ok->"ok"|`Error->"error"moduleKey=structletduration="duration"letstatus="status"letminor_words="minor words"letpromoted_words="promoted words"letmajor_words="major words"letminor_collections="minor collections"letmajor_collections="major collections"letheap_words="heap words"letheap_chunks="heap chunks"letcompactions="compactions"letlive_words="live words"letlive_blocks="live blocks"letfree_words="free words"letfree_blocks="free blocks"letlargest_free="largest free"letfragments="fragments"lettop_heap_words="top heap words"letstack_size="stack size"endletstatusv=fieldKey.status(Other(Fmt.of_to_stringstring_of_status))vletdurationi=int64Key.durationiletpp:typea.aty->aFmt.t=funtyppfv->matchtywith|String->Fmt.stringppfv|Bool->Fmt.boolppfv|Int->Fmt.intppfv|Int32->Fmt.int32ppfv|Int64->Fmt.int64ppfv|Float->Fmt.floatppfv|Uint->Fmt.uintppfv|Uint32->Fmt.uint32ppfv|Uint64->Fmt.uint64ppfv|Otherpp->ppppfvtypevalue=V:'aty*'a->valueletpp_keyppff=Fmt.stringppf(keyf)letpp_valueppf(F{v={ty;v};_})=pptyppfvletvalue(F{v={ty;v};_})=V(ty,v)lettag:typeab.(a,b)Src.src->a=funsrc->letrecaux:typea.tags->aTags.t->a=funtags->function|Tags.[]->List.revtags|Tags.(h::t)->funa->lettags=fieldh.k(Otherh.pp)a::tagsinauxtagstinaux[]src.Src.tags(* Reporters *)typereporter={now:unit->int64;at_exit:unit->unit;report:'a.tags:tags->data:data->over:(unit->unit)->Src.t->(unit->'a)->'a;}letnop_reporter={at_exit=(fun()->());now=(fun()->0L);report=(fun~tags:_~data:_~over_k->over();k());}let_reporter=refnop_reporterletset_reporterr=_reporter:=rletreporter()=!_reporterlet()=at_exit(fun()->!_reporter.at_exit())letnow()=!_reporter.now()moduleSM=Map.Make(Src)letcache_reporter()=letm=refSM.emptyinletreport~tags~data~oversrck=m:=SM.addsrc(tags,data)!m;over();k()in((fun()->!m),{report;now;at_exit=(fun()->())})letreportsrc~over~ktagsf=lettags=tags(tagsrc)infsrc.Src.data(fundata->!_reporter.report~tags~data~over(Srcsrc)k)letover()=()letkunit_=()letadd_no_checksrc?duration?statustagsf=reportsrc~over~k:kunittags(fundatak->letdata=fdatainletdata=match(duration,status)with|None,None->data|Somed,None|None,Somed->Data.consddata|Somex,Somey->Data.consx(Data.consydata)ininitsrcdata;kdata)letis_activesrc=src.Src.activeletaddsrctagsdata=ifis_activesrcthenadd_no_checksrctagsdataletmktfv=iftthenSome(fv)elseNoneletrunsrctagsg=ifnot(is_activesrc)theng()elseletd0=now()inletr=tryOk(g())withe->Erroreinletduration=mksrc.durationduration(Int64.sub(now())d0)inletstatusx=mksrc.statusstatusxinmatchrwith|Okx->add_no_checksrctags?duration?status:(status`Ok)(funf->fr);x|Errore->add_no_checksrctags?duration?status:(status`Error)(funf->fr);raiseetype('a,'b)rresult=('a,[`Exnofexn|`Errorof'b])resultletrrunsrctagsg=ifnot(is_activesrc)theng()elseletd0=now()inletr=tryOk(g())withe->Error(`Exne)inletduration=mksrc.durationduration(Int64.sub(now())d0)inletstatusx=mksrc.statusstatusxinmatchrwith|Ok(Ok_asx)->add_no_checksrctags?duration?status:(status`Ok)(funf->fx);x|Ok(Erroreasx)->add_no_checksrctags?duration?status:(status`Error)(funf->f(Error(`Errore)));x|Error(`Exneasx)->add_no_checksrctags?duration?status:(status`Error)(funf->f(Errorx));raiseelettags_enabled()=Keys.elementsSrc._tags.tagsletall_enabled()=Src._tags.allletenable_tagt=Src._tags.tags<-Keys.addtSrc._tags.tags;Src.update()letdisable_tagt=Src._tags.tags<-Keys.removetSrc._tags.tags;Src.update()letenable_all()=Src._tags.all<-true;Src.update()letdisable_all()=Src._tags.all<-false;Src._tags.tags<-Keys.empty;Src.update()letgc_quick_stat~tags=letdoc="OCaml memory management counters (quick)"inletgraph=Graph.v~title:doc~ylabel:"words"()inletdata()=letstat=Gc.quick_stat()inData.v[floatKey.minor_words~graphstat.Gc.minor_words;floatKey.promoted_words~graphstat.Gc.promoted_words;floatKey.major_words~graphstat.Gc.major_words;uintKey.minor_collections~graphstat.Gc.minor_collections;uintKey.major_collections~graphstat.Gc.major_collections;uintKey.heap_words~graphstat.Gc.heap_words;uintKey.heap_chunks~graphstat.Gc.heap_chunks;uintKey.compactions~graphstat.Gc.compactions;uintKey.top_heap_words~graphstat.Gc.top_heap_words;uintKey.stack_size~graphstat.Gc.stack_size;]inSrc.v~doc~tags~data"gc quick"letgc_stat~tags=letdoc="OCaml memory management counters"inletgraph=Graph.v~title:doc~ylabel:"words"()inletdata()=letstat=Gc.stat()inData.v[floatKey.minor_words~graphstat.Gc.minor_words;floatKey.promoted_words~graphstat.Gc.promoted_words;floatKey.major_words~graphstat.Gc.major_words;uintKey.minor_collections~graphstat.Gc.minor_collections;uintKey.major_collections~graphstat.Gc.major_collections;uintKey.heap_words~graphstat.Gc.heap_words;uintKey.heap_chunks~graphstat.Gc.heap_chunks;uintKey.compactions~graphstat.Gc.compactions;uintKey.live_words~graphstat.Gc.live_words;uintKey.live_blocks~graphstat.Gc.live_blocks;uintKey.free_words~graphstat.Gc.free_words;uintKey.free_blocks~graphstat.Gc.free_blocks;uintKey.largest_free~graphstat.Gc.largest_free;uintKey.fragments~graphstat.Gc.fragments;uintKey.top_heap_words~graphstat.Gc.top_heap_words;uintKey.stack_size~graphstat.Gc.stack_size;]inSrc.v~doc~tags~data"gc"