File
Blob: worker/src/client/exhibit/details/hardware-details.tsx
| 1 | import type { Hardware } from '@/shared/contracts/hardware.ts'; |
| 2 | import { formatBytes } from '@/client/ui/format.ts'; |
| 3 | |
| 4 | export function HardwareDetails({ |
| 5 | hardware, |
| 6 | radioStack, |
| 7 | analysisStack, |
| 8 | }: { |
| 9 | hardware?: Hardware | null; |
| 10 | radioStack?: number; |
| 11 | analysisStack?: number; |
| 12 | }) { |
| 13 | return ( |
| 14 | <div className="mt-3 border-t border-line pt-3 text-xs leading-relaxed"> |
| 15 | <p> |
| 16 | CPU bars show non-idle task time over one second. Temperature is measured inside the chip. |
| 17 | </p> |
| 18 | {hardware ? ( |
| 19 | <> |
| 20 | <table className="mt-3 w-full table-fixed text-[10px] [&_th]:pb-1 [&_th]:font-medium [&_td]:py-1 [&_td]:text-right [&_td]:font-mono [&_th]:text-right [&_th:first-child]:text-left [&_td:first-child]:text-left [&_td:first-child]:font-sans"> |
| 21 | <thead> |
| 22 | <tr> |
| 23 | <th>Memory</th> |
| 24 | <th>Free</th> |
| 25 | <th>Minimum</th> |
| 26 | <th>Largest block</th> |
| 27 | </tr> |
| 28 | </thead> |
| 29 | <tbody> |
| 30 | {( |
| 31 | [ |
| 32 | ['Internal', hardware.internal], |
| 33 | ['PSRAM', hardware.psram], |
| 34 | ] as const |
| 35 | ).map(([label, memory]) => ( |
| 36 | <tr key={label}> |
| 37 | <td>{label}</td> |
| 38 | <td>{formatBytes(memory.free)}</td> |
| 39 | <td>{formatBytes(memory.minimumFree)}</td> |
| 40 | <td>{formatBytes(memory.largestBlock)}</td> |
| 41 | </tr> |
| 42 | ))} |
| 43 | </tbody> |
| 44 | </table> |
| 45 | <p className="mt-3"> |
| 46 | Stack headroom: radio {formatBytes(radioStack)}, analysis {formatBytes(analysisStack)}, |
| 47 | sampler {formatBytes(hardware.samplerStackFree)}. These are minima since boot. |
| 48 | </p> |
| 49 | <p className="mt-2"> |
| 50 | Last sampling cost: {(hardware.sampleCostUs / 1000).toFixed(2)} ms. |
| 51 | </p> |
| 52 | </> |
| 53 | ) : null} |
| 54 | </div> |
| 55 | ); |
| 56 | } |