123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(** Server requests about general statistics on the Eva analysis. *)openServeropenCil_typesletpackage=lettitle="Statistics about Eva analysis"inPackage.package~plugin:"eva"~name:"stats"~title()(* ----- Analysis statistics ------------------------------------------------ *)moduleAlarmCategory=structopenServer.DatamoduleTags=structletdictionary=Enum.dictionary()(* Give a normal representation of the category *)letrepr=lete=List.hdCil_datatype.Exp.reprsinletlv=List.hdCil_datatype.Lval.reprsinlettyp=List.hdCil_datatype.Typ.reprsinfunction|Summary.Division_by_zero->Alarms.Division_by_zeroe|Memory_access->Memory_access(lv,For_reading)|Index_out_of_bound->Index_out_of_bound(e,None)|Unaligned_pointer->Unaligned_pointer(e,typ)|Invalid_shift->Invalid_shift(e,None)|Overflow->Overflow(Signed,e,Z.one,Lower_bound)|Uninitialized->Uninitializedlv|Dangling->Danglinglv|Nan_or_infinite->Is_nan_or_infinite(e,FFloat)|Float_to_int->Float_to_int(e,Z.one,Lower_bound)|Other->assertfalseletregisteralarm_category=letname,descr=matchalarm_categorywith|Summary.Other->"other","Any other alarm"|alarm_category->letalarm=repralarm_categoryinAlarms.(get_short_namealarm,get_descriptionalarm)inEnum.tagdictionary~name~label:(Markdown.plainname)~descr:(Markdown.plaindescr)letdivision_by_zero=registerDivision_by_zeroletmemory_access=registerMemory_accessletindex_out_of_bound=registerIndex_out_of_boundletunaligned_pointer=registerUnaligned_pointerletinvalid_shift=registerInvalid_shiftletoverflow=registerOverflowletuninitialized=registerUninitializedletdangling=registerDanglingletnan_or_infinite=registerNan_or_infiniteletfloat_to_int=registerFloat_to_intletother=registerOtherlet()=Enum.set_lookupdictionarybeginfunction|Summary.Division_by_zero->division_by_zero|Memory_access->memory_access|Index_out_of_bound->index_out_of_bound|Unaligned_pointer->unaligned_pointer|Invalid_shift->invalid_shift|Overflow->overflow|Uninitialized->uninitialized|Dangling->dangling|Nan_or_infinite->nan_or_infinite|Float_to_int->float_to_int|Other->otherendendletname="alarmCategory"letdescr=Markdown.plain"The alarms are counted after being grouped by these categories"letdata=Request.dictionary~package~name~descrTags.dictionaryinclude(valdata:Swithtypet=Summary.alarm_category)endmoduleCoverage=structopenSummarytypet=coverageletjtype=Package.(Jrecord["reachable",Jnumber;"dead",Jnumber;])letto_jsonx=`Assoc["reachable",`Intx.reachable;"dead",`Intx.dead;]endmoduleEvents=structopenSummaryletjtype=Package.(Jrecord["errors",Jnumber;"warnings",Jnumber;])letto_jsonx=`Assoc["errors",`Intx.errors;"warnings",`Intx.warnings;]endmoduleStatuses=structopenSummarytypet=statusesletjtype=Data.declare~package~name:"statusesEntry"~descr:(Markdown.plain"Statuses count.")Package.(Jrecord["valid",Jnumber;"unknown",Jnumber;"invalid",Jnumber;])letto_jsonx=`Assoc["valid",`Intx.valid;"unknown",`Intx.unknown;"invalid",`Intx.invalid;]endmoduleAlarmEntry=structletjtype=Data.declare~package~name:"alarmEntry"~descr:(Markdown.plain"Alarm count for each alarm category.")Package.(Jrecord["category",AlarmCategory.jtype;"count",Jnumber])letto_json(a,c)=`Assoc["category",AlarmCategory.to_jsona;"count",`Intc]endmoduleAlarms=structtypet=(AlarmCategory.t*int)listletjtype=Package.JarrayAlarmEntry.jtypeletto_jsonx=`List(List.mapAlarmEntry.to_jsonx)endmoduleStatistics=structopenSummarytypet=program_statsletjtype=Data.declare~package~name:"programStatsType"~descr:(Markdown.plain"Statistics about an Eva analysis.")Package.(Jrecord["progFunCoverage",Coverage.jtype;"progStmtCoverage",Coverage.jtype;"progAlarms",Alarms.jtype;"evaEvents",Events.jtype;"kernelEvents",Events.jtype;"alarmsStatuses",Statuses.jtype;"assertionsStatuses",Statuses.jtype;"precondsStatuses",Statuses.jtype])letto_jsonx=`Assoc["progFunCoverage",Coverage.to_jsonx.prog_fun_coverage;"progStmtCoverage",Coverage.to_jsonx.prog_stmt_coverage;"progAlarms",Alarms.to_jsonx.prog_alarms;"evaEvents",Events.to_jsonx.eva_events;"kernelEvents",Events.to_jsonx.kernel_events;"alarmsStatuses",Statuses.to_jsonx.alarms_statuses;"assertionsStatuses",Statuses.to_jsonx.assertions_statuses;"precondsStatuses",Statuses.to_jsonx.preconds_statuses]endlet_computed_signal=States.register_value~package~name:"programStats"~descr:(Markdown.plain"Statistics about the last Eva analysis for the whole program")~output:(moduleStatistics)~get:Summary.compute_stats~add_hook:Update.add_computation_hook()let_functionStats=letopenSummaryinletmodel=States.model()inStates.columnmodel~name:"fctName"~descr:(Markdown.plain"Function name")~data:(moduleData.Jalpha)~get:(fun(kf,_)->Kernel_function.get_namekf);States.columnmodel~name:"coverage"~descr:(Markdown.plain"Coverage of the Eva analysis")~data:(moduleCoverage)~get:(fun(_kf,stats)->stats.fun_coverage);States.columnmodel~name:"alarmCount"~descr:(Markdown.plain"Alarms raised by the Eva analysis by category")~data:(moduleAlarms)~get:(fun(_kf,stats)->stats.fun_alarm_count);States.columnmodel~name:"alarmStatuses"~descr:(Markdown.plain"Alarms statuses emitted by the Eva analysis")~data:(moduleStatuses)~get:(fun(_kf,stats)->stats.fun_alarm_statuses);States.register_framac_array~package~name:"functionStats"~descr:(Markdown.plain"Statistics about the last Eva analysis for each function")~key:(funkf->Kernel_ast.Decl.index(SFunctionkf))~keyType:(Kernel_ast.Decl.jtype)model(moduleFunctionStats)(* ----- Flamegraph and execution times ------------------------------------- *)letcallstack_to_stringkf_list=letpp_list=Pretty_utils.pp_list~sep:":"Kernel_function.prettyinFormat.asprintf"%a"pp_list(List.revkf_list)let_evaFlamegraph=letmodel=States.model()inStates.columnmodel~name:"stackNames"~descr:(Markdown.plain"Callstack as functions name list, starting from main")~data:(moduleData.Jlist(Data.Jstring))~get:(fun(cs,_)->List.rev_mapKernel_function.get_namecs);States.columnmodel~name:"nbCalls"~descr:(Markdown.plain"Number of times the callstack has been analyzed")~data:(moduleData.Jint)~get:(fun(_cs,stat)->stat.Eva_perf.nb_calls);States.columnmodel~name:"selfTime"~descr:(Markdown.plain"Computation time for the callstack itself")~data:(moduleData.Jfloat)~get:(fun(_cs,stat)->stat.Eva_perf.self_duration);States.columnmodel~name:"totalTime"~descr:(Markdown.plain"Total computation time, including functions called")~data:(moduleData.Jfloat)~get:(fun(_cs,stat)->stat.Eva_perf.total_duration);States.columnmodel~name:"kfDecl"~descr:(Markdown.plain"Declaration of the top function")~data:(moduleKernel_ast.Decl)~get:(fun(cs,_)->Printer_tag.SFunction(List.hdcs));States.register_framac_array~package~name:"flamegraph"~descr:(Markdown.plain"Data for flamegraph: execution times by callstack")~key:callstack_to_stringmodel(moduleEva_perf.StatByCallstack)