Add GPU stats to the /stats API and debug screen (#3931)

* Add ffprobe endpoint

* Get ffprobe for multiple inputs

* Copy ffprobe in output

* Fix bad if statement

* Return full output of ffprobe process

* Return full output of ffprobe process

* Make ffprobe button show dialog with output and option to copy

* Add driver names to consts

* Add driver env var name

* Setup general tracking for GPU stats

* Catch RPi args as well

* Add util to get radeontop results

* Add real amd GPU stats

* Fix missed arg

* pass config

* Use only the values

* Fix vram

* Add nvidia gpu stats

* Use nvidia stats

* Add chart for gpu stats

* Format AMD with space between percent

* Get correct nvidia %

* Start to add support for intel GPU stats

* Block out RPi as util is not currently available

* Formatting

* Fix mypy

* Strip for float conversion

* Strip for float conversion

* Fix percent formatting

* Remove name from gpu map

* Add tests and fix AMD formatting

* Add nvidia gpu stats test

* Formatting

* Add intel_gpu_top for testing

* Formatting

* Handle case where hwaccel is not setup

* Formatting

* Check to remove none

* Don't use set

* Cleanup and fix types

* Handle case where args is list

* Fix mypy

* Cast to str

* Fix type checking

* Return none instead of empty

* Fix organization

* Make keys consistent

* Make gpu match style

* Get support for vainfo

* Add vainfo endpoint

* Set vainfo output in error correctly

* Remove duplicate function

* Fix errors

* Do cpu & gpu work asynchonously

* Fix async

* Fix event loop

* Fix crash

* Fix naming

* Send empty data for gpu if error occurs

* Show error if gpu stats could not be retrieved

* Fix mypy

* Fix test

* Don't use json for vainfo

* Fix cross references

* Strip unicode still

* await vainfo response

* Add gpu deps

* Formatting

* remove comments

* Use empty string

* Add vainfo back in
This commit is contained in:
Nicolas Mowen
2022-11-28 18:24:20 -07:00
committed by GitHub
parent 3cb6d43fac
commit aaedd24f37
7 changed files with 365 additions and 11 deletions

View File

@@ -21,9 +21,17 @@ export default function System() {
} = useWs('stats');
const { data: initialStats } = useSWR('stats');
const { cpu_usages, detectors, service = {}, detection_fps: _, ...cameras } = stats || initialStats || emptyObject;
const {
cpu_usages,
gpu_usages,
detectors,
service = {},
detection_fps: _,
...cameras
} = stats || initialStats || emptyObject;
const detectorNames = Object.keys(detectors || emptyObject);
const gpuNames = Object.keys(gpu_usages || emptyObject);
const cameraNames = Object.keys(cameras || emptyObject);
const handleCopyConfig = useCallback(() => {
@@ -55,9 +63,9 @@ export default function System() {
});
if (response.status === 200) {
setState({ showFfprobe: true, ffprobe: JSON.stringify(response.data, null, 2) });
setState({ ...state, showFfprobe: true, ffprobe: JSON.stringify(response.data, null, 2) });
} else {
setState({ ...state, ffprobe: 'There was an error getting the ffprobe output.' });
setState({ ...state, showFfprobe: true, ffprobe: 'There was an error getting the ffprobe output.' });
}
};
@@ -66,11 +74,31 @@ export default function System() {
setState({ ...state, ffprobe: '', showFfprobe: false });
};
const onHandleVainfo = async (e) => {
if (e) {
e.stopPropagation();
}
const response = await axios.get('vainfo');
if (response.status === 200) {
setState({ ...state, showVainfo: true, vainfo: JSON.stringify(response.data, null, 2) });
} else {
setState({ ...state, showVainfo: true, vainfo: 'There was an error getting the vainfo output.' });
}
};
const onCopyVainfo = async () => {
await window.navigator.clipboard.writeText(JSON.stringify(state.vaifp, null, 2));
setState({ ...state, vainfo: '', showVainfo: false });
};
return (
<div className="space-y-4 p-2 px-4">
<Heading>
System <span className="text-sm">{service.version}</span>
</Heading>
{state.showFfprobe && (
<Dialog>
<div className="p-4">
@@ -92,6 +120,23 @@ export default function System() {
</Dialog>
)}
{state.showVainfo && (
<Dialog>
<div className="p-4">
<Heading size="lg">Vainfo Output</Heading>
{state.vainfo != '' ? <p className="mb-2">{state.vainfo}</p> : <ActivityIndicator />}
</div>
<div className="p-2 flex justify-start flex-row-reverse space-x-2">
<Button className="ml-2" onClick={() => onCopyVainfo()} type="text">
Copy
</Button>
<Button className="ml-2" onClick={() => setState({ ...state, vainfo: '', showVainfo: false })} type="text">
Close
</Button>
</div>
</Dialog>
)}
{!detectors ? (
<div>
<ActivityIndicator />
@@ -125,6 +170,50 @@ export default function System() {
))}
</div>
<div className="text-lg flex justify-between p-4">
<Heading size="lg">GPUs</Heading>
<Button onClick={(e) => onHandleVainfo(e)}>vainfo</Button>
</div>
{!gpu_usages ? (
<div className="p-4">
<Link href={'https://docs.frigate.video/configuration/hardware_acceleration'}>
Hardware acceleration has not been setup, see the docs to setup hardware acceleration.
</Link>
</div>
) : (
<div data-testid="gpus" className="grid grid-cols-1 3xl:grid-cols-3 md:grid-cols-2 gap-4">
{gpuNames.map((gpu) => (
<div key={gpu} className="dark:bg-gray-800 shadow-md hover:shadow-lg rounded-lg transition-shadow">
<div className="text-lg flex justify-between p-4">{gpu}</div>
<div className="p-2">
{gpu_usages[gpu]['gpu'] == -1 ? (
<div className="p-4">
There was an error getting usage stats. Either your GPU does not support this or frigate does
not have proper access.
</div>
) : (
<Table className="w-full">
<Thead>
<Tr>
<Th>Gpu %</Th>
<Th>Memory %</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>{gpu_usages[gpu]['gpu']}</Td>
<Td>{gpu_usages[gpu]['mem']}</Td>
</Tr>
</Tbody>
</Table>
)}
</div>
</div>
))}
</div>
)}
<Heading size="lg">Cameras</Heading>
<div data-testid="cameras" className="grid grid-cols-1 3xl:grid-cols-3 md:grid-cols-2 gap-4">
{cameraNames.map((camera) => (