123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304(*
* Copyright (c) 2018-2022 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.
*)openImportmoduleMetrics=Irmin.MetricsmodulePack_store=structincludeStats_intf.Pack_storetypeMetrics.origin+=Pack_store_statstypestat=tMetrics.tletcreate_pack_store()={appended_hashes=0;appended_offsets =0;total=0;from_staging=0;from_lru=0;from_pack_direct =0;from_pack_indexed=0;}letinit()=letinitial_state=create_pack_store()inMetrics.v~origin:Pack_store_stats~name:"pack_store_metric"~initial_statetletclearm=letv=Metrics.stateminv.appended_hashes<-0;v.appended_offsets<-0;v.total<-0;v.from_staging<-0;v.from_lru<-0;v.from_pack_direct<-0;v.from_pack_indexed<-0letexportm=Metrics.statemletupdate~fieldfinds=letfv=matchfieldwith|Appended_hashes->v.appended_hashes<-succv.appended_hashes|Appended_offsets->v.appended_offsets<-succv.appended_offsets|Staging->v.total<-succv.total;v.from_staging<-succv.from_staging|Lru->v.total<-succv.total;v.from_lru<-succv.from_lru|Pack_direct->v.total<-succv.total;v.from_pack_direct<-succv.from_pack_direct|Pack_indexed->v.total <-succv.total;v.from_pack_indexed <-succ v.from_pack_indexed|Not_found ->v.total<-succv.total;()inletmut=Metrics.MutatefinMetrics.updatefindsmutletcache_misses{(* Total finds (hits + misses): *)total;(* In-memory hits: *)from_staging;from_lru;_;}=total-(from_staging+from_lru)endmoduleIndex=structincludeStats_intf.IndextypeMetrics.origin+=Index_statstypestat=tMetrics.tletcreate_index()={bytes_read=0;nb_reads=0;bytes_written=0;nb_writes=0;nb_merge=0;merge_durations=[];nb_replace=0;replace_durations=[];nb_sync=0;time_sync=0.0;lru_hits=0;lru_misses=0;}letclear(data:stat)=lets=Metrics.statedatainIndex.Stats.reset_stats();s.bytes_read<-0;s.nb_reads<-0;s.bytes_written<-0;s.nb_writes<-0;s.nb_merge<-0;s.merge_durations<-[];s.nb_replace<-0;s.replace_durations<-[];s.nb_sync<-0;s.time_sync<-0.0;s.lru_hits<-0;s.lru_misses<-0letinit()=letinitial_state=create_index()inMetrics.v~origin:Index_stats~name:"index_metric"~initial_statetletreportindex=letmodifier=Metrics.Replace(fun_->Stats_intf.Index.S.get())inMetrics.(updateindexmodifier)letexportm=Metrics.statemendmoduleFile_manager=structincludeStats_intf.File_managertypeMetrics.origin+=File_manager(* NOTE return a new instance each time, since fields are mutable *)letcreate()={dict_flushes=0;suffix_flushes=0;index_flushes=0;auto_dict=0;auto_suffix=0;auto_index=0;flush=0;}(* NOTE type [stat] is an abstract type in stats.mli *)typestat=tMetrics.tletinit():stat=letinitial_state=create()inMetrics.v~origin:File_manager~name:"file_manager_metric"~initial_statet(* [export] reveals the [t] contained in the [Metrics.t] container *)letexport:stat->t=funm->Metrics.statem(* support [reset_stats] function below *)letclear'(t:t)=t.dict_flushes<-0;t.suffix_flushes<-0;t.index_flushes<-0;()letclear(t:stat)=clear'(exportt)(* we want to support an interface where the particular fields of type [t] are reified
as variants, so that we can call [incr_fm_field Dict_flushes] for example *)typefield=|Dict_flushes|Suffix_flushes|Index_flushes|Auto_dict|Auto_suffix|Auto_index|Flushletupdate~fieldt=letft=matchfieldwith|Dict_flushes->t.dict_flushes<-t.dict_flushes+1|Suffix_flushes->t.suffix_flushes<-t.suffix_flushes+1|Index_flushes->t.index_flushes<-t.index_flushes+1|Auto_dict->t.auto_dict<-t.auto_dict+1|Auto_suffix->t.auto_suffix<-t.auto_suffix+1|Auto_index->t.auto_index<-t.auto_index+1|Flush->t.flush<-t.flush+1inMetrics.updatet(Metrics.Mutatef)endmoduleLatest_gc=structincludeStats_intf.Latest_gctypeMetrics.origin+=Latest_gctypestat=tMetrics.t(* [stats] is the latest_gc stats.
[t] is [stats option].
[stat] is the [Metrics] wrapper around [t] *)letinit:unit->stat=fun()->letinitial_state=NoneinMetrics.v~origin:Latest_gc~name:"latest_gc_metric"~initial_statetletclear:stat->unit=funm->Metrics.updatem(Metrics.Replace(fun_->None))letexport:stat->t=Metrics.stateletupdate:stats->stat->unit=funstatm->Metrics.updatem(Metrics.Replace(fun_->Somestat))letnew_suffix_end_offset_before_finaliseworker=matchList.assoc_opt"suffix"worker.fileswith|Somex->x|None->assertfalseletfinalise_durationt=letsteps=t.steps|>List.map(fun(k,v)->(k,v.wall))inletduration=steps|>List.mapsnd|>List.fold_leftFloat.add0.induration-.List.assoc"worker startup"steps-.List.assoc"before finalise"stepslettotal_durationt=letsteps=t.steps|>List.map(fun(k,v)->(k,v.wall))insteps|>List.mapsnd|>List.fold_leftFloat.add0.letfinalise_suffix_transfert=letopenInt63.Syntaxinletsize_of_the_new_suffix_file=t.after_suffix_end_offset-t.before_suffix_end_offsetinletcopied_by_the_worker=t.worker.suffix_transfers|>List.fold_leftInt63.addInt63.zeroinsize_of_the_new_suffix_file-copied_by_the_workerendtypet={pack_store:Pack_store.stat;index:Index.stat;file_manager:File_manager.stat;latest_gc:Latest_gc.stat;}lets={pack_store=Pack_store.init();index=Index.init();file_manager=File_manager.init();latest_gc=Latest_gc.init();}letreset_stats()=Pack_store.clears.pack_store;Index.clears.index;File_manager.clears.file_manager;Latest_gc.clears.latest_gc;()letget()=sletreport_pack_store~field=Pack_store.update~fields.pack_storeletreport_index()=Index.reports.indexletincr_appended_hashes()=Pack_store.update~field:Pack_store.Appended_hashess.pack_storeletincr_appended_offsets()=Pack_store.update~field:Pack_store.Appended_offsetss.pack_storetypecache_stats={cache_misses:float}typeoffset_stats={offset_ratio:float;offset_significance:int}letdiv_or_zeroab=ifb=0then0.elsefloat_of_inta/.float_of_intbletget_cache_stats()=letpack_store=Metrics.states.pack_storeinletcache_misses=Pack_store.cache_missespack_storein{cache_misses=div_or_zerocache_missespack_store.total}letget_offset_stats()=letpack_store=Metrics.states.pack_storein{offset_ratio=div_or_zeropack_store.appended_offsets(pack_store.appended_offsets+pack_store.appended_hashes);offset_significance=pack_store.appended_offsets+pack_store.appended_hashes;}letincr_fm_fieldfield=File_manager.update~fields.file_managerletreport_latest_gcx=Latest_gc.updatexs.latest_gc