123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326(*
* Copyright (c) 2018-2021 Tarides <contact@tarides.com>
*
* 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.
*)open!Import(* This file avoids the [option] type and other clean functionnal paradigms in
order to lower the cpu footprint. The integer incrementation functions are
called millions of times per freeze. *)(** Ensure lists are not growing indefinitely by dropping elements. *)letlimit_length_list=10letminimum_seconds_to_be_considered_long=1.0typecounters={mutablecontents:int;mutablenodes:int;mutablecommits:int;mutablebranches:int;mutableadds:int;mutableskip_tests:int;mutableskips:int;mutableyields:int;}typefreeze_profile={idx:int;past_adds:int;t0:Mtime.t;mutablet1:Mtime.t;mutablecurrent_section:string;mutablecurrent_counters:counters;mutablerev_timeline:(string*Mtime.t*float*counters)list;mutablecopy_newies_loops:int;mutableoutside_totlen:float;mutableinside_totlen:float;mutableoutside_maxlen:string*float;mutableinside_maxlen:string*float;mutablerev_longest_yields:(string,int*float)Hashtbl.t;mutablerev_longest_blocks:(string,int*float)Hashtbl.t;}letfresh_counters()={contents=0;nodes=0;commits=0;branches=0;adds=0;skips=0;skip_tests=0;yields=0;}letfresh_freeze_profileidxt0initial_sectionpast_adds={idx;past_adds;t0;t1=t0;current_section=initial_section;current_counters=fresh_counters();rev_timeline=[];copy_newies_loops=0;outside_totlen=0.;inside_totlen=0.;outside_maxlen=("never",0.);inside_maxlen=("never",0.);rev_longest_yields=Hashtbl.create2;rev_longest_blocks=Hashtbl.create2;}letget_elapsed=letc=ref(Mtime_clock.counter())infun~reset->letelapsed=Mtime.Span.to_s(Mtime_clock.count!c)inifresetthenc:=Mtime_clock.counter();elapsedletfreeze_start_counter=letc=ref(-1)infun()->incrc;!cletfreeze_profiles=ref[]letlatest=ref(fresh_freeze_profile(-1)(Mtime_clock.now())""0)letare_all_counters_zeroc=c=fresh_counters()letreset_stats()=freeze_profiles:=[];latest:=fresh_freeze_profile(-1)(Mtime_clock.now())""0letfreeze_startt0initial_section=letpast_adds=!latest.current_counters.addsinlet(_:float)=get_elapsed~reset:trueinlatest:=fresh_freeze_profile(freeze_start_counter())t0initial_sectionpast_addsletfreeze_sectionev_name'=letev_name=!latest.current_sectioninletnow=Mtime_clock.now()inletnow_inside=get_elapsed~reset:false+.!latest.inside_totleninletc=!latest.current_countersin!latest.current_counters<-fresh_counters();!latest.current_section<-ev_name';!latest.rev_timeline<-(ev_name,now,now_inside,c)::!latest.rev_timelineletcopy_contents()=!latest.current_counters.contents<-succ!latest.current_counters.contentsletcopy_nodes()=!latest.current_counters.nodes<-succ!latest.current_counters.nodesletcopy_commits()=!latest.current_counters.commits<-succ!latest.current_counters.commitsletcopy_branches()=!latest.current_counters.branches<-succ!latest.current_counters.branchesletadd()=(* The only incrementator not called from freeze. *)!latest.current_counters.adds<-succ!latest.current_counters.addsletskip_testshould_skip=!latest.current_counters.skip_tests<-succ!latest.current_counters.skip_tests;ifshould_skipthen!latest.current_counters.skips<-succ!latest.current_counters.skipsletcopy_newies_loop()=!latest.copy_newies_loops<-succ!latest.copy_newies_loopsletfold_countersvf=List.fold_left(funacc(_,_,_,c)->acc+fc)(fv.current_counters)v.rev_timelineletget_add_count()=fold_counters!latest(func->c.adds)letget_copied_commits_count()=fold_counters!latest(func->c.commits)letget_copied_branches_count()=fold_counters!latest(func->c.branches)letget_copied_contents_count()=fold_counters!latest(func->c.contents)letget_copied_nodes_count()=fold_counters!latest(func->c.nodes)letget_freeze_count()=List.length!freeze_profilesletfreeze_yield()=!latest.current_counters.yields<-succ!latest.current_counters.yields;letd1=get_elapsed~reset:trueinletd0=!latest.inside_totlenin!latest.inside_totlen<-d0+.d1;let_,d0=!latest.inside_maxleninifd1>d0then!latest.inside_maxlen<-(!latest.current_section,d1);ifd1>=minimum_seconds_to_be_considered_longthenlettbl=!latest.rev_longest_blocksinlets=!latest.current_sectioninletnew_entry=matchHashtbl.find_opttblswith|None->(1,d1)|Some(i,d)->(i+1,d+.d1)inHashtbl.replacetblsnew_entryletfreeze_yield_end()=letd1=get_elapsed~reset:trueinletd0=!latest.outside_totlenin!latest.outside_totlen<-d0+.d1;let_,d0=!latest.outside_maxleninifd1>d0then!latest.outside_maxlen<-(!latest.current_section,d1);ifd1>=minimum_seconds_to_be_considered_longthenlettbl=!latest.rev_longest_yieldsinlets=!latest.current_sectioninletnew_entry=matchHashtbl.find_opttblswith|None->(1,d1)|Some(i,d)->(i+1,d+.d1)inHashtbl.replacetblsnew_entryletfreeze_stop()=letv=!latestinfreeze_yield();v.current_counters.yields<-predv.current_counters.yields;v.t1<-Mtime_clock.now();v.rev_timeline<-(v.current_section,Mtime_clock.now(),v.inside_totlen,v.current_counters)::v.rev_timeline;v.current_counters<-fresh_counters();letshorterls=List.fold_left(fun(acc,i)x->ifi<limit_length_listthen(x::acc,i+1)else(acc,i+1))([],0)ls|>fst|>List.revinfreeze_profiles:=shorter(v::!freeze_profiles)letpp_latest_when_anyppfv=letongoing=Mtime.equalv.t0v.t1inlettimeline=letl,t0,t0_block=List.fold_right(fun(s,t1,t1_block,counters)(acc,t0,t0_block)->letspan=Mtime.spant0t1inletspan_block=t1_block-.t0_blockinletdata=(s,span,span_block,counters,false)in(data::acc,t1,t1_block))v.rev_timeline([],v.t0,0.)inletl=ifnotongoingthenlelselett1=Mtime_clock.now()inlett1_block=get_elapsed~reset:false+.v.inside_totleninletspan=Mtime.spant0t1inletspan_block=t1_block-.t0_blockin(v.current_section,span,span_block,v.current_counters,true)::linList.revlinlettotlen=ifongoingthenMtime.spanv.t0(Mtime_clock.now())elseMtime.spanv.t0v.t1inletfrac_out,frac_in=lettotlen=Mtime.Span.to_stotlenin(v.outside_totlen/.totlen,v.inside_totlen/.totlen)inletpp_timeline_timings_sectionppf(name,span,span_block,_,is_ongoing)=lettotlen=Mtime.Span.to_stotleninletspan=Mtime.Span.to_sspaninletpp=Mtime.Span.pp_float_sinletpp'ppfv=Format.fprintfppf"%.0f%%"(v*.100.)inFormat.fprintfppf"@\n %20s took %a (%a of total) and blocked %a (%a of total)%s."nameppspanpp'(span/.totlen)ppspan_blockpp'(span_block/.v.inside_totlen)(ifis_ongoingthen" (ongoing)"else"")inletpp_timeline_timingsppf=Format.fprintfppf"%a"Fmt.(list~sep:(any"")pp_timeline_timings_section)timelineinletpp_timeline_counters_sectionppf(name,_,_,c,is_ongoing)=Format.fprintfppf"@\n %20s %a%s."nameFmt.(list~sep:(any", ")(pair~sep:(any":")stringint))[("copy_contents",c.contents);("copy_nodes",c.nodes);("copy_commits",c.commits);("copy_branches",c.branches);("adds",c.adds);("skips",c.skips);("skip_tests",c.skip_tests);("yields",c.yields);](ifis_ongoingthen" (ongoing)"else"")inletpp_timeline_countersppf=lettimeline=List.filter(fun(_,_,_,c,_)->not@@are_all_counters_zeroc)timelineinFormat.fprintfppf"%a"Fmt.(list~sep:(any"")pp_timeline_counters_section)timelineinletpp_long_segmentppf(action_name,(max_section,max_len),tbl)=ifmax_len=0.thenFormat.fprintfppf"No %ss"action_nameelseifHashtbl.lengthtbl=0thenFormat.fprintfppf"Longest %s: %a (during \"%s\")"action_nameMtime.Span.pp_float_smax_lenmax_sectionelseletpp_per_sectionppf(section,(count,totlen))=letpp_if_maxppf=ifsection=max_sectionthenFormat.fprintfppf" (max:%a)"Mtime.Span.pp_float_smax_leninifcount=1thenFormat.fprintfppf"1 long %s in \"%s\" of %a"action_namesectionMtime.Span.pp_float_stotlenelseFormat.fprintfppf"%d long %ss in \"%s\" of ~%a%t"countaction_namesectionMtime.Span.pp_float_s(totlen/.float_of_intcount)pp_if_maxinFormat.fprintfppf"Longests %ss: [%a]"action_nameFmt.(list~sep:(any"; ")pp_per_section)(Hashtbl.to_seqtbl|>List.of_seq)inFormat.fprintfppf"freeze %d (%s) blocked %a (%.0f%%), and yielded %a (%.0f%%). Total %a. %d \
adds before freeze. Copy newies loops: %d.@\n\
\ %a.@\n\
\ %a.@\n\
\ Timeline timings: %t@\n\
\ Timeline counters: %t@\n"v.idx(ifongoingthen"ongoing"else"finished")Mtime.Span.pp_float_sv.inside_totlen(frac_in*.100.)Mtime.Span.pp_float_sv.outside_totlen(frac_out*.100.)Mtime.Span.pptotlenv.past_addsv.copy_newies_loopspp_long_segment("block",v.inside_maxlen,v.rev_longest_blocks)pp_long_segment("yield",v.outside_maxlen,v.rev_longest_yields)pp_timeline_timingspp_timeline_countersletpp_latestppf=letv=!latestinifv.idx=-1thenFormat.fprintfppf"No freeze started yet."elsepp_latest_when_anyppfv