import { Component, For, Show, createMemo } from 'solid-js'; import { StatsData } from '../utils/types'; import { formatBytes, formatNumber, formatTime } from '../utils/formatters'; import MetricCard from './MetricCard'; import Section from './Section'; import MemoryChart from './MemoryChart'; import TimeChart from './TimeChart'; import OperationsChart from './OperationsChart'; import ThunkChart from './ThunkChart'; const TOOLTIPS = { cpuTime: 'Total CPU user time in seconds spent on Nix expression evaluation', memory: 'Combined memory for all evaluation structures (envs, lists, values, symbols, sets)', nrExprs: 'Total number of Nix expressions parsed and created during evaluation', nrThunks: "Number of thunks (delayed computations) created during evaluation. A thunk is created when a value is needed but hasn't been computed yet.", nrAvoided: 'Number of thunks avoided by value reuse. When a value is already computed, forcing a thunk reuses it instead of creating a new computation.', nrLookups: 'Number of attribute lookups performed (e.g., accessing .attr from an attribute set)', nrPrimOpCalls: 'Total number of builtin function (primop) calls like map, foldl, concatMap, etc.', nrFunctionCalls: 'Total number of user-defined function calls executed', nrOpUpdates: 'Number of attribute set update operations performed (the // operator)', nrOpUpdateValuesCopied: 'Number of values copied during attribute set updates', envsNumber: 'Total number of lexical environments created during evaluation. Environments bind variables to values.', envsElements: 'Total number of values stored in all environment slots across all environments', envsBytes: 'Memory for environments = nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value*)', listElements: 'Total number of list elements ([ ... ]) allocated across all lists', listBytes: 'Memory for list elements = nrListElems * sizeof(Value*) (pointer per element)', listConcats: 'Number of list concatenation operations (++) performed during evaluation', valuesNumber: 'Total number of Value objects allocated during evaluation', valuesBytes: 'Memory for values = nrValues * sizeof(Value)', symbolsNumber: 'Total number of unique symbols interned in the symbol table', symbolsBytes: 'Total memory used by all symbol strings in the symbol table', setsNumber: 'Total number of attribute sets ({ ... }) created during evaluation', setsElements: 'Total number of attributes (key-value pairs) across all attribute sets', setsBytes: 'Memory for attribute sets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr)', narRead: 'Number of NAR (Nix Archive) files read from the Nix store', narWrite: 'Number of NAR (Nix Archive) files written to the Nix store', narReadBytes: 'Total uncompressed bytes read from NAR archives', narWriteBytes: 'Total uncompressed bytes written to NAR archives', gcHeapSize: 'Current size of the garbage collected heap in bytes', gcTotalBytes: 'Total number of bytes allocated since program start', gcCycles: 'Total number of garbage collection cycles performed', attrSelect: 'Number of attribute selections performed (accessing .attr from an attribute set)', }; const Analysis: Component<{ stats: StatsData }> = props => { const totalMemory = createMemo( () => props.stats.envs.bytes + props.stats.list.bytes + props.stats.values.bytes + props.stats.symbols.bytes + props.stats.sets.bytes, ); const memoryBreakdown = createMemo(() => [ { label: 'Envs', value: props.stats.envs.bytes, total: totalMemory(), colorClass: 'chart-1' }, { label: 'Lists', value: props.stats.list.bytes, total: totalMemory(), colorClass: 'chart-2', }, { label: 'Values', value: props.stats.values.bytes, total: totalMemory(), colorClass: 'chart-3', }, { label: 'Symbols', value: props.stats.symbols.bytes, total: totalMemory(), colorClass: 'chart-4', }, { label: 'Sets', value: props.stats.sets.bytes, total: totalMemory(), colorClass: 'chart-5' }, ].sort((a, b) => b.value - a.value), ); const topPrimops = createMemo(() => { if (!props.stats.primops) return []; return Object.entries(props.stats.primops) .sort((a, b) => b[1] - a[1]) .slice(0, 10) .map(([name, count]) => ({ name, count })); }); const topFunctions = createMemo(() => { if (!props.stats.functions) return []; return [...props.stats.functions].sort((a, b) => b.count - a.count).slice(0, 10); }); const topAttributes = createMemo(() => { if (!props.stats.attributes) return []; return [...props.stats.attributes].sort((a, b) => b.count - a.count).slice(0, 10); }); return (