diff --git a/ivette/package.json b/ivette/package.json
index e44cabd9e3d998792d6dd0f9d6896ad0a08a4cba..a443b467f10619e0554b46a7f8b740b19863c915 100644
--- a/ivette/package.json
+++ b/ivette/package.json
@@ -48,6 +48,7 @@
     "react-dom": "^18",
     "react-draggable": "^4.4.6",
     "react-fast-compare": "^3.2.2",
+    "react-flame-graph" : "^1.4.0",
     "react-force-graph-2d": "^1.25.4",
     "react-force-graph-3d": "^1.24.2",
     "react-infinite-scroller": "^1.2.6",
diff --git a/ivette/src/dome/renderer/controls/gallery.json b/ivette/src/dome/renderer/controls/gallery.json
index 36bc7aa800032da1d9b372d45f89656444206013..d5d97ee59f91c835dd423ccec0a110e9964ac2e1 100644
--- a/ivette/src/dome/renderer/controls/gallery.json
+++ b/ivette/src/dome/renderer/controls/gallery.json
@@ -316,6 +316,12 @@
     "viewBox": "0 0 24 24",
     "path": "M15.428 18.429v-2.143q0-0.188-0.121-0.308t-0.308-0.121h-1.286v-6.857q0-0.188-0.121-0.308t-0.308-0.121h-4.286q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h1.286v4.286h-1.286q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h6q0.188 0 0.308-0.121t0.121-0.308zM13.714 6.429v-2.143q0-0.188-0.121-0.308t-0.308-0.121h-2.571q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h2.571q0.188 0 0.308-0.121t0.121-0.308zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z"
   },
+  "TARGET": {
+    "section": "Buttons",
+    "title": "Target",
+    "viewBox": "0 0 32 32",
+    "path": "M32 14h-3.154c-0.864-5.57-5.276-9.982-10.846-10.846v-3.154h-4v3.154c-5.57 0.864-9.982 5.276-10.846 10.846h-3.154v4h3.154c0.864 5.57 5.276 9.982 10.846 10.846v3.154h4v-3.154c5.57-0.864 9.982-5.276 10.846-10.846h3.154v-4zM24.776 14h-3.118c-0.603-1.705-1.953-3.056-3.658-3.658v-3.118c3.36 0.765 6.010 3.416 6.776 6.776zM16 18c-1.105 0-2-0.895-2-2s0.895-2 2-2c1.105 0 2 0.895 2 2s-0.895 2-2 2zM14 7.224v3.118c-1.705 0.603-3.056 1.953-3.658 3.658h-3.118c0.765-3.36 3.416-6.010 6.776-6.776zM7.224 18h3.118c0.603 1.705 1.953 3.056 3.658 3.658v3.118c-3.36-0.765-6.010-3.416-6.776-6.776zM18 24.776v-3.118c1.705-0.603 3.056-1.953 3.658-3.658h3.118c-0.765 3.36-3.416 6.010-6.776 6.776z"
+  },
   "SWITCH.OFF": {
     "section": "Buttons",
     "title": "Off",
diff --git a/ivette/src/frama-c/plugins/eva/Flamegraph.tsx b/ivette/src/frama-c/plugins/eva/Flamegraph.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..41f01b1f881070e9da2616a5f707b34e51590433
--- /dev/null
+++ b/ivette/src/frama-c/plugins/eva/Flamegraph.tsx
@@ -0,0 +1,178 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2024                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+import React from 'react';
+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/general';
+import { FlameGraph } from 'react-flame-graph';
+import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
+import { EvaReady, EvaStatus } from './components/AnalysisStatus';
+import { Inset } from 'dome/frame/toolbars';
+import { useFlipSettings } from 'dome';
+
+// --- Flamegraph Table ---
+interface Flamegraph {
+  kfKey?: string;
+  name: string;
+  value: number;
+  children?: Flamegraph[];
+}
+
+const addNodeToFlamegraph = (
+  flamegraph: Flamegraph,
+  cs: string[],
+  row: Eva.evaFlamegraphData,
+): void => {
+  // Accumulate times for all nodes crossed
+  flamegraph.value += row.time;
+  // updating last node
+  if(cs.length === 0) {
+    flamegraph.kfKey = row.kfkey;
+    return;
+  }
+  // Search/create next node
+  if (!flamegraph.children) flamegraph.children = [];
+  let nextNode = flamegraph.children.find((elt) => elt.name === cs[0]);
+  if (!nextNode) {
+    nextNode = { name: cs[0], value: 0 };
+    flamegraph.children.unshift(nextNode);
+  }
+  cs.shift();
+  // Treatment of the next node
+  addNodeToFlamegraph(nextNode, cs, row);
+};
+
+interface EvaFlamegraphProps {
+  useScope: boolean;
+  flameGraph: Flamegraph;
+  size: Size
+}
+
+/* Round f to at most [decimal] decimals. */
+function round(f: number, decimal: number): number {
+  const factor = 10 ** decimal;
+  return Math.round(f * factor) / factor;
+}
+
+/* Returns text to be shown about a node in a flamegraph. */
+function nodeInfoText(flameGraph:Flamegraph, node:Flamegraph): string {
+  const percentage = round(100 * node.value / flameGraph.value, 1);
+  const value = round(node.value, 2);
+  const infos = node.name + " : " + value + "s : " + percentage + "%";
+  return infos;
+}
+
+function EvaFlamegraph(props: EvaFlamegraphProps): JSX.Element {
+  const { useScope, flameGraph, size } = props;
+  const { width, height } = size;
+  const [ nodeInfos, setNodeInfos ] = React.useState("");
+
+  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
+  const changeScope = (node:any): void => {
+    if (useScope) States.setCurrentScope(node.source.kfKey as Ast.decl);
+  };
+
+  return (
+    <>
+      <FlameGraph
+        data={flameGraph}
+        height={height}
+        width={width}
+        onChange={changeScope}
+        onMouseOver={(_e:Event, node:Flamegraph) => {
+          setNodeInfos(nodeInfoText(flameGraph, node));
+        }}
+        onMouseOut={() => { setNodeInfos(""); }}
+      />
+      {
+        nodeInfos &&
+        <div className='flame-details'>
+          {nodeInfos}
+        </div>
+      }
+    </>
+  );
+}
+
+// --- Flamegraph Component ---
+export function FlamegraphComponent(): JSX.Element {
+  const [useScope, flipUseScope] =
+    useFlipSettings("eva.flamegraph.scope", true);
+  const model = States.useSyncArrayData(Eva.evaFlamegraph);
+
+  const flameGraph = React.useMemo<Flamegraph | null>(() => {
+    if(model.length === 0 ) return null;
+    const flame: Flamegraph = {
+      name: model[0].funlist.split(":")[0],
+      value: 0
+    };
+    model.forEach(row => {
+      const cs = row.funlist.split(":");
+      cs.shift();
+      addNodeToFlamegraph(flame, cs, row);
+    });
+    return flame;
+  }, [model]);
+
+  const isWaitingForData = !flameGraph || !flameGraph.children;
+
+  return (
+    <>
+      <Ivette.TitleBar >
+        <IconButton
+          icon="PIN"
+          kind={useScope ? "positive" : "default"}
+          onClick={flipUseScope}
+          title={useScope ? "Scope change enabled" : "Scope change disabled"}
+        />
+        <Inset />
+        <EvaStatus />
+      </Ivette.TitleBar>
+      <EvaReady showChildrenForComputingStatus={!isWaitingForData} >
+        {
+          !isWaitingForData &&
+          <AutoSizer key="flamegraph">
+            {(size: Size) => (
+              <EvaFlamegraph
+                useScope={useScope}
+                flameGraph={flameGraph}
+                size={size}
+              />
+            )}
+          </AutoSizer>
+        }
+      </EvaReady>
+    </>
+  );
+}
+
+Ivette.registerComponent({
+  id: 'fc.eva.flamegraph',
+  label: 'Eva Flamegraph',
+  title: 'Detailed flamegraph of the Eva analysis',
+  children: <FlamegraphComponent />,
+});
+
+// --------------------------------------------------------------------------
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/index.tsx b/ivette/src/frama-c/plugins/eva/index.tsx
index d277a0fe8d7446e85312ffb17e8d4534b23c8a03..18d19940d089dcd90c2177ed3ebf2cd37cc96706 100644
--- a/ivette/src/frama-c/plugins/eva/index.tsx
+++ b/ivette/src/frama-c/plugins/eva/index.tsx
@@ -30,6 +30,7 @@ import './Summary';
 import './Coverage';
 import './DomainStates';
 import './EvaSidebar';
+import './Flamegraph';
 import './style.css';
 
 // --------------------------------------------------------------------------
@@ -47,7 +48,8 @@ Ivette.registerView({
   layout: {
     'A': 'fc.eva.summary',
     'B': 'fc.eva.coverage',
-    'CD': 'fc.kernel.messages',
+    'C': 'fc.kernel.messages',
+    'D': 'fc.eva.flamegraph',
   },
 });
 
diff --git a/ivette/src/frama-c/plugins/eva/style.css b/ivette/src/frama-c/plugins/eva/style.css
index 41fb3879bf8948076ed5433ae54c9352183ae3ab..3b7861ae8effa376b882369b1e46db2f6c1b25b2 100644
--- a/ivette/src/frama-c/plugins/eva/style.css
+++ b/ivette/src/frama-c/plugins/eva/style.css
@@ -339,6 +339,17 @@ tr:first-of-type > .eva-table-callsite-box {
 .eva-status-icon.eva-computed { fill: var(--eva-alarms-true); }
 .eva-status-icon.eva-not_computed { fill: var(--eva-alarms-false); }
 
+/* -------------------------------------------------------------------------- */
+/* --- Flamegraph                                                         --- */
+/* -------------------------------------------------------------------------- */
+
+.flame-details {
+  padding: 3px 10px;
+  position: absolute;
+  bottom : 0;
+  background-color: var(--background-report);
+}
+
 /* -------------------------------------------------------------------------- */
 /* --- Sidebar Eva                                                        --- */
 /* -------------------------------------------------------------------------- */
diff --git a/ivette/src/frama-c/react-flame-graph.d.ts b/ivette/src/frama-c/react-flame-graph.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff0062665305dbcce1dea513f2bd7856c6b4e3bc
--- /dev/null
+++ b/ivette/src/frama-c/react-flame-graph.d.ts
@@ -0,0 +1,23 @@
+/* ************************************************************************ */
+/*                                                                          */
+/*   This file is part of Frama-C.                                          */
+/*                                                                          */
+/*   Copyright (C) 2007-2024                                                */
+/*     CEA (Commissariat à l'énergie atomique et aux énergies               */
+/*          alternatives)                                                   */
+/*                                                                          */
+/*   you can redistribute it and/or modify it under the terms of the GNU    */
+/*   Lesser General Public License as published by the Free Software        */
+/*   Foundation, version 2.1.                                               */
+/*                                                                          */
+/*   It is distributed in the hope that it will be useful,                  */
+/*   but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*   GNU Lesser General Public License for more details.                    */
+/*                                                                          */
+/*   See the GNU Lesser General Public License version 2.1                  */
+/*   for more details (enclosed in the file licenses/LGPLv2.1).             */
+/*                                                                          */
+/* ************************************************************************ */
+
+declare module 'react-flame-graph';
diff --git a/ivette/yarn.lock b/ivette/yarn.lock
index 573ecf8a41acd737c6ebc929ed39fee2dce137db..2f199e3035293664ca748c61734b6ac3db1d2198 100644
--- a/ivette/yarn.lock
+++ b/ivette/yarn.lock
@@ -3223,6 +3223,11 @@ flatted@^3.1.0:
   resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz"
   integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
 
+flow-bin@^0.118.0:
+  version "0.118.0"
+  resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.118.0.tgz#fb706364a58c682d67a2ca7df39396467dc397d1"
+  integrity sha512-jlbUu0XkbpXeXhan5xyTqVK1jmEKNxE8hpzznI3TThHTr76GiFwK0iRzhDo4KNy+S9h/KxHaqVhTP86vA6wHCg==
+
 for-each@^0.3.3:
   version "0.3.3"
   resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz"
@@ -4350,6 +4355,16 @@ matcher@^3.0.0:
   dependencies:
     escape-string-regexp "^4.0.0"
 
+"memoize-one@>=3.1.1 <6":
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
+  integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+
+memoize-one@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-3.1.1.tgz#ef609811e3bc28970eac2884eece64d167830d17"
+  integrity sha512-YqVh744GsMlZu6xkhGslPSqSurOv6P+kLN2J3ysBZfagLcL5FdRK/0UpgLoL8hwjjEvvAVkjJZyFP+1T6p1vgA==
+
 merge2@^1.3.0, merge2@^1.4.1:
   version "1.4.1"
   resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
@@ -4994,6 +5009,15 @@ react-fast-compare@^3.2.2:
   resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
   integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
 
+react-flame-graph@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/react-flame-graph/-/react-flame-graph-1.4.0.tgz#52d118cc94348f630a812fc0ec530a5b73c30cdb"
+  integrity sha512-DaCK9ZX+xK0mNca72kUE5cu6T8hGe/KLsefQWf+eT9sVt+0WP1dVxZCGD8Svfn2KrZB9Mv011Intg/yG2YWSxA==
+  dependencies:
+    flow-bin "^0.118.0"
+    memoize-one "^3.1.1"
+    react-window "^1"
+
 react-force-graph-2d@^1.25.4:
   version "1.25.4"
   resolved "https://registry.yarnpkg.com/react-force-graph-2d/-/react-force-graph-2d-1.25.4.tgz#91f9e8169d0eeb6a7e36c36dd99da5128702b776"
@@ -5077,6 +5101,14 @@ react-virtualized@9.22.5:
     prop-types "^15.7.2"
     react-lifecycles-compat "^3.0.4"
 
+react-window@^1:
+  version "1.8.10"
+  resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.10.tgz#9e6b08548316814b443f7002b1cf8fd3a1bdde03"
+  integrity sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==
+  dependencies:
+    "@babel/runtime" "^7.0.0"
+    memoize-one ">=3.1.1 <6"
+
 react@^18:
   version "18.2.0"
   resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
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/utils/eva_perf.ml b/src/plugins/eva/utils/eva_perf.ml
index efb4a27305ab0ab8bd4c7af35ec92b903fb956a9..8486714a22a6f306595cca4741db4e6328497a3f 100644
--- a/src/plugins/eva/utils/eva_perf.ml
+++ b/src/plugins/eva/utils/eva_perf.ml
@@ -353,110 +353,116 @@ let reset_perf () =
 
 (* Set to [Some _] if option [-eva-flamegraph] is set and [main] is
    currently being analyzed and the file is ok. Otherwise, set to [None]. *)
-let oc_flamegraph = ref None
-
-let stack_flamegraph = ref []
-(* Callstack for flamegraphs. The most recent function is at the top of the
-   list. The elements of the list are [(starting_time, self_total_time)].
-   [starting_time] is the time when we started analyzing the function.
-   [total_time] is the time spent so far in the function itself, _without the
-   callees_. [total_time] is updated from [starting_time] when we start a
-   callee, or when the analysis of the function ends. This stack is never
-   empty when an analysis is in progress. *)
-
-(* pretty-prints the functions in a Value callstack, starting by main (i.e.
-   in reverse order). *)
-let pretty_callstack oc callstack =
-  let rec aux oc = function
-    | [] -> () (* does not happen in theory *)
-    | [main] -> Printf.fprintf oc "%s" (Kernel_function.get_name main)
-    | kf :: q -> Printf.fprintf oc "%s;%a" (Kernel_function.get_name kf) aux q
-  in
-  aux oc (Callstack.to_kf_list callstack)
+let oc_fmt_flamegraph = ref None
+
+(* We cannot use a Callstack here because we ignore the call statements. *)
+module KfList = struct
+  include Datatype.List_with_collections(Cil_datatype.Kf)
+      (struct
+        let module_name = "Eva.KfList"
+      end)
+  let pretty ?(sep=format_of_string ";") fmt l =
+    Pretty_utils.pp_flowlist ~left:"" ~sep ~right:""
+      (fun fmt kf -> Kernel_function.pretty fmt kf)
+      fmt l
+end
+
+(* A mapping from callstacks to (time_of_last_call, total_duration).
+   [time_of_last_call] is the timestamp of the last time that the leaf function
+   in the callstack was called.
+   [total_duration] is the accumulated total amount of time spent in the
+   callstack.
+*)
+module EvaFlamegraph =
+  State_builder.Hashtbl
+    (KfList.Hashtbl)
+    (Datatype.Pair(Datatype.Float)(Datatype.Float))
+    (struct
+      let name = "Eva.Flamegraph"
+      let dependencies = [ Ast.self ]
+      let size = 20
+    end)
 
 (* update the [self_total_time] information for the function being analyzed,
    assuming that the current time is [time] *)
-let update_self_total_time time =
-  match !stack_flamegraph with
-  | [] -> assert false
-  | (start_caller, total) :: q ->
+let update_self_total_time cl time =
+  try
+    let (start_caller, total) = EvaFlamegraph.find cl in
     let d = duration start_caller time in
-    stack_flamegraph := (start_caller, d +. total) :: q
+    let new_total = d +. total in
+    EvaFlamegraph.replace cl (time, new_total);
+    new_total
+  with Not_found ->
+    Self.fatal
+      "EvaFlamegraph: caller list not found: %a"
+      (KfList.pretty ~sep:";") cl
+
+let start_call_flamegraph_main cl =
+  (* Analysis of main *)
+  EvaFlamegraph.clear ();
+  EvaFlamegraph.add cl (Sys.time (), 0.0);
+  if not (Parameters.ValPerfFlamegraphs.is_empty ()) then begin
+    let file = Parameters.ValPerfFlamegraphs.get () in
+    try
+      let oc = open_out (file:>string) in
+      oc_fmt_flamegraph := Some (oc, Format.formatter_of_out_channel oc);
+    with e ->
+      Self.error "cannot open flamegraph file: %s"
+        (Printexc.to_string e);
+      oc_fmt_flamegraph := None (* to be on the safe side  *)
+  end
 
 (* called when a new function is being analyzed *)
-let start_doing_flamegraph callstack =
-  match callstack.Callstack.stack with
-  | [] ->
-    (* Analysis of main *)
-    if not (Parameters.ValPerfFlamegraphs.is_empty ()) then begin
-      let file = Parameters.ValPerfFlamegraphs.get () in
-      try
-        (* Flamegraphs must be computed. Set up the stack and the output file *)
-        let oc = open_out (file:>string) in
-        oc_flamegraph := Some oc;
-        stack_flamegraph := [ (Sys.time (), 0.) ]
-      with e ->
-        Self.error "cannot open flamegraph file: %s"
-          (Printexc.to_string e);
-        oc_flamegraph := None (* to be on the safe side  *)
-    end
-  | _ :: _ ->
-    if !oc_flamegraph <> None then
-      (* Flamegraphs are being computed. Update time spent in current function
-         so far, then push a slot for the analysis of the new function *)
-      let time = Sys.time () in
-      update_self_total_time time;
-      stack_flamegraph := (time, 0.) :: !stack_flamegraph;
+let start_call_flamegraph ~prev cs =
+  let cl = Callstack.to_kf_list cs in
+  let prev = Option.map Callstack.to_kf_list prev in
+  match prev with
+  | None -> start_call_flamegraph_main cl
+  | Some prev ->
+    let time = Sys.time () in
+    ignore (update_self_total_time prev time);
+    let (_start, total) =
+      try EvaFlamegraph.find cl with Not_found -> (0.0, 0.0)
+    in
+    EvaFlamegraph.replace cl (time, total)
 ;;
 
 (* called when the analysis of a function ends. This function is at the top
    of [callstack] *)
-let stop_doing_flamegraph callstack =
-  match !oc_flamegraph with
-  | None -> ()
-  | Some oc -> (* Flamegraphs are being recorded *)
-    let time = Sys.time() in
-    update_self_total_time time; (* update current function *)
-    match !stack_flamegraph with
-    | [] -> assert false
-    | (_, total) :: q ->
-      (* dump the total time (that we just updated) for the current function *)
-      Printf.fprintf oc "%a %.3f\n%!"
-        pretty_callstack callstack (total *. 1000.);
-      match q with
-      | [] -> stack_flamegraph := [] (* we are back to the main function *)
-      | (_, total_caller) :: q' ->
-        (* drop the current function from the flamegraph stack AND update
-           the 'current time' information, so that the time spent in the
-           callee is not counted. *)
-        stack_flamegraph := (time, total_caller) :: q'
-;;
+let end_call_flamegraph cs =
+  let cl = Callstack.to_kf_list cs in
+  let time = Sys.time () in
+  let total = update_self_total_time cl time in (* update current function *)
+  begin
+    match !oc_fmt_flamegraph with
+    | None -> ()
+    | Some (_, fmt) -> (* Flamegraphs are being written to a file *)
+      Format.fprintf fmt "%a %.3f\n%!"
+        (KfList.pretty ~sep:";") cl (total *. 1000.)
+  end
 
 let reset_flamegraph () =
-  match !oc_flamegraph with
+  EvaFlamegraph.clear ();
+  match !oc_fmt_flamegraph with
   | None -> ()
-  | Some fd -> close_out fd; stack_flamegraph := []; oc_flamegraph := None
-
+  | Some (oc, _) ->
+    close_out oc; oc_fmt_flamegraph := None
 
 (* -------------------------------------------------------------------------- *)
 (* --- Exported interface                                                 --- *)
 (* -------------------------------------------------------------------------- *)
 
-let start_doing callgraph =
-  start_doing_perf callgraph;
-  start_doing_flamegraph callgraph;
-;;
+let start_call ~prev cs =
+  start_doing_perf cs;
+  start_call_flamegraph ~prev cs
 
-let stop_doing callgraph =
+let end_call callgraph =
   stop_doing_perf callgraph;
-  stop_doing_flamegraph callgraph;
-;;
-
+  end_call_flamegraph callgraph
 
 let reset () =
   reset_perf ();
-  reset_flamegraph ();
-;;
+  reset_flamegraph ()
 
 
 (* TODO: Output files with more graphical outputs, such as
diff --git a/src/plugins/eva/utils/eva_perf.mli b/src/plugins/eva/utils/eva_perf.mli
index 77bfd55f02a30fc6758f6f7ed3a180ecaf8cde43..20a78d8f2586145482bded1d76791a6f3c1f2f99 100644
--- a/src/plugins/eva/utils/eva_perf.mli
+++ b/src/plugins/eva/utils/eva_perf.mli
@@ -20,13 +20,13 @@
 (*                                                                        *)
 (**************************************************************************)
 
-(** Call [start_doing] when starting analyzing a new function. The new
-    function is on the top of the call stack.*)
-val start_doing: Callstack.t -> unit
+(** Call [start_call] when starting analyzing a new function call.
+    The new function is on the top of the call stack.*)
+val start_call: prev:Callstack.t option -> Callstack.t -> unit
 
-(** Call [start_doing] when finishing analyzing a function. The
+(** Call [end_call] when finishing analyzing a function. The
     function must still be on the top of the call stack. *)
-val stop_doing: Callstack.t -> unit
+val end_call: Callstack.t -> unit
 
 (** Display a complete summary of performance informations. Can be
     called during the analysis. *)
@@ -35,3 +35,13 @@ val display: Format.formatter -> unit
 (** Reset the internal state of the module; to call at the very
     beginning of the analysis. *)
 val reset: unit -> unit
+
+module KfList : sig
+  include Datatype.S_with_collections with type t = Kernel_function.t list
+  val pretty : ?sep:Pretty_utils.sformat -> Format.formatter ->
+    Kernel_function.t list -> unit
+end
+
+module EvaFlamegraph :
+  State_builder.Hashtbl with type key = KfList.t
+                         and type data = float * float
diff --git a/src/plugins/eva/utils/eva_utils.ml b/src/plugins/eva/utils/eva_utils.ml
index f8da531466ce7d087c4a37df41e232e67fa5fdb2..eafb7d948df2fca06a4cc9932f78d69d51e04f4d 100644
--- a/src/plugins/eva/utils/eva_utils.ml
+++ b/src/plugins/eva/utils/eva_utils.ml
@@ -30,14 +30,14 @@ let clear_call_stack () =
   match !current_callstack with
   | None -> ()
   | Some cs ->
-    Eva_perf.stop_doing cs;
+    Eva_perf.end_call cs;
     current_callstack := None
 
 let init_call_stack kf =
   assert (!current_callstack = None);
   let cs = Callstack.init kf in
   current_callstack := Some cs;
-  Eva_perf.start_doing cs;
+  Eva_perf.start_call ~prev:None cs;
   cs
 
 let current_call_stack_opt () = !current_callstack
@@ -55,11 +55,11 @@ let push_call_stack kf stmt =
   let cs = current_call_stack () in
   let new_cs = Callstack.push kf stmt cs in
   current_callstack := Some new_cs;
-  Eva_perf.start_doing new_cs
+  Eva_perf.start_call ~prev:(Some cs) new_cs
 
 let pop_call_stack () =
   let cs = current_call_stack () in
-  Eva_perf.stop_doing cs;
+  Eva_perf.end_call cs;
   current_callstack := Callstack.pop cs
 
 let pp_callstack fmt =