diff --git a/ivette/src/frama-c/plugins/eva/Flamegraph.tsx b/ivette/src/frama-c/plugins/eva/Flamegraph.tsx index ad08c4da3153e038117450be0a5b53f8d8b9db97..41f01b1f881070e9da2616a5f707b34e51590433 100644 --- a/ivette/src/frama-c/plugins/eva/Flamegraph.tsx +++ b/ivette/src/frama-c/plugins/eva/Flamegraph.tsx @@ -25,7 +25,7 @@ import { IconButton } from 'dome/controls/buttons'; import * as Ivette from 'ivette'; import * as Ast from 'frama-c/kernel/api/ast'; import * as States from 'frama-c/states'; -import * as Eva from 'frama-c/plugins/eva/api/values'; +import * as Eva from 'frama-c/plugins/eva/api/general'; import { FlameGraph } from 'react-flame-graph'; import AutoSizer, { Size } from 'react-virtualized-auto-sizer'; import { EvaReady, EvaStatus } from './components/AnalysisStatus'; diff --git a/ivette/src/frama-c/plugins/eva/api/general/index.ts b/ivette/src/frama-c/plugins/eva/api/general/index.ts index c37d5121b0b153e16622f7c4a2a01e83b54d3c20..ce5eb30dbab5659ea3483db89c6d6ad16931becb 100644 --- a/ivette/src/frama-c/plugins/eva/api/general/index.ts +++ b/ivette/src/frama-c/plugins/eva/api/general/index.ts @@ -760,4 +760,145 @@ export const getStates: Server.GetRequest< [ string, string, string ][] >= getStates_internal; +/** Kernel function stack identifier */ +export type kfstack = Json.index<'#kfstack'>; + +/** Decoder for `kfstack` */ +export const jKfstack: Json.Decoder<kfstack> = + Json.jIndex<'#kfstack'>('#kfstack'); + +/** Natural order for `kfstack` */ +export const byKfstack: Compare.Order<kfstack> = Compare.number; + +/** Default value for `kfstack` */ +export const kfstackDefault: kfstack = + Json.jIndex<'#kfstack'>('#kfstack')(-1); + +/** Kernel function list infos */ +export type calllink = { callee: decl, caller?: decl }; + +/** Decoder for `calllink` */ +export const jCalllink: Json.Decoder<calllink> = + Json.jObject({ callee: jDecl, caller: Json.jOption(jDecl),}); + +/** Natural order for `calllink` */ +export const byCalllink: Compare.Order<calllink> = + Compare.byFields + <{ callee: decl, caller?: decl }>({ + callee: byDecl, + caller: Compare.defined(byDecl), + }); + +/** Default value for `calllink` */ +export const calllinkDefault: calllink = + { callee: declDefault, caller: undefined }; + +/** Data for array rows [`evaFlamegraph`](#evaflamegraph) */ +export interface evaFlamegraphData { + /** Entry identifier. */ + key: Json.key<'#evaFlamegraph'>; + /** Caller list identifier */ + stack: kfstack; + /** Computation time for the kernel function stack */ + time: number; + /** Kernel function description */ + title: string; + /** Function name */ + name: string; + /** Function list */ + funlist: string; + /** Kernel function key */ + kfkey: string; +} + +/** Decoder for `evaFlamegraphData` */ +export const jEvaFlamegraphData: Json.Decoder<evaFlamegraphData> = + Json.jObject({ + key: Json.jKey<'#evaFlamegraph'>('#evaFlamegraph'), + stack: jKfstack, + time: Json.jNumber, + title: Json.jString, + name: Json.jString, + funlist: Json.jString, + kfkey: Json.jString, + }); + +/** Natural order for `evaFlamegraphData` */ +export const byEvaFlamegraphData: Compare.Order<evaFlamegraphData> = + Compare.byFields + <{ key: Json.key<'#evaFlamegraph'>, stack: kfstack, time: number, + title: string, name: string, funlist: string, kfkey: string }>({ + key: Compare.string, + stack: byKfstack, + time: Compare.number, + title: Compare.string, + name: Compare.string, + funlist: Compare.string, + kfkey: Compare.string, + }); + +/** Signal for array [`evaFlamegraph`](#evaflamegraph) */ +export const signalEvaFlamegraph: Server.Signal = { + name: 'plugins.eva.general.signalEvaFlamegraph', +}; + +const reloadEvaFlamegraph_internal: Server.GetRequest<null,null> = { + kind: Server.RqKind.GET, + name: 'plugins.eva.general.reloadEvaFlamegraph', + input: Json.jNull, + output: Json.jNull, + fallback: null, + signals: [], +}; +/** Force full reload for array [`evaFlamegraph`](#evaflamegraph) */ +export const reloadEvaFlamegraph: Server.GetRequest<null,null>= reloadEvaFlamegraph_internal; + +const fetchEvaFlamegraph_internal: Server.GetRequest< + number, + { reload: boolean, removed: Json.key<'#evaFlamegraph'>[], + updated: evaFlamegraphData[], pending: number } + > = { + kind: Server.RqKind.GET, + name: 'plugins.eva.general.fetchEvaFlamegraph', + input: Json.jNumber, + output: Json.jObject({ + reload: Json.jBoolean, + removed: Json.jArray( + Json.jKey<'#evaFlamegraph'>('#evaFlamegraph')), + updated: Json.jArray(jEvaFlamegraphData), + pending: Json.jNumber, + }), + fallback: { reload: false, removed: [], updated: [], pending: 0 }, + signals: [], +}; +/** Data fetcher for array [`evaFlamegraph`](#evaflamegraph) */ +export const fetchEvaFlamegraph: Server.GetRequest< + number, + { reload: boolean, removed: Json.key<'#evaFlamegraph'>[], + updated: evaFlamegraphData[], pending: number } + >= fetchEvaFlamegraph_internal; + +const evaFlamegraph_internal: State.Array< + Json.key<'#evaFlamegraph'>, + evaFlamegraphData + > = { + name: 'plugins.eva.general.evaFlamegraph', + getkey: ((d:evaFlamegraphData) => d.key), + signal: signalEvaFlamegraph, + fetch: fetchEvaFlamegraph, + reload: reloadEvaFlamegraph, + order: byEvaFlamegraphData, +}; +/** Data for Eva flamegraph */ +export const evaFlamegraph: State.Array< + Json.key<'#evaFlamegraph'>, + evaFlamegraphData + > = evaFlamegraph_internal; + +/** Default value for `evaFlamegraphData` */ +export const evaFlamegraphDataDefault: evaFlamegraphData = + { key: Json.jKey<'#evaFlamegraph'>('#evaFlamegraph')(''), + stack: kfstackDefault, time: 0, title: '', name: '', funlist: '', + kfkey: '' }; + /* ------------------------------------- */ diff --git a/ivette/src/frama-c/plugins/eva/api/values/index.ts b/ivette/src/frama-c/plugins/eva/api/values/index.ts index c0cf380694fab72d4438d7d9a3493bf3f7e96c8c..e5dfbd41bb73978a2bcc2adb8f5665c168cf6977 100644 --- a/ivette/src/frama-c/plugins/eva/api/values/index.ts +++ b/ivette/src/frama-c/plugins/eva/api/values/index.ts @@ -232,145 +232,4 @@ export const getValues: Server.GetRequest< vElse?: evaluation } >= getValues_internal; -/** Kernel function stack identifier */ -export type kfstack = Json.index<'#kfstack'>; - -/** Decoder for `kfstack` */ -export const jKfstack: Json.Decoder<kfstack> = - Json.jIndex<'#kfstack'>('#kfstack'); - -/** Natural order for `kfstack` */ -export const byKfstack: Compare.Order<kfstack> = Compare.number; - -/** Default value for `kfstack` */ -export const kfstackDefault: kfstack = - Json.jIndex<'#kfstack'>('#kfstack')(-1); - -/** Kernel function list infos */ -export type calllink = { callee: decl, caller?: decl }; - -/** Decoder for `calllink` */ -export const jCalllink: Json.Decoder<calllink> = - Json.jObject({ callee: jDecl, caller: Json.jOption(jDecl),}); - -/** Natural order for `calllink` */ -export const byCalllink: Compare.Order<calllink> = - Compare.byFields - <{ callee: decl, caller?: decl }>({ - callee: byDecl, - caller: Compare.defined(byDecl), - }); - -/** Default value for `calllink` */ -export const calllinkDefault: calllink = - { callee: declDefault, caller: undefined }; - -/** Data for array rows [`evaFlamegraph`](#evaflamegraph) */ -export interface evaFlamegraphData { - /** Entry identifier. */ - key: Json.key<'#evaFlamegraph'>; - /** Caller list identifier */ - stack: kfstack; - /** Computation time for the kernel function stack */ - time: number; - /** Kernel function description */ - title: string; - /** Function name */ - name: string; - /** Function list */ - funlist: string; - /** Kernel function key */ - kfkey: string; -} - -/** Decoder for `evaFlamegraphData` */ -export const jEvaFlamegraphData: Json.Decoder<evaFlamegraphData> = - Json.jObject({ - key: Json.jKey<'#evaFlamegraph'>('#evaFlamegraph'), - stack: jKfstack, - time: Json.jNumber, - title: Json.jString, - name: Json.jString, - funlist: Json.jString, - kfkey: Json.jString, - }); - -/** Natural order for `evaFlamegraphData` */ -export const byEvaFlamegraphData: Compare.Order<evaFlamegraphData> = - Compare.byFields - <{ key: Json.key<'#evaFlamegraph'>, stack: kfstack, time: number, - title: string, name: string, funlist: string, kfkey: string }>({ - key: Compare.string, - stack: byKfstack, - time: Compare.number, - title: Compare.string, - name: Compare.string, - funlist: Compare.string, - kfkey: Compare.string, - }); - -/** Signal for array [`evaFlamegraph`](#evaflamegraph) */ -export const signalEvaFlamegraph: Server.Signal = { - name: 'plugins.eva.values.signalEvaFlamegraph', -}; - -const reloadEvaFlamegraph_internal: Server.GetRequest<null,null> = { - kind: Server.RqKind.GET, - name: 'plugins.eva.values.reloadEvaFlamegraph', - input: Json.jNull, - output: Json.jNull, - fallback: null, - signals: [], -}; -/** Force full reload for array [`evaFlamegraph`](#evaflamegraph) */ -export const reloadEvaFlamegraph: Server.GetRequest<null,null>= reloadEvaFlamegraph_internal; - -const fetchEvaFlamegraph_internal: Server.GetRequest< - number, - { reload: boolean, removed: Json.key<'#evaFlamegraph'>[], - updated: evaFlamegraphData[], pending: number } - > = { - kind: Server.RqKind.GET, - name: 'plugins.eva.values.fetchEvaFlamegraph', - input: Json.jNumber, - output: Json.jObject({ - reload: Json.jBoolean, - removed: Json.jArray( - Json.jKey<'#evaFlamegraph'>('#evaFlamegraph')), - updated: Json.jArray(jEvaFlamegraphData), - pending: Json.jNumber, - }), - fallback: { reload: false, removed: [], updated: [], pending: 0 }, - signals: [], -}; -/** Data fetcher for array [`evaFlamegraph`](#evaflamegraph) */ -export const fetchEvaFlamegraph: Server.GetRequest< - number, - { reload: boolean, removed: Json.key<'#evaFlamegraph'>[], - updated: evaFlamegraphData[], pending: number } - >= fetchEvaFlamegraph_internal; - -const evaFlamegraph_internal: State.Array< - Json.key<'#evaFlamegraph'>, - evaFlamegraphData - > = { - name: 'plugins.eva.values.evaFlamegraph', - getkey: ((d:evaFlamegraphData) => d.key), - signal: signalEvaFlamegraph, - fetch: fetchEvaFlamegraph, - reload: reloadEvaFlamegraph, - order: byEvaFlamegraphData, -}; -/** Data for Eva flamegraph */ -export const evaFlamegraph: State.Array< - Json.key<'#evaFlamegraph'>, - evaFlamegraphData - > = evaFlamegraph_internal; - -/** Default value for `evaFlamegraphData` */ -export const evaFlamegraphDataDefault: evaFlamegraphData = - { key: Json.jKey<'#evaFlamegraph'>('#evaFlamegraph')(''), - stack: kfstackDefault, time: 0, title: '', name: '', funlist: '', - kfkey: '' }; - /* ------------------------------------- */ diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml index a6ba38f5c9fd9a5c423ac7d9489305bcbb884d8c..afcf9ac7c2036366833b2bdd636faeb4ee5dd3c4 100644 --- a/src/plugins/eva/api/general_requests.ml +++ b/src/plugins/eva/api/general_requests.ml @@ -868,3 +868,98 @@ let () = Request.register ~package (Data.Jtriple (Data.Jstring) (Data.Jstring) (Data.Jstring))) ~signals:[computation_signal] get_states + + + +(* ----- Flamegraph --------------------------------------------------------- *) + +module Jkfstack : +sig + include Data.S with type t = Eva_perf.KfList.t + val get : Eva_perf.KfList.t -> int +end = Data.Index + (Eva_perf.KfList.Map) + (struct + let package = package + let name = "kfstack" + let descr = Markdown.plain "Kernel function stack identifier" + end) + +module Jkfs : Request.Output with type t = Eva_perf.KfList.t = struct + + type t = Eva_perf.KfList.t + + let jcalllink = Server.Data.declare ~package + ~name:"calllink" ~descr:(Markdown.plain "Kernel function list infos") + (Jrecord [ + "callee" , Kernel_ast.Decl.jtype ; + "caller" , Joption Kernel_ast.Decl.jtype ; + ]) + + let jtype = Package.(Jarray jcalllink) + + let jkfstack ~jcaller ~jcallee = + `Assoc [ + "callee", jcallee ; + "caller", jcaller ; + ] + + let to_json (cl : t) = + let aux (acc, jcaller) callee = + let jcallee = Kernel_ast.Decl.to_json (SFunction callee) in + jkfstack ~jcaller ~jcallee :: acc, jcallee + in + match cl with + | [] -> `List [] + | entry :: r -> + let entry_point = Kernel_ast.Decl.to_json (SFunction entry) in + let l, _last_callee = + List.fold_left aux + ([`Assoc [ "callee", entry_point ]], entry_point) + (List.rev r) + in `List l + +end + +let _evaFlamegraph = + let model = States.model () in + (* This field is useful for interacting with other components, + eg. the currently selected callstack in EVA values *) + States.column model ~name:"stack" + ~descr:(Markdown.plain "Caller list identifier") + ~data:(module Jkfstack) ~get:fst ; + (* This field contains the computation time *) + States.column model ~name:"time" + ~descr:(Markdown.plain "Computation time for the kernel function stack") + ~data:(module Data.Jfloat) + ~get:(fun (_cs, (_start, duration)) -> duration); + (* This field might be useful to display tooltips on the flames *) + States.column model ~name:"title" + ~descr:(Markdown.plain "Kernel function description") + ~data:(module Data.Jstring) + ~get:(fun (cl,_) -> Pretty_utils.to_string Eva_perf.KfList.pretty cl); + (* This field contains the name of the function on top of the + kernel function stack *) + States.column model ~name:"name" + ~descr:(Markdown.plain "Function name") + ~data:(module Data.Jstring) + ~get:(fun (cl,_) -> Kernel_function.get_name (List.(hd (rev cl)))); + (* This field contains the list of the function names *) + States.column model ~name:"funlist" + ~descr:(Markdown.plain "Function list") + ~data:(module Data.Jstring) + ~get:(fun (cl,_) -> + Pretty_utils.to_string (Eva_perf.KfList.pretty ~sep:":") cl); + (* This field contains the declaration of the function on top of the + kernel function stack *) + States.column model ~name:"kfkey" + ~descr:(Markdown.plain "Kernel function key") + ~data:(module Data.Jstring) + ~get:(fun (cl,_) -> Kernel_ast.Decl.index (SFunction (List.(hd (rev cl))))); + (* Add/remove other fields if necessary... *) + States.register_framac_array + ~package + ~name:"evaFlamegraph" + ~descr:(Markdown.plain "Data for Eva flamegraph") + ~key:(fun cl -> Format.sprintf "#%06d" @@ Jkfstack.get cl) + model (module Eva_perf.EvaFlamegraph) diff --git a/src/plugins/eva/api/values_request.ml b/src/plugins/eva/api/values_request.ml index 74be4f22038405a95f19280ce81edc1f59ce12aa..401d42f473131eed05eb435afe9900debdafb8e5 100644 --- a/src/plugins/eva/api/values_request.ml +++ b/src/plugins/eva/api/values_request.ml @@ -722,98 +722,3 @@ let () = end (* -------------------------------------------------------------------------- *) -(* --- Flamegraph --- *) -(* -------------------------------------------------------------------------- *) - -module Jkfstack : -sig - include Data.S with type t = Eva_perf.KfList.t - val get : Eva_perf.KfList.t -> int -end = Data.Index - (Eva_perf.KfList.Map) - (struct - let package = package - let name = "kfstack" - let descr = Md.plain "Kernel function stack identifier" - end) - -module Jkfs : Request.Output with type t = Eva_perf.KfList.t = struct - - type t = Eva_perf.KfList.t - - let jcalllink = Server.Data.declare ~package - ~name:"calllink" ~descr:(Md.plain "Kernel function list infos") - (Jrecord [ - "callee" , Jdecl.jtype ; - "caller" , Joption Jdecl.jtype ; - ]) - - let jtype = Package.(Jarray jcalllink) - - let jkfstack ~jcaller ~jcallee = - `Assoc [ - "callee", jcallee ; - "caller", jcaller ; - ] - - let to_json (cl : t) = - let aux (acc, jcaller) callee = - let jcallee = Jdecl.to_json (SFunction callee) in - jkfstack ~jcaller ~jcallee :: acc, jcallee - in - match cl with - | [] -> `List [] - | entry :: r -> - let entry_point = Jdecl.to_json (SFunction entry) in - let l, _last_callee = - List.fold_left aux - ([`Assoc [ "callee", entry_point ]], entry_point) - (List.rev r) - in `List l - -end - -let _evaFlamegraph = - let model = States.model () in - (* This field is useful for interacting with other components, - eg. the currently selected callstack in EVA values *) - States.column model ~name:"stack" - ~descr:(Markdown.plain "Caller list identifier") - ~data:(module Jkfstack) ~get:fst ; - (* This field contains the computation time *) - States.column model ~name:"time" - ~descr:(Markdown.plain "Computation time for the kernel function stack") - ~data:(module Data.Jfloat) - ~get:(fun (_cs, (_start, duration)) -> duration); - (* This field might be useful to display tooltips on the flames *) - States.column model ~name:"title" - ~descr:(Markdown.plain "Kernel function description") - ~data:(module Data.Jstring) - ~get:(fun (cl,_) -> Pretty_utils.to_string Eva_perf.KfList.pretty cl); - (* This field contains the name of the function on top of the - kernel function stack *) - States.column model ~name:"name" - ~descr:(Markdown.plain "Function name") - ~data:(module Data.Jstring) - ~get:(fun (cl,_) -> Kernel_function.get_name (List.(hd (rev cl)))); - (* This field contains the list of the function names *) - States.column model ~name:"funlist" - ~descr:(Markdown.plain "Function list") - ~data:(module Data.Jstring) - ~get:(fun (cl,_) -> - Pretty_utils.to_string (Eva_perf.KfList.pretty ~sep:":") cl); - (* This field contains the declaration of the function on top of the - kernel function stack *) - States.column model ~name:"kfkey" - ~descr:(Markdown.plain "Kernel function key") - ~data:(module Data.Jstring) - ~get:(fun (cl,_) -> Kernel_ast.Decl.index (SFunction (List.(hd (rev cl))))); - (* Add/remove other fields if necessary... *) - States.register_framac_array - ~package - ~name:"evaFlamegraph" - ~descr:(Markdown.plain "Data for Eva flamegraph") - ~key:(fun cl -> Format.sprintf "#%06d" @@ Jkfstack.get cl) - model (module Eva_perf.EvaFlamegraph) - -(* -------------------------------------------------------------------------- *)