1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

feat(gpu): rework docker GPU for UI performance [EE-4918] (#8518)

This commit is contained in:
Ali 2023-03-03 14:47:10 +13:00 committed by GitHub
parent 769c8372fb
commit fd916bc8a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 692 additions and 285 deletions

View file

@ -10,6 +10,7 @@ import { OptionProps } from 'react-select/dist/declarations/src/components/Optio
import { Select } from '@@/form-components/ReactSelect';
import { Switch } from '@@/form-components/SwitchField/Switch';
import { Tooltip } from '@@/Tip/Tooltip';
import { TextTip } from '@@/Tip/TextTip';
interface Values {
enabled: boolean;
@ -35,6 +36,7 @@ export interface Props {
gpus: GPU[];
usedGpus: string[];
usedAllGpus: boolean;
enableGpuManagement?: boolean;
}
const NvidiaCapabilitiesOptions = [
@ -103,6 +105,7 @@ export function Gpu({
gpus = [],
usedGpus = [],
usedAllGpus,
enableGpuManagement,
}: Props) {
const options = useMemo(() => {
const options = (gpus || []).map((gpu) => ({
@ -181,30 +184,38 @@ export function Gpu({
return (
<div>
{!enableGpuManagement && (
<TextTip color="blue">
GPU in the UI is not currently enabled for this environment.
</TextTip>
)}
<div className="form-group">
<div className="col-sm-3 col-lg-2 control-label text-left">
Enable GPU
<Switch
id="enabled"
name="enabled"
checked={values.enabled}
checked={values.enabled && !!enableGpuManagement}
onChange={toggleEnableGpu}
className="ml-2"
disabled={enableGpuManagement === false}
/>
</div>
<div className="col-sm-9 col-lg-10 text-left">
<Select<GpuOption, true>
isMulti
closeMenuOnSelect
value={gpuValue}
isClearable={false}
backspaceRemovesValue={false}
isDisabled={!values.enabled}
onChange={onChangeSelectedGpus}
options={options}
components={{ MultiValueRemove }}
/>
</div>
{enableGpuManagement && values.enabled && (
<div className="col-sm-9 col-lg-10 text-left">
<Select<GpuOption, true>
isMulti
closeMenuOnSelect
value={gpuValue}
isClearable={false}
backspaceRemovesValue={false}
isDisabled={!values.enabled}
onChange={onChangeSelectedGpus}
options={options}
components={{ MultiValueRemove }}
/>
</div>
)}
</div>
{values.enabled && (

View file

@ -15,7 +15,7 @@ import { gpus } from './gpus';
export function useColumns(
isHostColumnVisible: boolean,
isGPUsColumnVisible: boolean
isGPUsColumnVisible?: boolean
) {
return useMemo(
() =>

View file

@ -1,8 +1,9 @@
import _ from 'lodash';
import { useInfo } from '@/docker/services/system.service';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { ResourceControlViewModel } from '@/react/portainer/access-control/models/ResourceControlViewModel';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { useInfo } from '@/docker/services/system.service';
import { useEnvironment } from '@/react/portainer/environments/queries';
import { DockerContainer, ContainerStatus } from './types';
import { DockerContainerResponse } from './types/response';
@ -95,10 +96,13 @@ function createStatus(statusText = ''): ContainerStatus {
}
export function useShowGPUsColumn(environmentID: EnvironmentId) {
const envInfoQuery = useInfo(
const isDockerStandaloneQuery = useInfo(
environmentID,
(info) => !!info.Swarm?.NodeID && !!info.Swarm?.ControlAvailable
(info) => !(!!info.Swarm?.NodeID && !!info.Swarm?.ControlAvailable) // is not a swarm environment, therefore docker standalone
);
return envInfoQuery.data !== true && !envInfoQuery.isLoading;
const enableGPUManagementQuery = useEnvironment(
environmentID,
(env) => env?.EnableGPUManagement
);
return isDockerStandaloneQuery.data && enableGPUManagementQuery.data;
}

View file

@ -0,0 +1,73 @@
import { array, object, string } from 'yup';
import { r2a } from '@/react-tools/react2angular';
import { withControlledInput } from '@/react-tools/withControlledInput';
import { InputList } from '@@/form-components/InputList';
import { ItemProps } from '@@/form-components/InputList/InputList';
import { InputGroup } from '@@/form-components/InputGroup';
export interface Gpu {
value: string;
name: string;
}
interface Props {
value: Gpu[];
onChange(value: Gpu[]): void;
}
function Item({ item, onChange }: ItemProps<Gpu>) {
return (
<div className="flex flex-grow gap-2">
<InputGroup size="small" className="flex-grow">
<InputGroup.Addon>GPU Name</InputGroup.Addon>
<InputGroup.Input
placeholder="my-gpu"
value={item.name}
onChange={(e) => {
onChange({ ...item, name: e.target.value });
}}
/>
</InputGroup>
<InputGroup size="small" className="flex-grow">
<InputGroup.Addon>Index or UUID</InputGroup.Addon>
<InputGroup.Input
placeholder="0 or GPU-6e2c7185-c3d3-ae22-da43-bc5267b89061"
value={item.value}
onChange={(e) => {
onChange({ ...item, value: e.target.value });
}}
/>
</InputGroup>
</div>
);
}
export function GpusList({ value, onChange }: Props) {
return (
<InputList<Gpu>
label="GPUs"
tooltip="You may optionally set up the GPUs that will be selectable against containers, although 'All GPUs' will always be available."
value={value}
onChange={onChange}
itemBuilder={() => ({ value: '', name: '' })}
addLabel="Add GPU"
item={Item}
/>
);
}
export function gpusListValidation() {
const gpuShape = object().shape({
name: string().required(),
value: string().required(),
});
return array().of(gpuShape).default([]);
}
export const GpusListAngular = r2a(withControlledInput(GpusList), [
'value',
'onChange',
]);