Skip to content

Commit 1ece29b

Browse files
authored
Enable the user to specify a number of concurrent jobs when starting the experiments queue (#3048)
* switch runner for executor * wire up starting the queue with input box * reorder command and event lists * refactor input box validator
1 parent 14145cc commit 1ece29b

File tree

12 files changed

+124
-33
lines changed

12 files changed

+124
-33
lines changed

extension/src/cli/dvc/constants.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export enum Command {
2525
PLOTS = 'plots',
2626
PULL = 'pull',
2727
PUSH = 'push',
28+
QUEUE = 'queue',
2829
REMOVE = 'remove',
2930
ROOT = 'root',
3031
PARAMS = 'params',
@@ -41,6 +42,7 @@ export enum Flag {
4142
ALL_COMMITS = '-A',
4243
FORCE = '-f',
4344
GRANULAR = '--granular',
45+
JOBS = '-j',
4446
JSON = '--json',
4547
NUM_COMMIT = '-n',
4648
OUTPUT_PATH = '-o',
@@ -59,11 +61,14 @@ export enum ExperimentSubCommand {
5961
RUN = 'run'
6062
}
6163

64+
export enum QueueSubCommand {
65+
START = 'start'
66+
}
67+
6268
export enum ExperimentFlag {
6369
NO_FETCH = '--no-fetch',
6470
QUEUE = '--queue',
65-
RESET = '--reset',
66-
RUN_ALL = '--run-all'
71+
RESET = '--reset'
6772
}
6873

6974
export enum GcPreserveFlag {

extension/src/cli/dvc/executor.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,28 @@ describe('CliExecutor', () => {
563563
})
564564
})
565565

566+
describe('queueStart', () => {
567+
it("should call createProcess with the correct parameters to start the experiment's queue", async () => {
568+
const cwd = __dirname
569+
const jobs = '91231324'
570+
571+
const stdout = `Started '${jobs}' new experiments task queue workers.`
572+
573+
mockedCreateProcess.mockReturnValueOnce(getMockedProcess(stdout))
574+
575+
const output = await dvcExecutor.queueStart(cwd, jobs)
576+
577+
expect(output).toStrictEqual(stdout)
578+
579+
expect(mockedCreateProcess).toHaveBeenCalledWith({
580+
args: ['queue', 'start', '-j', jobs],
581+
cwd,
582+
env: mockedEnv,
583+
executable: 'dvc'
584+
})
585+
})
586+
})
587+
566588
describe('remove', () => {
567589
it('should call createProcess with the correct parameters to remove a .dvc file', async () => {
568590
const cwd = __dirname

extension/src/cli/dvc/executor.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
ExperimentFlag,
66
ExperimentSubCommand,
77
Flag,
8-
GcPreserveFlag
8+
GcPreserveFlag,
9+
QueueSubCommand
910
} from './constants'
1011
import { typeCheckCommands } from '..'
1112
import { ContextKey, setContextValue } from '../../vscode/context'
@@ -25,6 +26,7 @@ export const autoRegisteredCommands = {
2526
MOVE: 'move',
2627
PULL: 'pull',
2728
PUSH: 'push',
29+
QUEUE_START: 'queueStart',
2830
REMOVE: 'remove'
2931
} as const
3032

@@ -126,6 +128,16 @@ export class DvcExecutor extends DvcCli {
126128
return this.blockAndExecuteProcess(cwd, Command.PUSH, ...args)
127129
}
128130

131+
public queueStart(cwd: string, jobs: string) {
132+
return this.executeDvcProcess(
133+
cwd,
134+
Command.QUEUE,
135+
QueueSubCommand.START,
136+
Flag.JOBS,
137+
jobs
138+
)
139+
}
140+
129141
public remove(cwd: string, ...args: Args) {
130142
return this.blockAndExecuteProcess(cwd, Command.REMOVE, ...args)
131143
}

extension/src/cli/dvc/runner.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import { Disposable } from '../../class/dispose'
1919

2020
export const autoRegisteredCommands = {
2121
EXPERIMENT_RESET_AND_RUN: 'runExperimentReset',
22-
EXPERIMENT_RUN: 'runExperiment',
23-
EXPERIMENT_RUN_QUEUED: 'runExperimentQueue'
22+
EXPERIMENT_RUN: 'runExperiment'
2423
} as const
2524

2625
export class DvcRunner extends Disposable implements ICli {
@@ -112,10 +111,6 @@ export class DvcRunner extends Disposable implements ICli {
112111
return this.runExperiment(dvcRoot, ExperimentFlag.RESET, ...args)
113112
}
114113

115-
public runExperimentQueue(dvcRoot: string) {
116-
return this.runExperiment(dvcRoot, ExperimentFlag.RUN_ALL)
117-
}
118-
119114
public async run(cwd: string, ...args: Args) {
120115
await this.pseudoTerminal.openCurrentInstance()
121116
if (!this.pseudoTerminal.isBlocked()) {

extension/src/commands/external.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ export enum RegisteredCliCommands {
55
EXPERIMENT_REMOVE = 'dvc.removeExperiment',
66
EXPERIMENT_REMOVE_QUEUE = 'dvc.removeExperimentQueue',
77
EXPERIMENT_REMOVE_QUEUED = 'dvc.removeQueuedExperiment',
8+
EXPERIMENT_RESET_AND_RUN = 'dvc.resetAndRunCheckpointExperiment',
89
EXPERIMENT_RESUME = 'dvc.resumeCheckpointExperiment',
910
EXPERIMENT_RUN = 'dvc.runExperiment',
10-
EXPERIMENT_RUN_QUEUED = 'dvc.startExperimentsQueue',
11-
EXPERIMENT_RESET_AND_RUN = 'dvc.resetAndRunCheckpointExperiment',
1211
EXPERIMENT_SHARE_AS_BRANCH = 'dvc.shareExperimentAsBranch',
1312
EXPERIMENT_SHARE_AS_COMMIT = 'dvc.shareExperimentAsCommit',
1413
QUEUE_EXPERIMENT = 'dvc.queueExperiment',
14+
QUEUE_START = 'dvc.startExperimentsQueue',
1515

1616
EXPERIMENT_VIEW_APPLY = 'dvc.views.experiments.applyExperiment',
1717
EXPERIMENT_VIEW_BRANCH = 'dvc.views.experiments.branchExperiment',

extension/src/experiments/commands/register.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,17 @@ const registerExperimentRunCommands = (
294294
)
295295

296296
internalCommands.registerExternalCliCommand(
297-
RegisteredCliCommands.EXPERIMENT_RUN_QUEUED,
298-
() => experiments.getCwdThenRun(AvailableCommands.EXPERIMENT_RUN_QUEUED)
297+
RegisteredCliCommands.QUEUE_START,
298+
() =>
299+
experiments.getCwdIntegerInputAndRun(
300+
AvailableCommands.QUEUE_START,
301+
Title.ENTER_EXPERIMENT_WORKER_COUNT,
302+
{
303+
prompt:
304+
'Input the maximum number of concurrent queue workers to start.',
305+
value: '1'
306+
}
307+
)
299308
)
300309

301310
internalCommands.registerExternalCommand(

extension/src/experiments/workspace.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Args, DVCLIVE_ONLY_RUNNING_SIGNAL_FILE } from '../cli/dvc/constants'
66
import { CommandId, InternalCommands } from '../commands/internal'
77
import { ResourceLocator } from '../resourceLocator'
88
import { Toast } from '../vscode/toast'
9-
import { getInput } from '../vscode/inputBox'
9+
import { getInput, getPositiveIntegerInput } from '../vscode/inputBox'
1010
import { BaseWorkspaceWebviews } from '../webview/workspace'
1111
import { Title } from '../vscode/title'
1212
import { ContextKey, setContextValue } from '../vscode/context'
@@ -264,6 +264,25 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
264264
return this.runCommand(commandId, cwd, name)
265265
}
266266

267+
public async getCwdIntegerInputAndRun(
268+
commandId: CommandId,
269+
title: Title,
270+
options: { prompt: string; value: string }
271+
) {
272+
const cwd = await this.getFocusedOrOnlyOrPickProject()
273+
if (!cwd) {
274+
return
275+
}
276+
277+
const integer = await getPositiveIntegerInput(title, options)
278+
279+
if (!integer) {
280+
return
281+
}
282+
283+
return this.runCommand(commandId, cwd, integer)
284+
}
285+
267286
public runCommand(commandId: CommandId, cwd: string, ...args: Args) {
268287
return Toast.showOutput(
269288
this.internalCommands.executeCommand(commandId, cwd, ...args)

extension/src/telemetry/constants.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,30 +137,30 @@ export interface IEventNamePropertyMapping {
137137
[EventName.EXPERIMENT_REMOVE_QUEUED]: undefined
138138
[EventName.EXPERIMENT_RESUME]: undefined
139139
[EventName.EXPERIMENT_RUN]: undefined
140-
[EventName.EXPERIMENT_RUN_QUEUED]: undefined
141140
[EventName.EXPERIMENT_RESET_AND_RUN]: undefined
142141
[EventName.EXPERIMENT_SELECT]: undefined
143142
[EventName.EXPERIMENT_SHARE_AS_BRANCH]: undefined
144143
[EventName.EXPERIMENT_SHARE_AS_COMMIT]: undefined
145144
[EventName.EXPERIMENT_SHOW]: undefined
146-
[EventName.EXPERIMENT_SORT_ADD]: undefined
147145
[EventName.EXPERIMENT_SORT_ADD_STARRED]: undefined
146+
[EventName.EXPERIMENT_SORT_ADD]: undefined
148147
[EventName.EXPERIMENT_SORT_REMOVE]: undefined
149-
[EventName.EXPERIMENT_SORTS_REMOVE]: undefined
150148
[EventName.EXPERIMENT_SORTS_REMOVE_ALL]: undefined
149+
[EventName.EXPERIMENT_SORTS_REMOVE]: undefined
150+
[EventName.EXPERIMENT_TOGGLE]: undefined
151151
[EventName.EXPERIMENT_VIEW_APPLY]: undefined
152152
[EventName.EXPERIMENT_VIEW_BRANCH]: undefined
153153
[EventName.EXPERIMENT_VIEW_REMOVE]: undefined
154154
[EventName.EXPERIMENT_VIEW_SHARE_AS_BRANCH]: undefined
155155
[EventName.EXPERIMENT_VIEW_SHARE_AS_COMMIT]: undefined
156-
[EventName.EXPERIMENT_TOGGLE]: undefined
156+
[EventName.QUEUE_EXPERIMENT]: undefined
157+
[EventName.QUEUE_START]: undefined
157158

158159
[EventName.EXPERIMENT_VIEW_QUEUE]: undefined
159160
[EventName.EXPERIMENT_VIEW_RESUME]: undefined
160161
[EventName.EXPERIMENT_VIEW_RUN]: undefined
161162
[EventName.EXPERIMENT_VIEW_RESET_AND_RUN]: undefined
162163

163-
[EventName.QUEUE_EXPERIMENT]: undefined
164164
[EventName.MODIFY_EXPERIMENT_PARAMS_AND_QUEUE]: undefined
165165
[EventName.MODIFY_EXPERIMENT_PARAMS_AND_RESUME]: undefined
166166
[EventName.MODIFY_EXPERIMENT_PARAMS_AND_RUN]: undefined

extension/src/test/suite/experiments/workspace.test.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,17 +439,23 @@ suite('Workspace Experiments Test Suite', () => {
439439

440440
describe('dvc.startExperimentsQueue', () => {
441441
it('should be able to execute all experiments in the run queue', async () => {
442-
const mockRunExperimentQueue = stub(
443-
DvcRunner.prototype,
444-
'runExperimentQueue'
445-
).resolves(undefined)
442+
const mockQueueStart = stub(DvcExecutor.prototype, 'queueStart').resolves(
443+
undefined
444+
)
445+
446+
const dDosNumberOfJobs = '10000'
447+
448+
const mockInputBox = stub(window, 'showInputBox').resolves(
449+
dDosNumberOfJobs
450+
)
446451

447452
stubWorkspaceExperimentsGetters(dvcDemoPath)
448453

449-
await commands.executeCommand(RegisteredCliCommands.EXPERIMENT_RUN_QUEUED)
454+
await commands.executeCommand(RegisteredCliCommands.QUEUE_START)
450455

451-
expect(mockRunExperimentQueue).to.be.calledOnce
452-
expect(mockRunExperimentQueue).to.be.calledWith(dvcDemoPath)
456+
expect(mockQueueStart).to.be.calledOnce
457+
expect(mockQueueStart).to.be.calledWith(dvcDemoPath, dDosNumberOfJobs)
458+
expect(mockInputBox)
453459
})
454460
})
455461

extension/src/util/number.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ export const formatNumber = (value: number): string => {
1010
return automatic
1111
}
1212

13+
export const isValidStringInteger = (
14+
input: string | undefined
15+
): input is string =>
16+
!!input && Number.parseInt(input) === Number.parseFloat(input)
17+
1318
export const createValidInteger = (
1419
input: string | number | undefined
1520
): number | undefined => {
16-
if (!input) {
17-
return
18-
}
19-
2021
if (typeof input === 'number') {
2122
return validateNumericInteger(input)
2223
}
2324

24-
return Number.parseInt(input) === Number.parseFloat(input)
25-
? Number.parseInt(input)
26-
: undefined
25+
return isValidStringInteger(input) ? Number.parseInt(input) : undefined
2726
}

0 commit comments

Comments
 (0)