Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
61bed4c
duplicate transform and set function with new data
mattseddon Apr 11, 2023
e8415a0
duplicate functions out to reader (tests will break)
mattseddon Apr 11, 2023
351e42a
fix all integration tests
mattseddon Apr 12, 2023
2bbe80f
update all remaining test fixtures
mattseddon Apr 13, 2023
6b77df0
fix all test data and deduplicate functions
mattseddon Apr 13, 2023
4be5754
Merge branch 'main' into integrate-exp-show
mattseddon Apr 13, 2023
679c7ce
remove some code climate duplication
mattseddon Apr 13, 2023
336d737
Merge branch 'main' into integrate-exp-show
mattseddon Apr 13, 2023
9c5f59c
wrap all loose test data in generator
mattseddon Apr 14, 2023
b198d11
use breaking change version of dvc
mattseddon Apr 14, 2023
8340d74
fix experiment status in dvc contract
mattseddon Apr 14, 2023
54eedd9
self review
mattseddon Apr 17, 2023
ead10f9
Merge branch 'main' into integrate-exp-show
mattseddon Apr 17, 2023
269840a
Remove checkpoints model and file system watcher (#3684)
mattseddon Apr 17, 2023
ce57701
Merge branch 'main' into integrate-exp-show
mattseddon Apr 17, 2023
a9f5ee5
update demo project
mattseddon Apr 19, 2023
932951b
Merge branch 'main' into integrate-exp-show
mattseddon Apr 19, 2023
5804573
Extend timeout of run experiment test (e2e) (#3713)
mattseddon Apr 19, 2023
ef25c85
Prevent plotting of running experiments (#3712)
mattseddon Apr 19, 2023
8fee434
Merge branch 'main' into integrate-exp-show
mattseddon Apr 19, 2023
6f3fd93
Trigger plot updates whenever commit data changes (#3715)
mattseddon Apr 19, 2023
d275ab0
Merge branch 'main' into integrate-exp-show
mattseddon Apr 19, 2023
cb72502
update demo project and min required version of DVC
mattseddon Apr 20, 2023
ccdfc04
Fix experiment id for commits (shown in plots) (#3724)
mattseddon Apr 20, 2023
b2c2835
Merge branch 'main' into integrate-exp-show
mattseddon Apr 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 73 additions & 5 deletions extension/src/cli/dvc/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export enum ExperimentStatus {
SUCCESS = 'Success'
}

export const EXPERIMENT_WORKSPACE_ID = 'workspace'
export const EXPERIMENT_WORKSPACE_ID = 'workspace' as const

export interface BaseExperimentFields {
name?: string
Expand All @@ -69,13 +69,14 @@ export interface BaseExperimentFields {
type Dep = { hash: null | string; size: null | number; nfiles: null | number }
type Out = Dep & { use_cache: boolean; is_data_source: boolean }

type Outs = RelPathObject<Out>
export type Deps = RelPathObject<Dep>

export interface ExperimentFields extends BaseExperimentFields {
params?: ValueTreeRoot
metrics?: ValueTreeRoot
deps?: Deps
outs?: RelPathObject<Out>
params?: ValueTreeRoot | null
metrics?: ValueTreeRoot | null
deps?: Deps | null
outs?: RelPathObject<Out> | null
error?: ErrorContents
}

Expand All @@ -96,6 +97,73 @@ export interface ExperimentsOutput {
}
}

type ValueTreeOrError_ = { data: ValueTree } | DvcError
type MetricsOrParams = RelPathObject<ValueTreeOrError_>

type ExpStateData = {
rev: string
timestamp: string | null
params: MetricsOrParams | null
metrics: MetricsOrParams | null
deps: Deps | null
outs: Outs | null
meta: { has_checkpoints: boolean }
}

export const ExperimentExecutor = {
DVC_TASK: 'dvc-task',
[EXPERIMENT_WORKSPACE_ID]: EXPERIMENT_WORKSPACE_ID
} as const

export type Executor =
| {
state: ExperimentStatus.QUEUED
name: typeof ExperimentExecutor.DVC_TASK
local: {
root: null
log: null
pid: null
returncode: null
task_id: string
}
}
| {
state:
| ExperimentStatus.RUNNING
| ExperimentStatus.FAILED
| ExperimentStatus.SUCCESS
name: (typeof ExperimentExecutor)[keyof typeof ExperimentExecutor] | null
local: {
root: string
log: string
pid: number
task_id?: string
returncode: null | number
} | null
}
| null

export type ExpWithError = {
rev: string
name?: string
} & DvcError

export type ExpState =
| {
rev: string
name?: string
data: ExpStateData
}
| ExpWithError

export type ExpRange = {
revs: ExpState[]
name?: string
executor: Executor
}

export type ExpShowOutput = (ExpState & { experiments?: ExpRange[] | null })[]

export interface PlotsData {
[path: string]: Plot[]
}
Expand Down
4 changes: 2 additions & 2 deletions extension/src/experiments/columns/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const extractFileMetricsOrParams = (
}

const extractMetricsOrParams = (
valueTreeRoot?: ValueTreeRoot
valueTreeRoot?: ValueTreeRoot | null
): { columns: MetricOrParamColumns; errors: string[] } | undefined => {
if (!valueTreeRoot) {
return
Expand All @@ -46,7 +46,7 @@ const extractMetricsOrParams = (
}

const extractDeps = (
columns?: Deps,
columns?: Deps | null,
commit?: Experiment
): DepColumns | undefined => {
if (!columns) {
Expand Down
210 changes: 207 additions & 3 deletions extension/src/experiments/model/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ import {
ExperimentsCommitOutput,
ExperimentsOutput,
EXPERIMENT_WORKSPACE_ID,
ExperimentStatus
ExperimentStatus,
ExpShowOutput,
ExpState,
ExpWithError,
ExperimentExecutor,
ExpRange,
Executor
} from '../../cli/dvc/contract'
import { addToMapArray } from '../../util/map'
import { RegisteredCommands } from '../../commands/external'
Expand Down Expand Up @@ -274,7 +280,7 @@ const formatCommitMessage = (commit: string) => {
return `${lines[0]}${lines.length > 1 ? ' ...' : ''}`
}

const getCommitMessages = (
const getCommitData = (
commitsOutput: string
): { [sha: string]: CommitData } => {
if (!commitsOutput) {
Expand All @@ -291,7 +297,7 @@ const addDataToCommits = (
commits: Experiment[],
commitsOutput: string
): Experiment[] => {
const commitMessages = getCommitMessages(commitsOutput)
const commitMessages = getCommitData(commitsOutput)
return commits.map(commit => {
const { sha } = commit
if (sha && commitMessages[sha]) {
Expand Down Expand Up @@ -329,6 +335,204 @@ export const collectExperiments = (
return acc
}

const hasError = (expState: ExpState): expState is ExpWithError =>
!!(expState as { error?: unknown }).error

const transformExpState = (experiment: Experiment, expState: ExpState) => {
const { rev } = expState

if (rev.length === 40) {
experiment.sha = rev
}

if (hasError(expState)) {
const error = expState.error.msg
experiment.error = error
return experiment
}

const { data } = expState
if (data) {
transformColumns(experiment, data)
}

return experiment
}

const addCommitData = (
baseline: Experiment,
commitData: { [sha: string]: CommitData } = {}
): void => {
const { sha } = baseline
if (!sha) {
return
}

const commit = commitData[sha]

if (!commit) {
return
}
baseline.displayName = formatCommitMessage(commit.message)
baseline.commit = commit
}

const collectExpState = (
acc: ExperimentsAccumulator,
expState: ExpState,
commitData: { [sha: string]: CommitData }
): string | undefined => {
const { rev, name } = expState
const id = name || rev
const label =
rev === EXPERIMENT_WORKSPACE_ID
? EXPERIMENT_WORKSPACE_ID
: name || shortenForLabel(rev)

const experiment: Experiment = { id, label }

const baseline = transformExpState(experiment, expState)

if (rev === EXPERIMENT_WORKSPACE_ID && !name) {
acc.workspace = baseline
return
}

addCommitData(baseline, commitData)

acc.commits.push(baseline)
return id
}

const getExecutor = (experiment: Experiment): string => {
if ([experiment.executor, experiment.id].includes(EXPERIMENT_WORKSPACE_ID)) {
return EXPERIMENT_WORKSPACE_ID
}
return ExperimentExecutor.DVC_TASK
}

const collectExecutorInfo = (
acc: ExperimentsAccumulator,
experiment: Experiment,
executor: Executor
): void => {
if (!executor) {
return
}

const { name, state } = executor

if (name && state === ExperimentStatus.RUNNING) {
experiment.executor = name
}
if (state && state !== ExperimentStatus.SUCCESS) {
experiment.status = state
}

if (experiment.status === ExperimentStatus.RUNNING) {
acc.runningExperiments.push({
executor: getExecutor(experiment),
id: experiment.id
})
}
}

const collectExpRange = (
acc: ExperimentsAccumulator,
baselineId: string,
expRange: ExpRange
): void => {
const { revs, executor } = expRange
if (!revs?.length) {
return
}
const expState = revs[0]

const { name, rev } = expState

const experiment = transformExpState(
{
id: name || rev,
label:
rev === EXPERIMENT_WORKSPACE_ID
? EXPERIMENT_WORKSPACE_ID
: shortenForLabel(rev)
},
expState
)

if (name) {
const displayName = `[${name}]`
experiment.displayName = displayName
experiment.logicalGroupName = displayName
}

collectExecutorInfo(acc, experiment, executor)

addToMapArray(acc.experimentsByCommit, baselineId, experiment)
}

const setWorkspaceAsRunning = (
acc: ExperimentsAccumulator,
dvcLiveOnly: boolean
) => {
if (dvcLiveOnly) {
acc.workspace.executor = EXPERIMENT_WORKSPACE_ID
acc.workspace.status = ExperimentStatus.RUNNING
acc.runningExperiments.unshift({
executor: EXPERIMENT_WORKSPACE_ID,
id: EXPERIMENT_WORKSPACE_ID
})
}

if (
acc.runningExperiments.some(
({ executor, id }) =>
executor === ExperimentExecutor[EXPERIMENT_WORKSPACE_ID] &&
id !== EXPERIMENT_WORKSPACE_ID
)
) {
acc.workspace.executor = EXPERIMENT_WORKSPACE_ID
acc.workspace.status = ExperimentStatus.RUNNING
acc.runningExperiments.unshift({
Copy link
Contributor Author

@mattseddon mattseddon Apr 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[I] Should be able to get rid of this (runningExperiments) altogether too (follow-up).

executor: EXPERIMENT_WORKSPACE_ID,
id: EXPERIMENT_WORKSPACE_ID
})
}
}

export const collectExperiments_ = (
output: ExpShowOutput,
dvcLiveOnly: boolean,
commitsOutput: string
): ExperimentsAccumulator => {
const acc: ExperimentsAccumulator = {
commits: [],
experimentsByCommit: new Map(),
runningExperiments: [],
workspace: { id: EXPERIMENT_WORKSPACE_ID, label: EXPERIMENT_WORKSPACE_ID }
}

const commitData = getCommitData(commitsOutput)

for (const expState of output) {
const baselineId = collectExpState(acc, expState, commitData)
const { experiments } = expState

if (!(baselineId && experiments?.length)) {
continue
}

for (const expRange of experiments) {
collectExpRange(acc, baselineId, expRange)
}
}

setWorkspaceAsRunning(acc, dvcLiveOnly)

return acc
}

type DeletableExperimentAccumulator = { [dvcRoot: string]: Set<string> }

const initializeAccumulatorRoot = (
Expand Down
8 changes: 8 additions & 0 deletions extension/src/experiments/model/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { join } from 'path'
import { commands } from 'vscode'
import { ExperimentsModel } from '.'
import outputFixture from '../../test/fixtures/expShow/base/output'
import outputFixture_ from '../../test/fixtures/expShow/base/output_'
import rowsFixture from '../../test/fixtures/expShow/base/rows'
import rowsFixture_ from '../../test/fixtures/expShow/base/rows_'
import deeplyNestedRowsFixture from '../../test/fixtures/expShow/deeplyNested/rows'
import deeplyNestedOutputFixture from '../../test/fixtures/expShow/deeplyNested/output'
import uncommittedDepsFixture from '../../test/fixtures/expShow/uncommittedDeps/output'
Expand Down Expand Up @@ -61,6 +63,12 @@ describe('ExperimentsModel', () => {
expect(model.getRowData()).toStrictEqual(rowsFixture)
})

it('should return the expected rows when given the output fixture_', () => {
const model = new ExperimentsModel('', buildMockMemento())
model.transformAndSet_(outputFixture_, false, '')
expect(model.getRowData()).toStrictEqual(rowsFixture_)
})

it('should return the expected rows when given the survival fixture', () => {
const model = new ExperimentsModel('', buildMockMemento())
model.transformAndSet(survivalOutputFixture, false, '')
Expand Down
Loading