@sdeverywhere/check-core 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1104 -442
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +536 -108
- package/dist/index.d.ts +536 -108
- package/dist/index.js +1092 -437
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -38,33 +38,178 @@ var __async = (__this, __arguments, generator) => {
|
|
|
38
38
|
});
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
// src/bundle/impl-vars-codec.ts
|
|
42
|
+
function encodeImplVars(input) {
|
|
43
|
+
const subscripts = [];
|
|
44
|
+
const variables = [];
|
|
45
|
+
const varTypes = [];
|
|
46
|
+
const varInstances = {};
|
|
47
|
+
const subscriptMap = /* @__PURE__ */ new Map();
|
|
48
|
+
const variableMap = /* @__PURE__ */ new Map();
|
|
49
|
+
const varTypeMap = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const [groupKey, implVars] of Object.entries(input)) {
|
|
51
|
+
const instances = [];
|
|
52
|
+
for (const implVar of implVars) {
|
|
53
|
+
const varIdInfo = parseSubscripts(implVar.varId);
|
|
54
|
+
const varNameInfo = parseSubscripts(implVar.varName);
|
|
55
|
+
let varTypeIndex = varTypeMap.get(implVar.varType);
|
|
56
|
+
if (varTypeIndex === void 0) {
|
|
57
|
+
varTypeIndex = varTypes.length;
|
|
58
|
+
varTypes.push(implVar.varType);
|
|
59
|
+
varTypeMap.set(implVar.varType, varTypeIndex);
|
|
60
|
+
}
|
|
61
|
+
let variableIndex = variableMap.get(implVar.varIndex);
|
|
62
|
+
if (variableIndex === void 0) {
|
|
63
|
+
variableIndex = variables.length;
|
|
64
|
+
variables.push({
|
|
65
|
+
n: varNameInfo.base,
|
|
66
|
+
i: varIdInfo.base,
|
|
67
|
+
x: implVar.varIndex
|
|
68
|
+
});
|
|
69
|
+
variableMap.set(implVar.varIndex, variableIndex);
|
|
70
|
+
}
|
|
71
|
+
let subscriptIndices;
|
|
72
|
+
let subscriptValues;
|
|
73
|
+
if (varIdInfo.subscripts.length > 0) {
|
|
74
|
+
subscriptIndices = [];
|
|
75
|
+
subscriptValues = implVar.subscriptIndices || [];
|
|
76
|
+
for (let i = 0; i < varIdInfo.subscripts.length; i++) {
|
|
77
|
+
const subscriptId = varIdInfo.subscripts[i];
|
|
78
|
+
const subscriptName = varNameInfo.subscripts[i];
|
|
79
|
+
let subscriptIndex = subscriptMap.get(subscriptId);
|
|
80
|
+
if (subscriptIndex === void 0) {
|
|
81
|
+
subscriptIndex = subscripts.length;
|
|
82
|
+
subscripts.push({
|
|
83
|
+
n: subscriptName,
|
|
84
|
+
i: subscriptId
|
|
85
|
+
});
|
|
86
|
+
subscriptMap.set(subscriptId, subscriptIndex);
|
|
87
|
+
}
|
|
88
|
+
subscriptIndices.push(subscriptIndex);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const instance = [varTypeIndex, variableIndex];
|
|
92
|
+
if (subscriptIndices) {
|
|
93
|
+
instance.push(...subscriptIndices, ...subscriptValues);
|
|
94
|
+
}
|
|
95
|
+
instances.push(instance);
|
|
96
|
+
}
|
|
97
|
+
varInstances[groupKey] = instances;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
subscripts,
|
|
101
|
+
variables,
|
|
102
|
+
varTypes,
|
|
103
|
+
varInstances
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function decodeImplVars(encoded) {
|
|
107
|
+
const result = {};
|
|
108
|
+
for (const [groupKey, instances] of Object.entries(encoded.varInstances)) {
|
|
109
|
+
const implVars = [];
|
|
110
|
+
for (const instance of instances) {
|
|
111
|
+
const varType = encoded.varTypes[instance[0]];
|
|
112
|
+
const variable = encoded.variables[instance[1]];
|
|
113
|
+
let varId = variable.i;
|
|
114
|
+
let varName = variable.n;
|
|
115
|
+
if (instance.length > 2) {
|
|
116
|
+
const subscriptIds = [];
|
|
117
|
+
const subscriptNames = [];
|
|
118
|
+
const subscriptCount = (instance.length - 2) / 2;
|
|
119
|
+
const subscriptIndices = instance.slice(2, 2 + subscriptCount);
|
|
120
|
+
for (const subscriptIndex of subscriptIndices) {
|
|
121
|
+
const subscript = encoded.subscripts[subscriptIndex];
|
|
122
|
+
subscriptIds.push(subscript.i);
|
|
123
|
+
subscriptNames.push(subscript.n);
|
|
124
|
+
}
|
|
125
|
+
varId += `[${subscriptIds.join(",")}]`;
|
|
126
|
+
varName += `[${subscriptNames.join(",")}]`;
|
|
127
|
+
}
|
|
128
|
+
const implVar = {
|
|
129
|
+
varId,
|
|
130
|
+
varName,
|
|
131
|
+
varType,
|
|
132
|
+
varIndex: variable.x,
|
|
133
|
+
subscriptIndices: instance.length > 2 ? instance.slice(2 + (instance.length - 2) / 2) : void 0
|
|
134
|
+
};
|
|
135
|
+
implVars.push(implVar);
|
|
136
|
+
}
|
|
137
|
+
result[groupKey] = implVars;
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
function parseSubscripts(text) {
|
|
142
|
+
const bracketIndex = text.indexOf("[");
|
|
143
|
+
if (bracketIndex === -1) {
|
|
144
|
+
return { base: text, subscripts: [] };
|
|
145
|
+
}
|
|
146
|
+
const base = text.substring(0, bracketIndex);
|
|
147
|
+
const subscriptText = text.substring(bracketIndex + 1, text.lastIndexOf("]"));
|
|
148
|
+
const subscripts = subscriptText.split(",").map((s) => s.trim());
|
|
149
|
+
return { base, subscripts };
|
|
150
|
+
}
|
|
151
|
+
|
|
41
152
|
// src/_shared/task-queue.ts
|
|
42
|
-
var TaskQueue = class {
|
|
43
|
-
|
|
44
|
-
|
|
153
|
+
var TaskQueue = class _TaskQueue {
|
|
154
|
+
/**
|
|
155
|
+
* @param executors The map of available task executors.
|
|
156
|
+
*/
|
|
157
|
+
constructor(executors) {
|
|
158
|
+
this.executors = executors;
|
|
45
159
|
/** The queue of task keys, most recent at front. */
|
|
46
160
|
this.taskKeyQueue = [];
|
|
47
161
|
/** The map of tasks. */
|
|
48
162
|
this.taskMap = /* @__PURE__ */ new Map();
|
|
163
|
+
// /** The set of keys for the executors that are currently processing tasks. */
|
|
164
|
+
// private readonly activeExecutorKeys: Set<TaskExecutorKey> = new Set()
|
|
165
|
+
/** The idle event listeners. */
|
|
166
|
+
this.idleListeners = [];
|
|
49
167
|
/** Whether tasks are being processed. */
|
|
50
168
|
this.processing = false;
|
|
51
169
|
/** Whether `shutdown` has been called. */
|
|
52
170
|
this.stopped = false;
|
|
53
171
|
}
|
|
54
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Initialize the shared `TaskQueue` instance.
|
|
174
|
+
*
|
|
175
|
+
* @param executors The map of available task executors.
|
|
176
|
+
*/
|
|
177
|
+
static initialize(executors) {
|
|
178
|
+
if (executors.size === 0) {
|
|
179
|
+
throw new Error("Must provide at least one executor");
|
|
180
|
+
}
|
|
181
|
+
this.instance = new _TaskQueue(executors);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get the shared `TaskQueue` instance.
|
|
185
|
+
*/
|
|
186
|
+
static getInstance() {
|
|
187
|
+
if (!this.instance) {
|
|
188
|
+
throw new Error("TaskQueue not initialized; must call `initialize` first");
|
|
189
|
+
}
|
|
190
|
+
return this.instance;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Add a task to the queue.
|
|
194
|
+
*
|
|
195
|
+
* @param task The task to add.
|
|
196
|
+
*/
|
|
197
|
+
addTask(task) {
|
|
55
198
|
if (this.stopped) {
|
|
56
199
|
return;
|
|
57
200
|
}
|
|
58
|
-
if (this.taskMap.has(key)) {
|
|
59
|
-
throw new Error(`Task already added for key ${key}`);
|
|
201
|
+
if (this.taskMap.has(task.key)) {
|
|
202
|
+
throw new Error(`Task already added for key ${task.key}`);
|
|
60
203
|
}
|
|
61
|
-
this.taskKeyQueue.push(key);
|
|
62
|
-
this.taskMap.set(key,
|
|
63
|
-
input,
|
|
64
|
-
onComplete
|
|
65
|
-
});
|
|
204
|
+
this.taskKeyQueue.push(task.key);
|
|
205
|
+
this.taskMap.set(task.key, task);
|
|
66
206
|
this.processTasksIfNeeded();
|
|
67
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Cancel a task.
|
|
210
|
+
*
|
|
211
|
+
* @param taskKey The key of the task to cancel.
|
|
212
|
+
*/
|
|
68
213
|
cancelTask(taskKey) {
|
|
69
214
|
const index = this.taskKeyQueue.indexOf(taskKey);
|
|
70
215
|
if (index >= 0) {
|
|
@@ -72,9 +217,37 @@ var TaskQueue = class {
|
|
|
72
217
|
}
|
|
73
218
|
this.taskMap.delete(taskKey);
|
|
74
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Add an idle listener.
|
|
222
|
+
*
|
|
223
|
+
* @param listener The listener to add.
|
|
224
|
+
*/
|
|
225
|
+
onIdle(listener) {
|
|
226
|
+
this.idleListeners.push(listener);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Remove an idle listener.
|
|
230
|
+
*
|
|
231
|
+
* @param listener The listener to remove.
|
|
232
|
+
*/
|
|
233
|
+
removeIdleListener(listener) {
|
|
234
|
+
this.idleListeners.splice(this.idleListeners.indexOf(listener), 1);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Notify the idle listeners.
|
|
238
|
+
*
|
|
239
|
+
* @param error The error to notify the listeners with.
|
|
240
|
+
*/
|
|
241
|
+
notifyIdle(error) {
|
|
242
|
+
for (const listener of this.idleListeners) {
|
|
243
|
+
listener(error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Shutdown the task queue, cancelling all pending tasks.
|
|
248
|
+
*/
|
|
75
249
|
shutdown() {
|
|
76
250
|
this.stopped = true;
|
|
77
|
-
this.processing = false;
|
|
78
251
|
this.taskKeyQueue.length = 0;
|
|
79
252
|
this.taskMap.clear();
|
|
80
253
|
}
|
|
@@ -82,75 +255,98 @@ var TaskQueue = class {
|
|
|
82
255
|
if (!this.stopped && !this.processing) {
|
|
83
256
|
this.processing = true;
|
|
84
257
|
setTimeout(() => {
|
|
85
|
-
this.
|
|
258
|
+
this.processNextTasks();
|
|
86
259
|
});
|
|
87
260
|
}
|
|
88
261
|
}
|
|
89
|
-
|
|
262
|
+
processNextTasks() {
|
|
90
263
|
return __async(this, null, function* () {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
264
|
+
const taskKeys = this.taskKeyQueue.splice(0, this.executors.size);
|
|
265
|
+
if (taskKeys.length === 0) {
|
|
266
|
+
this.processing = false;
|
|
267
|
+
if (!this.stopped) {
|
|
268
|
+
this.notifyIdle();
|
|
269
|
+
}
|
|
94
270
|
return;
|
|
95
271
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
272
|
+
const executeCalls = [];
|
|
273
|
+
const availableExecutorKeys = Array.from(this.executors.keys());
|
|
274
|
+
for (const taskKey of taskKeys) {
|
|
275
|
+
const task = this.taskMap.get(taskKey);
|
|
276
|
+
if (!task) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
98
279
|
this.taskMap.delete(taskKey);
|
|
99
|
-
|
|
100
|
-
|
|
280
|
+
const executorKey = availableExecutorKeys.shift();
|
|
281
|
+
const executor = this.executors.get(executorKey);
|
|
282
|
+
if (!executor) {
|
|
283
|
+
throw new Error(`No executor found for key ${executorKey}`);
|
|
284
|
+
}
|
|
285
|
+
executeCalls.push(executor.execute(task));
|
|
101
286
|
}
|
|
102
|
-
let output;
|
|
103
287
|
try {
|
|
104
|
-
|
|
288
|
+
yield Promise.all(executeCalls);
|
|
105
289
|
} catch (e) {
|
|
106
290
|
if (!this.stopped) {
|
|
107
291
|
this.shutdown();
|
|
108
|
-
|
|
292
|
+
this.notifyIdle(e);
|
|
109
293
|
}
|
|
110
294
|
return;
|
|
111
295
|
}
|
|
112
|
-
task.onComplete(output);
|
|
113
296
|
if (this.taskKeyQueue.length > 0) {
|
|
114
297
|
setTimeout(() => {
|
|
115
|
-
this.
|
|
298
|
+
this.processNextTasks();
|
|
116
299
|
});
|
|
117
300
|
} else {
|
|
118
301
|
this.processing = false;
|
|
119
302
|
if (!this.stopped) {
|
|
120
|
-
|
|
303
|
+
this.notifyIdle();
|
|
121
304
|
}
|
|
122
305
|
}
|
|
123
306
|
});
|
|
124
307
|
}
|
|
125
308
|
};
|
|
309
|
+
function createExecutor(bundleModelL, bundleModelR) {
|
|
310
|
+
return {
|
|
311
|
+
execute: (task) => __async(null, null, function* () {
|
|
312
|
+
return task.process({
|
|
313
|
+
L: bundleModelL,
|
|
314
|
+
R: bundleModelR
|
|
315
|
+
});
|
|
316
|
+
})
|
|
317
|
+
};
|
|
318
|
+
}
|
|
126
319
|
|
|
127
320
|
// src/check/check-data-coordinator.ts
|
|
128
321
|
var CheckDataCoordinator = class {
|
|
129
|
-
constructor(
|
|
130
|
-
this.
|
|
131
|
-
this.taskQueue = new TaskQueue({
|
|
132
|
-
process: (request) => __async(this, null, function* () {
|
|
133
|
-
const result = yield this.bundleModel.getDatasetsForScenario(request.scenarioSpec, [request.datasetKey]);
|
|
134
|
-
const dataset = result.datasetMap.get(request.datasetKey);
|
|
135
|
-
return {
|
|
136
|
-
dataset
|
|
137
|
-
};
|
|
138
|
-
})
|
|
139
|
-
});
|
|
322
|
+
constructor(taskQueue) {
|
|
323
|
+
this.taskQueue = taskQueue;
|
|
140
324
|
}
|
|
141
325
|
requestDataset(requestKey, scenarioSpec, datasetKey, onResponse) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
326
|
+
const task = {
|
|
327
|
+
key: requestKey,
|
|
328
|
+
kind: "check-data-coordinator",
|
|
329
|
+
process: (bundleModels) => __async(null, null, function* () {
|
|
330
|
+
const bundleModelR = bundleModels.R;
|
|
331
|
+
const result = yield bundleModelR.getDatasetsForScenario(scenarioSpec, [datasetKey]);
|
|
332
|
+
const dataset = result.datasetMap.get(datasetKey);
|
|
333
|
+
onResponse(dataset);
|
|
334
|
+
})
|
|
145
335
|
};
|
|
146
|
-
this.taskQueue.addTask(
|
|
147
|
-
onResponse(response.dataset);
|
|
148
|
-
});
|
|
336
|
+
this.taskQueue.addTask(task);
|
|
149
337
|
}
|
|
150
338
|
cancelRequest(key) {
|
|
151
339
|
this.taskQueue.cancelTask(key);
|
|
152
340
|
}
|
|
153
341
|
};
|
|
342
|
+
function createCheckDataCoordinator() {
|
|
343
|
+
return new CheckDataCoordinator(TaskQueue.getInstance());
|
|
344
|
+
}
|
|
345
|
+
function createCheckDataCoordinatorForTests(bundleModel) {
|
|
346
|
+
const executor = createExecutor(void 0, bundleModel);
|
|
347
|
+
const taskQueue = new TaskQueue(/* @__PURE__ */ new Map([["test-executor-0", executor]]));
|
|
348
|
+
return new CheckDataCoordinator(taskQueue);
|
|
349
|
+
}
|
|
154
350
|
|
|
155
351
|
// src/check/check-report.ts
|
|
156
352
|
import assertNever2 from "assert-never";
|
|
@@ -212,6 +408,10 @@ function buildCheckReport(checkPlan, checkResults) {
|
|
|
212
408
|
testStatus = "failed";
|
|
213
409
|
scenarioStatus = "failed";
|
|
214
410
|
datasetStatus = "failed";
|
|
411
|
+
} else if (checkResult.status === "skipped" && testStatus === "passed") {
|
|
412
|
+
testStatus = "skipped";
|
|
413
|
+
scenarioStatus = "skipped";
|
|
414
|
+
datasetStatus = "skipped";
|
|
215
415
|
}
|
|
216
416
|
}
|
|
217
417
|
predicateReports.push(predicateReport(predicatePlan, checkKey, checkResult));
|
|
@@ -1147,16 +1347,6 @@ function actionForPredicate(predicateSpec) {
|
|
|
1147
1347
|
};
|
|
1148
1348
|
}
|
|
1149
1349
|
|
|
1150
|
-
// src/_shared/combo.ts
|
|
1151
|
-
function cartesianProductOf(arr) {
|
|
1152
|
-
return arr.reduce(
|
|
1153
|
-
(a, b) => {
|
|
1154
|
-
return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
|
|
1155
|
-
},
|
|
1156
|
-
[[]]
|
|
1157
|
-
);
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
1350
|
// src/check/check-dataset.ts
|
|
1161
1351
|
function expandDatasets(modelSpec, datasetSpec) {
|
|
1162
1352
|
var _a;
|
|
@@ -1185,25 +1375,10 @@ function expandDatasets(modelSpec, datasetSpec) {
|
|
|
1185
1375
|
name: match.outputVar.varName
|
|
1186
1376
|
});
|
|
1187
1377
|
} else if (match.implVar) {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
const subscriptCombos = cartesianProductOf(subscripts);
|
|
1193
|
-
for (const subscriptCombo of subscriptCombos) {
|
|
1194
|
-
const subIdParts = subscriptCombo.map((sub) => `[${sub.id}]`).join("");
|
|
1195
|
-
const subNameParts = subscriptCombo.map((sub) => sub.name).join(",");
|
|
1196
|
-
checkDatasets.push({
|
|
1197
|
-
datasetKey: `${baseDatasetKey}${subIdParts}`,
|
|
1198
|
-
name: `${implVar.varName}[${subNameParts}]`
|
|
1199
|
-
});
|
|
1200
|
-
}
|
|
1201
|
-
} else {
|
|
1202
|
-
checkDatasets.push({
|
|
1203
|
-
datasetKey: match.datasetKey,
|
|
1204
|
-
name: implVar.varName
|
|
1205
|
-
});
|
|
1206
|
-
}
|
|
1378
|
+
checkDatasets.push({
|
|
1379
|
+
datasetKey: match.datasetKey,
|
|
1380
|
+
name: match.implVar.varName
|
|
1381
|
+
});
|
|
1207
1382
|
}
|
|
1208
1383
|
}
|
|
1209
1384
|
return checkDatasets;
|
|
@@ -1611,12 +1786,18 @@ var CheckPlanner = class {
|
|
|
1611
1786
|
this.dataRefs = /* @__PURE__ */ new Map();
|
|
1612
1787
|
this.checkKey = 1;
|
|
1613
1788
|
}
|
|
1614
|
-
addAllChecks(checkSpec,
|
|
1789
|
+
addAllChecks(checkSpec, skipChecks) {
|
|
1790
|
+
function skipCheckKey(groupName, testName) {
|
|
1791
|
+
return `${groupName.toLowerCase()} :: ${testName.toLowerCase()}`;
|
|
1792
|
+
}
|
|
1793
|
+
const skipChecksSet = new Set(skipChecks.map((check) => skipCheckKey(check.groupName, check.testName)));
|
|
1615
1794
|
for (const groupSpec of checkSpec.groups) {
|
|
1616
1795
|
const groupName = groupSpec.describe;
|
|
1617
1796
|
const planTests = [];
|
|
1618
1797
|
for (const testSpec of groupSpec.tests) {
|
|
1619
1798
|
const testName = testSpec.it;
|
|
1799
|
+
const shouldSkip = skipChecksSet.has(skipCheckKey(groupName, testName));
|
|
1800
|
+
const simplifyScenarios = false;
|
|
1620
1801
|
const checkScenarios = expandScenarios(this.modelSpec, testSpec.scenarios || [], simplifyScenarios);
|
|
1621
1802
|
const checkDatasets = [];
|
|
1622
1803
|
for (const datasetSpec of testSpec.datasets) {
|
|
@@ -1657,7 +1838,8 @@ var CheckPlanner = class {
|
|
|
1657
1838
|
scenario: checkScenario,
|
|
1658
1839
|
dataset: checkDataset,
|
|
1659
1840
|
action: checkAction,
|
|
1660
|
-
dataRefs
|
|
1841
|
+
dataRefs,
|
|
1842
|
+
skip: shouldSkip
|
|
1661
1843
|
});
|
|
1662
1844
|
}
|
|
1663
1845
|
planDatasets.push({
|
|
@@ -1794,6 +1976,7 @@ function checkSummaryFromReport(checkReport) {
|
|
|
1794
1976
|
break;
|
|
1795
1977
|
case "failed":
|
|
1796
1978
|
case "error":
|
|
1979
|
+
case "skipped":
|
|
1797
1980
|
predicateSummaries.push({
|
|
1798
1981
|
checkKey: predicate.checkKey,
|
|
1799
1982
|
result: predicate.result
|
|
@@ -1811,14 +1994,14 @@ function checkSummaryFromReport(checkReport) {
|
|
|
1811
1994
|
predicateSummaries
|
|
1812
1995
|
};
|
|
1813
1996
|
}
|
|
1814
|
-
function checkReportFromSummary(checkConfig, checkSummary) {
|
|
1997
|
+
function checkReportFromSummary(checkConfig, checkSummary, skipChecks = []) {
|
|
1815
1998
|
const checkSpecResult = parseTestYaml(checkConfig.tests);
|
|
1816
1999
|
if (checkSpecResult.isErr()) {
|
|
1817
2000
|
return void 0;
|
|
1818
2001
|
}
|
|
1819
2002
|
const checkSpec = checkSpecResult.value;
|
|
1820
|
-
const checkPlanner = new CheckPlanner(checkConfig.bundle.
|
|
1821
|
-
checkPlanner.addAllChecks(checkSpec,
|
|
2003
|
+
const checkPlanner = new CheckPlanner(checkConfig.bundle.modelSpec);
|
|
2004
|
+
checkPlanner.addAllChecks(checkSpec, skipChecks);
|
|
1822
2005
|
const checkPlan = checkPlanner.buildPlan();
|
|
1823
2006
|
const checkResults = /* @__PURE__ */ new Map();
|
|
1824
2007
|
for (const predicateSummary of checkSummary.predicateSummaries) {
|
|
@@ -1828,98 +2011,116 @@ function checkReportFromSummary(checkConfig, checkSummary) {
|
|
|
1828
2011
|
}
|
|
1829
2012
|
|
|
1830
2013
|
// src/comparison/run/comparison-data-coordinator.ts
|
|
1831
|
-
import { assertNever as assertNever7 } from "assert-never";
|
|
1832
2014
|
var ComparisonDataCoordinator = class {
|
|
1833
|
-
constructor(
|
|
1834
|
-
this.
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2015
|
+
constructor(taskQueue) {
|
|
2016
|
+
this.taskQueue = taskQueue;
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Request datasets from the two models.
|
|
2020
|
+
*
|
|
2021
|
+
* @param requestKey The unique key for the request.
|
|
2022
|
+
* @param sourceL The source of the first ("left") dataset. If "left", the datasets will
|
|
2023
|
+
* be fetched from the "left" bundle's model, otherwise they will be fetched from the
|
|
2024
|
+
* "right" bundle's model.
|
|
2025
|
+
* @param scenarioSpecL The scenario used for the first ("left") model of the comparison.
|
|
2026
|
+
* @param sourceR The source of the second ("right") dataset. If "left", the datasets
|
|
2027
|
+
* will be fetched from the "left" bundle's model, otherwise they will be fetched from
|
|
2028
|
+
* the "right" bundle's model.
|
|
2029
|
+
* @param scenarioSpecR The scenario used for the second ("right") model of the comparison.
|
|
2030
|
+
* @param graphId The keys of the datasets to be fetched.
|
|
2031
|
+
* @param onResponse The callback that will be called with the dataset maps.
|
|
2032
|
+
*/
|
|
2033
|
+
requestDatasetMaps(requestKey, sourceL, scenarioSpecL, sourceR, scenarioSpecR, datasetKeys, onResponse) {
|
|
2034
|
+
function fetchDatasets(bundleModel, scenarioSpec) {
|
|
2035
|
+
return __async(this, null, function* () {
|
|
2036
|
+
if (scenarioSpec) {
|
|
2037
|
+
return bundleModel.getDatasetsForScenario(scenarioSpec, datasetKeys);
|
|
2038
|
+
} else {
|
|
2039
|
+
return void 0;
|
|
2040
|
+
}
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
const task = {
|
|
2044
|
+
key: requestKey,
|
|
2045
|
+
kind: "comparison-data-coordinator",
|
|
2046
|
+
process: (bundleModels) => __async(null, null, function* () {
|
|
2047
|
+
const modelL = sourceL === "left" ? bundleModels.L : bundleModels.R;
|
|
2048
|
+
const modelR = sourceR === "left" ? bundleModels.L : bundleModels.R;
|
|
2049
|
+
let resultL;
|
|
2050
|
+
let resultR;
|
|
2051
|
+
if (modelL === modelR) {
|
|
2052
|
+
resultL = yield fetchDatasets(modelL, scenarioSpecL);
|
|
2053
|
+
resultR = yield fetchDatasets(modelR, scenarioSpecR);
|
|
2054
|
+
} else {
|
|
2055
|
+
const results = yield Promise.all([
|
|
2056
|
+
fetchDatasets(modelL, scenarioSpecL),
|
|
2057
|
+
fetchDatasets(modelR, scenarioSpecR)
|
|
2058
|
+
]);
|
|
2059
|
+
resultL = results[0];
|
|
2060
|
+
resultR = results[1];
|
|
1845
2061
|
}
|
|
2062
|
+
onResponse(resultL == null ? void 0 : resultL.datasetMap, resultR == null ? void 0 : resultR.datasetMap);
|
|
1846
2063
|
})
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
1849
|
-
processDatasetRequest(request) {
|
|
1850
|
-
return __async(this, null, function* () {
|
|
1851
|
-
function fetchDatasets(bundleModel, scenarioSpec) {
|
|
1852
|
-
return __async(this, null, function* () {
|
|
1853
|
-
if (scenarioSpec) {
|
|
1854
|
-
return bundleModel.getDatasetsForScenario(scenarioSpec, request.datasetKeys);
|
|
1855
|
-
} else {
|
|
1856
|
-
return void 0;
|
|
1857
|
-
}
|
|
1858
|
-
});
|
|
1859
|
-
}
|
|
1860
|
-
const [resultL, resultR] = yield Promise.all([
|
|
1861
|
-
fetchDatasets(this.bundleModelL, request.scenarioSpecL),
|
|
1862
|
-
fetchDatasets(this.bundleModelR, request.scenarioSpecR)
|
|
1863
|
-
]);
|
|
1864
|
-
return {
|
|
1865
|
-
kind: "dataset",
|
|
1866
|
-
datasetMapL: resultL == null ? void 0 : resultL.datasetMap,
|
|
1867
|
-
datasetMapR: resultR == null ? void 0 : resultR.datasetMap
|
|
1868
|
-
};
|
|
1869
|
-
});
|
|
1870
|
-
}
|
|
1871
|
-
processGraphDataRequest(request) {
|
|
1872
|
-
return __async(this, null, function* () {
|
|
1873
|
-
function fetchGraphData(bundleModel, scenarioSpec) {
|
|
1874
|
-
return __async(this, null, function* () {
|
|
1875
|
-
if (scenarioSpec) {
|
|
1876
|
-
return bundleModel.getGraphDataForScenario(scenarioSpec, request.graphId);
|
|
1877
|
-
} else {
|
|
1878
|
-
return void 0;
|
|
1879
|
-
}
|
|
1880
|
-
});
|
|
1881
|
-
}
|
|
1882
|
-
const [graphDataL, graphDataR] = yield Promise.all([
|
|
1883
|
-
fetchGraphData(this.bundleModelL, request.scenarioSpecL),
|
|
1884
|
-
fetchGraphData(this.bundleModelR, request.scenarioSpecR)
|
|
1885
|
-
]);
|
|
1886
|
-
return {
|
|
1887
|
-
kind: "graph-data",
|
|
1888
|
-
graphDataL,
|
|
1889
|
-
graphDataR
|
|
1890
|
-
};
|
|
1891
|
-
});
|
|
1892
|
-
}
|
|
1893
|
-
requestDatasetMaps(requestKey, scenarioSpecL, scenarioSpecR, datasetKeys, onResponse) {
|
|
1894
|
-
const request = {
|
|
1895
|
-
kind: "dataset",
|
|
1896
|
-
scenarioSpecL,
|
|
1897
|
-
scenarioSpecR,
|
|
1898
|
-
datasetKeys
|
|
1899
2064
|
};
|
|
1900
|
-
this.taskQueue.addTask(
|
|
1901
|
-
if (response.kind === "dataset") {
|
|
1902
|
-
onResponse(response.datasetMapL, response.datasetMapR);
|
|
1903
|
-
}
|
|
1904
|
-
});
|
|
2065
|
+
this.taskQueue.addTask(task);
|
|
1905
2066
|
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2067
|
+
/**
|
|
2068
|
+
* Request graph data from the two models.
|
|
2069
|
+
*
|
|
2070
|
+
* @param requestKey The unique key for the request.
|
|
2071
|
+
* @param sourceL The source of the first ("left") dataset. If "left", the datasets will
|
|
2072
|
+
* be fetched from the "left" bundle's model, otherwise they will be fetched from the
|
|
2073
|
+
* "right" bundle's model.
|
|
2074
|
+
* @param scenarioSpecL The scenario used for the first ("left") model of the comparison.
|
|
2075
|
+
* @param sourceR The source of the second ("right") dataset. If "left", the datasets
|
|
2076
|
+
* will be fetched from the "left" bundle's model, otherwise they will be fetched from
|
|
2077
|
+
* the "right" bundle's model.
|
|
2078
|
+
* @param scenarioSpecR The scenario used for the second ("right") model of the comparison.
|
|
2079
|
+
* @param graphId The ID of the graph for which data will be fetched.
|
|
2080
|
+
* @param onResponse The callback that will be called with the graph data.
|
|
2081
|
+
*/
|
|
2082
|
+
requestGraphData(requestKey, sourceL, scenarioSpecL, sourceR, scenarioSpecR, graphId, onResponse) {
|
|
2083
|
+
function fetchGraphData(bundleModel, scenarioSpec) {
|
|
2084
|
+
return __async(this, null, function* () {
|
|
2085
|
+
var _a;
|
|
2086
|
+
if (scenarioSpec) {
|
|
2087
|
+
return (_a = bundleModel.getGraphDataForScenario) == null ? void 0 : _a.call(bundleModel, scenarioSpec, graphId);
|
|
2088
|
+
} else {
|
|
2089
|
+
return void 0;
|
|
2090
|
+
}
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
const task = {
|
|
2094
|
+
key: requestKey,
|
|
2095
|
+
kind: "comparison-data-coordinator",
|
|
2096
|
+
process: (bundleModels) => __async(null, null, function* () {
|
|
2097
|
+
const modelL = sourceL === "left" ? bundleModels.L : bundleModels.R;
|
|
2098
|
+
const modelR = sourceR === "left" ? bundleModels.L : bundleModels.R;
|
|
2099
|
+
let graphDataL;
|
|
2100
|
+
let graphDataR;
|
|
2101
|
+
if (modelL === modelR) {
|
|
2102
|
+
graphDataL = yield fetchGraphData(modelL, scenarioSpecL);
|
|
2103
|
+
graphDataR = yield fetchGraphData(modelR, scenarioSpecR);
|
|
2104
|
+
} else {
|
|
2105
|
+
const results = yield Promise.all([
|
|
2106
|
+
fetchGraphData(modelL, scenarioSpecL),
|
|
2107
|
+
fetchGraphData(modelR, scenarioSpecR)
|
|
2108
|
+
]);
|
|
2109
|
+
graphDataL = results[0];
|
|
2110
|
+
graphDataR = results[1];
|
|
2111
|
+
}
|
|
2112
|
+
onResponse(graphDataL, graphDataR);
|
|
2113
|
+
})
|
|
1912
2114
|
};
|
|
1913
|
-
this.taskQueue.addTask(
|
|
1914
|
-
if (response.kind === "graph-data") {
|
|
1915
|
-
onResponse(response.graphDataL, response.graphDataR);
|
|
1916
|
-
}
|
|
1917
|
-
});
|
|
2115
|
+
this.taskQueue.addTask(task);
|
|
1918
2116
|
}
|
|
1919
2117
|
cancelRequest(key) {
|
|
1920
2118
|
this.taskQueue.cancelTask(key);
|
|
1921
2119
|
}
|
|
1922
2120
|
};
|
|
2121
|
+
function createComparisonDataCoordinator() {
|
|
2122
|
+
return new ComparisonDataCoordinator(TaskQueue.getInstance());
|
|
2123
|
+
}
|
|
1923
2124
|
|
|
1924
2125
|
// src/comparison/diff-datasets/diff-datasets.ts
|
|
1925
2126
|
function diffDatasets(datasetL, datasetR) {
|
|
@@ -2069,14 +2270,14 @@ function diffGraphs(graphL, graphR, scenarioKey, testSummaries) {
|
|
|
2069
2270
|
|
|
2070
2271
|
// src/comparison/report/comparison-reporting.ts
|
|
2071
2272
|
function comparisonSummaryFromReport(comparisonReport) {
|
|
2273
|
+
var _a, _b;
|
|
2072
2274
|
const terseSummaries = [];
|
|
2073
2275
|
for (const r of comparisonReport.testReports) {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
});
|
|
2276
|
+
const baselineMaxDiff = (_a = r.baselineDiffReport) == null ? void 0 : _a.maxDiff;
|
|
2277
|
+
const baselineAvgDiff = (_b = r.baselineDiffReport) == null ? void 0 : _b.avgDiff;
|
|
2278
|
+
const summary = testSummaryFromReport(r, baselineMaxDiff, baselineAvgDiff);
|
|
2279
|
+
if (summary) {
|
|
2280
|
+
terseSummaries.push(summary);
|
|
2080
2281
|
}
|
|
2081
2282
|
}
|
|
2082
2283
|
return {
|
|
@@ -2085,6 +2286,43 @@ function comparisonSummaryFromReport(comparisonReport) {
|
|
|
2085
2286
|
perfReportR: comparisonReport.perfReportR
|
|
2086
2287
|
};
|
|
2087
2288
|
}
|
|
2289
|
+
function testSummaryFromReport(r, baselineMaxDiff, baselineAvgDiff) {
|
|
2290
|
+
var _a;
|
|
2291
|
+
function baselineRelativeDiff(diffValue, baselineDiffValue) {
|
|
2292
|
+
if (baselineDiffValue !== void 0) {
|
|
2293
|
+
const epsilon = 1e-6;
|
|
2294
|
+
if (baselineDiffValue === 0) {
|
|
2295
|
+
baselineDiffValue = epsilon;
|
|
2296
|
+
}
|
|
2297
|
+
return diffValue / baselineDiffValue;
|
|
2298
|
+
} else {
|
|
2299
|
+
if (diffValue === 0) {
|
|
2300
|
+
return 0;
|
|
2301
|
+
} else {
|
|
2302
|
+
return 1;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
if (r.diffReport === void 0) {
|
|
2307
|
+
return {
|
|
2308
|
+
s: r.scenarioKey,
|
|
2309
|
+
d: r.datasetKey
|
|
2310
|
+
};
|
|
2311
|
+
} else if (((_a = r.diffReport) == null ? void 0 : _a.validity) === "both" && r.diffReport.maxDiff > 0) {
|
|
2312
|
+
const maxDiffRelativeToBaseline = baselineRelativeDiff(r.diffReport.maxDiff, baselineMaxDiff);
|
|
2313
|
+
const avgDiffRelativeToBaseline = baselineRelativeDiff(r.diffReport.avgDiff, baselineAvgDiff);
|
|
2314
|
+
return {
|
|
2315
|
+
s: r.scenarioKey,
|
|
2316
|
+
d: r.datasetKey,
|
|
2317
|
+
md: r.diffReport.maxDiff,
|
|
2318
|
+
ad: r.diffReport.avgDiff,
|
|
2319
|
+
mdb: maxDiffRelativeToBaseline,
|
|
2320
|
+
adb: avgDiffRelativeToBaseline
|
|
2321
|
+
};
|
|
2322
|
+
} else {
|
|
2323
|
+
return void 0;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2088
2326
|
function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
|
|
2089
2327
|
const existingSummaries = /* @__PURE__ */ new Map();
|
|
2090
2328
|
for (const summary of terseSummaries) {
|
|
@@ -2097,24 +2335,33 @@ function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
|
|
|
2097
2335
|
for (const datasetKey of datasetKeys) {
|
|
2098
2336
|
const key = `${scenario.key}::${datasetKey}`;
|
|
2099
2337
|
const existingSummary = existingSummaries.get(key);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2338
|
+
if (existingSummary) {
|
|
2339
|
+
allTestSummaries.push(existingSummary);
|
|
2340
|
+
} else {
|
|
2341
|
+
allTestSummaries.push({
|
|
2342
|
+
s: scenario.key,
|
|
2343
|
+
d: datasetKey,
|
|
2344
|
+
md: 0,
|
|
2345
|
+
ad: 0,
|
|
2346
|
+
mdb: 0,
|
|
2347
|
+
adb: 0
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2106
2350
|
}
|
|
2107
2351
|
}
|
|
2108
2352
|
return allTestSummaries;
|
|
2109
2353
|
}
|
|
2110
2354
|
|
|
2111
2355
|
// src/comparison/report/buckets.ts
|
|
2112
|
-
function getBucketIndex(
|
|
2113
|
-
if (
|
|
2356
|
+
function getBucketIndex(diff, thresholds) {
|
|
2357
|
+
if (diff === void 0) {
|
|
2358
|
+
return thresholds.length + 2;
|
|
2359
|
+
}
|
|
2360
|
+
if (diff === 0) {
|
|
2114
2361
|
return 0;
|
|
2115
2362
|
}
|
|
2116
2363
|
for (let i = 0; i < thresholds.length; i++) {
|
|
2117
|
-
if (
|
|
2364
|
+
if (diff < thresholds[i]) {
|
|
2118
2365
|
return i + 1;
|
|
2119
2366
|
}
|
|
2120
2367
|
}
|
|
@@ -2122,14 +2369,32 @@ function getBucketIndex(diffPct, thresholds) {
|
|
|
2122
2369
|
}
|
|
2123
2370
|
|
|
2124
2371
|
// src/comparison/report/comparison-group-scores.ts
|
|
2125
|
-
function getScoresForTestSummaries(testSummaries, thresholds) {
|
|
2126
|
-
const diffCountByBucket = Array(thresholds.length +
|
|
2127
|
-
const
|
|
2372
|
+
function getScoresForTestSummaries(testSummaries, thresholds, sortMode) {
|
|
2373
|
+
const diffCountByBucket = Array(thresholds.length + 3).fill(0);
|
|
2374
|
+
const totalDiffByBucket = Array(thresholds.length + 3).fill(0);
|
|
2128
2375
|
let totalDiffCount = 0;
|
|
2376
|
+
let valueKey;
|
|
2377
|
+
switch (sortMode) {
|
|
2378
|
+
case "max-diff":
|
|
2379
|
+
valueKey = "md";
|
|
2380
|
+
break;
|
|
2381
|
+
case "avg-diff":
|
|
2382
|
+
valueKey = "ad";
|
|
2383
|
+
break;
|
|
2384
|
+
case "max-diff-relative":
|
|
2385
|
+
valueKey = "mdb";
|
|
2386
|
+
break;
|
|
2387
|
+
case "avg-diff-relative":
|
|
2388
|
+
valueKey = "adb";
|
|
2389
|
+
break;
|
|
2390
|
+
}
|
|
2129
2391
|
for (const testSummary of testSummaries) {
|
|
2130
|
-
const
|
|
2392
|
+
const value = testSummary[valueKey];
|
|
2393
|
+
const bucketIndex = getBucketIndex(value, thresholds);
|
|
2131
2394
|
diffCountByBucket[bucketIndex]++;
|
|
2132
|
-
|
|
2395
|
+
if (value !== void 0) {
|
|
2396
|
+
totalDiffByBucket[bucketIndex] += value;
|
|
2397
|
+
}
|
|
2133
2398
|
totalDiffCount++;
|
|
2134
2399
|
}
|
|
2135
2400
|
let diffPercentByBucket;
|
|
@@ -2140,20 +2405,20 @@ function getScoresForTestSummaries(testSummaries, thresholds) {
|
|
|
2140
2405
|
}
|
|
2141
2406
|
return {
|
|
2142
2407
|
totalDiffCount,
|
|
2143
|
-
|
|
2408
|
+
totalDiffByBucket,
|
|
2144
2409
|
diffCountByBucket,
|
|
2145
2410
|
diffPercentByBucket
|
|
2146
2411
|
};
|
|
2147
2412
|
}
|
|
2148
2413
|
|
|
2149
2414
|
// src/comparison/report/comparison-grouping.ts
|
|
2150
|
-
import { assertNever as
|
|
2151
|
-
function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
|
|
2415
|
+
import { assertNever as assertNever7 } from "assert-never";
|
|
2416
|
+
function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries, sortMode) {
|
|
2152
2417
|
const allTestSummaries = restoreFromTerseSummaries(comparisonConfig, terseSummaries);
|
|
2153
2418
|
const groupsByScenario = groupComparisonTestSummaries(allTestSummaries, "by-scenario");
|
|
2154
|
-
const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()]);
|
|
2419
|
+
const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()], sortMode);
|
|
2155
2420
|
const groupsByDataset = groupComparisonTestSummaries(allTestSummaries, "by-dataset");
|
|
2156
|
-
const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()]);
|
|
2421
|
+
const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()], sortMode);
|
|
2157
2422
|
return {
|
|
2158
2423
|
allTestSummaries,
|
|
2159
2424
|
byScenario,
|
|
@@ -2172,7 +2437,7 @@ function groupComparisonTestSummaries(testSummaries, groupKind) {
|
|
|
2172
2437
|
groupKey = testSummary.s;
|
|
2173
2438
|
break;
|
|
2174
2439
|
default:
|
|
2175
|
-
|
|
2440
|
+
assertNever7(groupKind);
|
|
2176
2441
|
}
|
|
2177
2442
|
const group = groups.get(groupKey);
|
|
2178
2443
|
if (group) {
|
|
@@ -2187,7 +2452,7 @@ function groupComparisonTestSummaries(testSummaries, groupKind) {
|
|
|
2187
2452
|
}
|
|
2188
2453
|
return groups;
|
|
2189
2454
|
}
|
|
2190
|
-
function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
2455
|
+
function categorizeComparisonGroups(comparisonConfig, allGroups, sortMode) {
|
|
2191
2456
|
const allGroupSummaries = /* @__PURE__ */ new Map();
|
|
2192
2457
|
const withErrors = [];
|
|
2193
2458
|
const onlyInLeft = [];
|
|
@@ -2197,7 +2462,9 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2197
2462
|
function addSummaryForGroup(group, root, validInL, validInR) {
|
|
2198
2463
|
let scores;
|
|
2199
2464
|
if (validInL && validInR) {
|
|
2200
|
-
|
|
2465
|
+
const isRelativeMode = sortMode === "max-diff-relative" || sortMode === "avg-diff-relative";
|
|
2466
|
+
const thresholds = isRelativeMode ? comparisonConfig.ratioThresholds : comparisonConfig.thresholds;
|
|
2467
|
+
scores = getScoresForTestSummaries(group.testSummaries, thresholds, sortMode);
|
|
2201
2468
|
}
|
|
2202
2469
|
const groupSummary = {
|
|
2203
2470
|
root,
|
|
@@ -2206,7 +2473,9 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2206
2473
|
};
|
|
2207
2474
|
allGroupSummaries.set(group.key, groupSummary);
|
|
2208
2475
|
if (validInL && validInR) {
|
|
2209
|
-
|
|
2476
|
+
const noDiffCount = scores.diffCountByBucket[0];
|
|
2477
|
+
const skippedCount = scores.diffCountByBucket[5];
|
|
2478
|
+
if (scores.totalDiffCount !== noDiffCount + skippedCount) {
|
|
2210
2479
|
withDiffs.push(groupSummary);
|
|
2211
2480
|
} else {
|
|
2212
2481
|
withoutDiffs.push(groupSummary);
|
|
@@ -2236,7 +2505,7 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2236
2505
|
break;
|
|
2237
2506
|
}
|
|
2238
2507
|
default:
|
|
2239
|
-
|
|
2508
|
+
assertNever7(group.kind);
|
|
2240
2509
|
}
|
|
2241
2510
|
}
|
|
2242
2511
|
if (withDiffs.length > 1) {
|
|
@@ -2298,13 +2567,13 @@ function sortScenarioGroupSummaries(summaries) {
|
|
|
2298
2567
|
});
|
|
2299
2568
|
}
|
|
2300
2569
|
function compareScores(a, b) {
|
|
2301
|
-
if (a.
|
|
2570
|
+
if (a.totalDiffByBucket.length !== b.totalDiffByBucket.length) {
|
|
2302
2571
|
return 0;
|
|
2303
2572
|
}
|
|
2304
|
-
const len = a.
|
|
2573
|
+
const len = a.totalDiffByBucket.length;
|
|
2305
2574
|
for (let i = len - 1; i >= 0; i--) {
|
|
2306
|
-
const aTotal = a.
|
|
2307
|
-
const bTotal = b.
|
|
2575
|
+
const aTotal = a.totalDiffByBucket[i];
|
|
2576
|
+
const bTotal = b.totalDiffByBucket[i];
|
|
2308
2577
|
if (aTotal > bTotal) {
|
|
2309
2578
|
return 1;
|
|
2310
2579
|
} else if (aTotal < bTotal) {
|
|
@@ -2316,7 +2585,7 @@ function compareScores(a, b) {
|
|
|
2316
2585
|
|
|
2317
2586
|
// src/comparison/config/parse/comparison-parser.ts
|
|
2318
2587
|
import Ajv2 from "ajv";
|
|
2319
|
-
import
|
|
2588
|
+
import assertNever8 from "assert-never";
|
|
2320
2589
|
import { err as err2, ok as ok2 } from "neverthrow";
|
|
2321
2590
|
import yaml2 from "yaml";
|
|
2322
2591
|
|
|
@@ -2852,7 +3121,7 @@ function parseComparisonSpecs(specSource) {
|
|
|
2852
3121
|
parsed = yaml2.parse(specSource.content);
|
|
2853
3122
|
break;
|
|
2854
3123
|
default:
|
|
2855
|
-
|
|
3124
|
+
assertNever8(specSource.kind);
|
|
2856
3125
|
}
|
|
2857
3126
|
if (validate(parsed)) {
|
|
2858
3127
|
for (const specItem of parsed) {
|
|
@@ -3079,7 +3348,7 @@ function viewGroupSpecFromParsed(parsedViewGroup) {
|
|
|
3079
3348
|
}
|
|
3080
3349
|
|
|
3081
3350
|
// src/comparison/config/resolve/comparison-resolver.ts
|
|
3082
|
-
import { assertNever as
|
|
3351
|
+
import { assertNever as assertNever10 } from "assert-never";
|
|
3083
3352
|
|
|
3084
3353
|
// src/bundle/model-inputs.ts
|
|
3085
3354
|
var ModelInputs = class {
|
|
@@ -3142,7 +3411,7 @@ var ModelInputs = class {
|
|
|
3142
3411
|
};
|
|
3143
3412
|
|
|
3144
3413
|
// src/comparison/config/resolve/comparison-scenario-specs.ts
|
|
3145
|
-
import { assertNever as
|
|
3414
|
+
import { assertNever as assertNever9 } from "assert-never";
|
|
3146
3415
|
function scenarioSpecsFromSettings(settings) {
|
|
3147
3416
|
switch (settings.kind) {
|
|
3148
3417
|
case "all-inputs-settings": {
|
|
@@ -3155,7 +3424,7 @@ function scenarioSpecsFromSettings(settings) {
|
|
|
3155
3424
|
return [specL, specR];
|
|
3156
3425
|
}
|
|
3157
3426
|
default:
|
|
3158
|
-
|
|
3427
|
+
assertNever9(settings);
|
|
3159
3428
|
}
|
|
3160
3429
|
}
|
|
3161
3430
|
function scenarioSpecFromInputs(inputs, side) {
|
|
@@ -3374,7 +3643,7 @@ function resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genK
|
|
|
3374
3643
|
];
|
|
3375
3644
|
}
|
|
3376
3645
|
default:
|
|
3377
|
-
|
|
3646
|
+
assertNever10(scenarioSpec);
|
|
3378
3647
|
}
|
|
3379
3648
|
}
|
|
3380
3649
|
function resolveScenarioMatrix(modelInputsL, modelInputsR, genKey) {
|
|
@@ -3430,7 +3699,7 @@ function resolveScenarioForInputSpecs(modelInputsL, modelInputsR, key, id, title
|
|
|
3430
3699
|
case "input-at-value":
|
|
3431
3700
|
return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.value);
|
|
3432
3701
|
default:
|
|
3433
|
-
|
|
3702
|
+
assertNever10(inputSpec);
|
|
3434
3703
|
}
|
|
3435
3704
|
});
|
|
3436
3705
|
const settings = {
|
|
@@ -3463,7 +3732,7 @@ function resolveScenarioForDistinctInputSpecs(modelInputsL, modelInputsR, key, i
|
|
|
3463
3732
|
inputState = resolveInputForNameInModel(modelInputs, inputSpec.inputName, inputSpec.value);
|
|
3464
3733
|
break;
|
|
3465
3734
|
default:
|
|
3466
|
-
|
|
3735
|
+
assertNever10(inputSpec);
|
|
3467
3736
|
}
|
|
3468
3737
|
if (inputState.error !== void 0) {
|
|
3469
3738
|
inputsWithErrors.push({
|
|
@@ -3679,7 +3948,7 @@ function inputValueAtPosition2(inputVar, position) {
|
|
|
3679
3948
|
case "at-maximum":
|
|
3680
3949
|
return inputVar.maxValue;
|
|
3681
3950
|
default:
|
|
3682
|
-
|
|
3951
|
+
assertNever10(position);
|
|
3683
3952
|
}
|
|
3684
3953
|
}
|
|
3685
3954
|
var ResolvedScenarioGroups = class {
|
|
@@ -3738,7 +4007,7 @@ function resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, grap
|
|
|
3738
4007
|
return [...graphIds];
|
|
3739
4008
|
}
|
|
3740
4009
|
default:
|
|
3741
|
-
|
|
4010
|
+
assertNever10(graphsSpec.preset);
|
|
3742
4011
|
}
|
|
3743
4012
|
}
|
|
3744
4013
|
// eslint-disable-next-line no-fallthrough
|
|
@@ -3752,7 +4021,7 @@ function resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, grap
|
|
|
3752
4021
|
return groupSpec.graphIds;
|
|
3753
4022
|
}
|
|
3754
4023
|
default:
|
|
3755
|
-
|
|
4024
|
+
assertNever10(graphsSpec);
|
|
3756
4025
|
}
|
|
3757
4026
|
}
|
|
3758
4027
|
function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphIds, graphOrder) {
|
|
@@ -3926,7 +4195,7 @@ function resolveViewGroupFromSpec(modelSpecL, modelSpecR, modelOutputs, resolved
|
|
|
3926
4195
|
views.push(resolveViewForScenario(void 0, void 0, scenario, graphIds, graphOrder));
|
|
3927
4196
|
break;
|
|
3928
4197
|
default:
|
|
3929
|
-
|
|
4198
|
+
assertNever10(scenario);
|
|
3930
4199
|
}
|
|
3931
4200
|
}
|
|
3932
4201
|
} else {
|
|
@@ -3935,13 +4204,13 @@ function resolveViewGroupFromSpec(modelSpecL, modelSpecR, modelOutputs, resolved
|
|
|
3935
4204
|
break;
|
|
3936
4205
|
}
|
|
3937
4206
|
default:
|
|
3938
|
-
|
|
4207
|
+
assertNever10(refSpec);
|
|
3939
4208
|
}
|
|
3940
4209
|
}
|
|
3941
4210
|
break;
|
|
3942
4211
|
}
|
|
3943
4212
|
default:
|
|
3944
|
-
|
|
4213
|
+
assertNever10(viewGroupSpec);
|
|
3945
4214
|
}
|
|
3946
4215
|
return {
|
|
3947
4216
|
kind: "view-group",
|
|
@@ -4004,9 +4273,9 @@ var ComparisonDatasetsImpl = class {
|
|
|
4004
4273
|
}
|
|
4005
4274
|
const allOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
4006
4275
|
const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
4007
|
-
function addOutputVars(outputVars,
|
|
4276
|
+
function addOutputVars(outputVars, handleRenames2) {
|
|
4008
4277
|
outputVars.forEach((outputVar, key) => {
|
|
4009
|
-
const remappedKey =
|
|
4278
|
+
const remappedKey = handleRenames2 ? leftKeyForRightKey(key) : key;
|
|
4010
4279
|
allOutputVarKeysSet.add(remappedKey);
|
|
4011
4280
|
if (outputVar.sourceName === void 0) {
|
|
4012
4281
|
modelOutputVarKeysSet.add(remappedKey);
|
|
@@ -4120,109 +4389,41 @@ var ComparisonScenariosImpl = class {
|
|
|
4120
4389
|
}
|
|
4121
4390
|
};
|
|
4122
4391
|
|
|
4123
|
-
// src/config/synchronized-model.ts
|
|
4124
|
-
function synchronizedBundleModel(sourceModel) {
|
|
4125
|
-
const promiseQueue = new PromiseQueue();
|
|
4126
|
-
return {
|
|
4127
|
-
modelSpec: sourceModel.modelSpec,
|
|
4128
|
-
getDatasetsForScenario: (scenarioSpec, datasetKeys) => {
|
|
4129
|
-
return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenarioSpec, datasetKeys));
|
|
4130
|
-
},
|
|
4131
|
-
getGraphDataForScenario: (scenarioSpec, graphId) => {
|
|
4132
|
-
return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenarioSpec, graphId));
|
|
4133
|
-
},
|
|
4134
|
-
getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
|
|
4135
|
-
};
|
|
4136
|
-
}
|
|
4137
|
-
var PromiseQueue = class {
|
|
4138
|
-
constructor() {
|
|
4139
|
-
this.tasks = [];
|
|
4140
|
-
this.runningCount = 0;
|
|
4141
|
-
}
|
|
4142
|
-
add(f) {
|
|
4143
|
-
return new Promise((resolve, reject) => {
|
|
4144
|
-
const run = () => __async(this, null, function* () {
|
|
4145
|
-
this.runningCount++;
|
|
4146
|
-
const promise = f();
|
|
4147
|
-
try {
|
|
4148
|
-
const result = yield promise;
|
|
4149
|
-
resolve(result);
|
|
4150
|
-
} catch (e) {
|
|
4151
|
-
reject(e);
|
|
4152
|
-
} finally {
|
|
4153
|
-
this.runningCount--;
|
|
4154
|
-
this.runNext();
|
|
4155
|
-
}
|
|
4156
|
-
});
|
|
4157
|
-
if (this.runningCount < 1) {
|
|
4158
|
-
run();
|
|
4159
|
-
} else {
|
|
4160
|
-
this.tasks.push(run);
|
|
4161
|
-
}
|
|
4162
|
-
});
|
|
4163
|
-
}
|
|
4164
|
-
runNext() {
|
|
4165
|
-
if (this.tasks.length > 0) {
|
|
4166
|
-
const task = this.tasks.shift();
|
|
4167
|
-
if (task) {
|
|
4168
|
-
task();
|
|
4169
|
-
}
|
|
4170
|
-
}
|
|
4171
|
-
}
|
|
4172
|
-
};
|
|
4173
|
-
|
|
4174
4392
|
// src/config/config.ts
|
|
4175
4393
|
function createConfig(options) {
|
|
4176
4394
|
return __async(this, null, function* () {
|
|
4177
|
-
var _a;
|
|
4178
|
-
|
|
4395
|
+
var _a, _b, _c, _d, _e;
|
|
4396
|
+
let concurrentModels;
|
|
4397
|
+
if (options.concurrency === void 0) {
|
|
4398
|
+
concurrentModels = 1;
|
|
4399
|
+
} else if (options.concurrency === 0) {
|
|
4400
|
+
let coreCount;
|
|
4401
|
+
if (typeof navigator !== "undefined") {
|
|
4402
|
+
coreCount = navigator.hardwareConcurrency;
|
|
4403
|
+
}
|
|
4404
|
+
if (coreCount === void 0 || coreCount < 1) {
|
|
4405
|
+
coreCount = 1;
|
|
4406
|
+
}
|
|
4407
|
+
concurrentModels = Math.max(1, Math.floor(coreCount / 2));
|
|
4408
|
+
} else {
|
|
4409
|
+
concurrentModels = Math.max(1, options.concurrency);
|
|
4410
|
+
}
|
|
4411
|
+
const origCurrentBundle = yield loadBundle(options.current, concurrentModels);
|
|
4179
4412
|
let currentBundle;
|
|
4180
4413
|
let comparisonConfig;
|
|
4181
4414
|
if (options.comparison === void 0) {
|
|
4182
4415
|
currentBundle = origCurrentBundle;
|
|
4183
4416
|
} else {
|
|
4184
|
-
const baselineBundle = yield
|
|
4185
|
-
|
|
4186
|
-
const
|
|
4187
|
-
|
|
4188
|
-
invertedRenamedKeys.set(newKey, oldKey);
|
|
4189
|
-
});
|
|
4190
|
-
const rightKeyForLeftKey = (leftKey) => {
|
|
4191
|
-
return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
|
|
4192
|
-
};
|
|
4193
|
-
const leftKeyForRightKey = (rightKey) => {
|
|
4194
|
-
return invertedRenamedKeys.get(rightKey) || rightKey;
|
|
4195
|
-
};
|
|
4196
|
-
const origBundleModelR = origCurrentBundle.model;
|
|
4197
|
-
const adjBundleModelR = {
|
|
4198
|
-
modelSpec: origBundleModelR.modelSpec,
|
|
4199
|
-
getDatasetsForScenario: (scenarioSpec, datasetKeys) => __async(this, null, function* () {
|
|
4200
|
-
const rightKeys = datasetKeys.map(rightKeyForLeftKey);
|
|
4201
|
-
const result = yield origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
|
|
4202
|
-
const mapWithRightKeys = result.datasetMap;
|
|
4203
|
-
const mapWithLeftKeys = /* @__PURE__ */ new Map();
|
|
4204
|
-
for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
|
|
4205
|
-
const leftKey = leftKeyForRightKey(rightKey);
|
|
4206
|
-
mapWithLeftKeys.set(leftKey, dataset);
|
|
4207
|
-
}
|
|
4208
|
-
return {
|
|
4209
|
-
datasetMap: mapWithLeftKeys,
|
|
4210
|
-
modelRunTime: result.modelRunTime
|
|
4211
|
-
};
|
|
4212
|
-
}),
|
|
4213
|
-
getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
|
|
4214
|
-
getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
|
|
4215
|
-
};
|
|
4216
|
-
currentBundle = __spreadProps(__spreadValues({}, origCurrentBundle), {
|
|
4217
|
-
model: adjBundleModelR
|
|
4218
|
-
});
|
|
4219
|
-
const modelSpecL = baselineBundle.model.modelSpec;
|
|
4220
|
-
const modelSpecR = currentBundle.model.modelSpec;
|
|
4417
|
+
const baselineBundle = yield loadBundle(options.comparison.baseline, concurrentModels);
|
|
4418
|
+
currentBundle = handleRenames(origCurrentBundle, (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys);
|
|
4419
|
+
const modelSpecL = baselineBundle.modelSpec;
|
|
4420
|
+
const modelSpecR = currentBundle.modelSpec;
|
|
4221
4421
|
const comparisonDefs = resolveComparisonSpecsFromSources(modelSpecL, modelSpecR, options.comparison.specs);
|
|
4222
4422
|
comparisonConfig = {
|
|
4223
4423
|
bundleL: baselineBundle,
|
|
4224
4424
|
bundleR: currentBundle,
|
|
4225
|
-
thresholds: options.comparison.thresholds,
|
|
4425
|
+
thresholds: (_b = options.comparison.thresholds) != null ? _b : [1, 5, 10],
|
|
4426
|
+
ratioThresholds: (_c = options.comparison.ratioThresholds) != null ? _c : [1, 2, 3],
|
|
4226
4427
|
scenarios: getComparisonScenarios(comparisonDefs.scenarios),
|
|
4227
4428
|
datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
|
|
4228
4429
|
viewGroups: comparisonDefs.viewGroups,
|
|
@@ -4233,26 +4434,77 @@ function createConfig(options) {
|
|
|
4233
4434
|
bundle: currentBundle,
|
|
4234
4435
|
tests: options.check.tests
|
|
4235
4436
|
};
|
|
4437
|
+
const executors = /* @__PURE__ */ new Map();
|
|
4438
|
+
for (let i = 0; i < checkConfig.bundle.models.length; i++) {
|
|
4439
|
+
const bundleModelL = (_d = comparisonConfig == null ? void 0 : comparisonConfig.bundleL.models) == null ? void 0 : _d[i];
|
|
4440
|
+
const bundleModelR = ((_e = comparisonConfig == null ? void 0 : comparisonConfig.bundleR.models) == null ? void 0 : _e[i]) || checkConfig.bundle.models[i];
|
|
4441
|
+
const executor = createExecutor(bundleModelL, bundleModelR);
|
|
4442
|
+
executors.set(`executor-${i}`, executor);
|
|
4443
|
+
}
|
|
4444
|
+
TaskQueue.initialize(executors);
|
|
4236
4445
|
return {
|
|
4237
4446
|
check: checkConfig,
|
|
4238
4447
|
comparison: comparisonConfig
|
|
4239
4448
|
};
|
|
4240
4449
|
});
|
|
4241
4450
|
}
|
|
4242
|
-
function
|
|
4451
|
+
function loadBundle(bundle, concurrentModels) {
|
|
4243
4452
|
return __async(this, null, function* () {
|
|
4244
|
-
const
|
|
4245
|
-
const
|
|
4453
|
+
const initCalls = Array.from({ length: concurrentModels }, () => bundle.bundle.initModel());
|
|
4454
|
+
const models = yield Promise.all(initCalls);
|
|
4246
4455
|
return {
|
|
4247
|
-
name:
|
|
4248
|
-
version:
|
|
4249
|
-
|
|
4456
|
+
name: bundle.name,
|
|
4457
|
+
version: bundle.bundle.version,
|
|
4458
|
+
modelSpec: bundle.bundle.modelSpec,
|
|
4459
|
+
models
|
|
4460
|
+
};
|
|
4461
|
+
});
|
|
4462
|
+
}
|
|
4463
|
+
function handleRenames(origCurrentBundle, renamedDatasetKeys) {
|
|
4464
|
+
if (renamedDatasetKeys === void 0 || renamedDatasetKeys.size === 0) {
|
|
4465
|
+
return origCurrentBundle;
|
|
4466
|
+
}
|
|
4467
|
+
const invertedRenamedKeys = /* @__PURE__ */ new Map();
|
|
4468
|
+
renamedDatasetKeys.forEach((newKey, oldKey) => {
|
|
4469
|
+
invertedRenamedKeys.set(newKey, oldKey);
|
|
4470
|
+
});
|
|
4471
|
+
const rightKeyForLeftKey = (leftKey) => {
|
|
4472
|
+
return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
|
|
4473
|
+
};
|
|
4474
|
+
const leftKeyForRightKey = (rightKey) => {
|
|
4475
|
+
return invertedRenamedKeys.get(rightKey) || rightKey;
|
|
4476
|
+
};
|
|
4477
|
+
function wrapModel(origBundleModelR) {
|
|
4478
|
+
var _a, _b, _c;
|
|
4479
|
+
return {
|
|
4480
|
+
modelSpec: origBundleModelR.modelSpec,
|
|
4481
|
+
getDatasetsForScenario: (scenarioSpec, datasetKeys) => __async(null, null, function* () {
|
|
4482
|
+
const rightKeys = datasetKeys.map(rightKeyForLeftKey);
|
|
4483
|
+
const result = yield origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
|
|
4484
|
+
const mapWithRightKeys = result.datasetMap;
|
|
4485
|
+
const mapWithLeftKeys = /* @__PURE__ */ new Map();
|
|
4486
|
+
for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
|
|
4487
|
+
const leftKey = leftKeyForRightKey(rightKey);
|
|
4488
|
+
mapWithLeftKeys.set(leftKey, dataset);
|
|
4489
|
+
}
|
|
4490
|
+
return {
|
|
4491
|
+
datasetMap: mapWithLeftKeys,
|
|
4492
|
+
modelRunTime: result.modelRunTime
|
|
4493
|
+
};
|
|
4494
|
+
}),
|
|
4495
|
+
getGraphDataForScenario: (_a = origBundleModelR.getGraphDataForScenario) == null ? void 0 : _a.bind(origBundleModelR),
|
|
4496
|
+
getGraphLinksForScenario: (_b = origBundleModelR.getGraphLinksForScenario) == null ? void 0 : _b.bind(origBundleModelR),
|
|
4497
|
+
createGraphView: (_c = origBundleModelR.createGraphView) == null ? void 0 : _c.bind(origBundleModelR)
|
|
4250
4498
|
};
|
|
4499
|
+
}
|
|
4500
|
+
const wrappedModels = origCurrentBundle.models.map(wrapModel);
|
|
4501
|
+
return __spreadProps(__spreadValues({}, origCurrentBundle), {
|
|
4502
|
+
models: wrappedModels
|
|
4251
4503
|
});
|
|
4252
4504
|
}
|
|
4253
4505
|
|
|
4254
4506
|
// src/perf/perf-runner.ts
|
|
4255
|
-
import { assertNever as
|
|
4507
|
+
import { assertNever as assertNever11 } from "assert-never";
|
|
4256
4508
|
|
|
4257
4509
|
// src/perf/perf-stats.ts
|
|
4258
4510
|
var PerfStats = class {
|
|
@@ -4289,80 +4541,110 @@ var PerfStats = class {
|
|
|
4289
4541
|
};
|
|
4290
4542
|
|
|
4291
4543
|
// src/perf/perf-runner.ts
|
|
4292
|
-
|
|
4293
|
-
|
|
4544
|
+
function runPerfWithTaskQueue(taskQueue, callbacks, options) {
|
|
4545
|
+
const perfRunner = new PerfRunner(taskQueue, callbacks, options);
|
|
4546
|
+
perfRunner.start();
|
|
4547
|
+
return () => {
|
|
4548
|
+
perfRunner.cancel();
|
|
4549
|
+
};
|
|
4550
|
+
}
|
|
4551
|
+
function runPerf(callbacks, options) {
|
|
4552
|
+
const taskQueue = TaskQueue.getInstance();
|
|
4553
|
+
return runPerfWithTaskQueue(taskQueue, callbacks, options);
|
|
4554
|
+
}
|
|
4294
4555
|
var PerfRunner = class {
|
|
4295
|
-
constructor(
|
|
4296
|
-
this.
|
|
4297
|
-
this.
|
|
4298
|
-
this.
|
|
4299
|
-
|
|
4300
|
-
this.
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
case "right": {
|
|
4310
|
-
const result = yield bundleModelR.getDatasetsForScenario(scenarioSpec, []);
|
|
4311
|
-
return {
|
|
4312
|
-
runTimeR: result.modelRunTime
|
|
4313
|
-
};
|
|
4314
|
-
}
|
|
4315
|
-
case "both": {
|
|
4316
|
-
const [resultL, resultR] = yield Promise.all([
|
|
4317
|
-
bundleModelL.getDatasetsForScenario(scenarioSpec, []),
|
|
4318
|
-
bundleModelR.getDatasetsForScenario(scenarioSpec, [])
|
|
4319
|
-
]);
|
|
4320
|
-
return {
|
|
4321
|
-
runTimeL: resultL.modelRunTime,
|
|
4322
|
-
runTimeR: resultR.modelRunTime
|
|
4323
|
-
};
|
|
4324
|
-
}
|
|
4325
|
-
default:
|
|
4326
|
-
assertNever12(request.kind);
|
|
4327
|
-
}
|
|
4328
|
-
})
|
|
4329
|
-
});
|
|
4556
|
+
constructor(taskQueue, callbacks, options) {
|
|
4557
|
+
this.taskQueue = taskQueue;
|
|
4558
|
+
this.callbacks = callbacks;
|
|
4559
|
+
this.options = options;
|
|
4560
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4561
|
+
this.stopped = false;
|
|
4562
|
+
}
|
|
4563
|
+
cancel() {
|
|
4564
|
+
if (!this.stopped) {
|
|
4565
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
4566
|
+
this.taskQueue.cancelTask(taskKey);
|
|
4567
|
+
}
|
|
4568
|
+
this.stopped = true;
|
|
4569
|
+
}
|
|
4330
4570
|
}
|
|
4331
4571
|
start() {
|
|
4572
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4332
4573
|
const statsL = new PerfStats();
|
|
4333
4574
|
const statsR = new PerfStats();
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
const taskQueue = this.taskQueue;
|
|
4343
|
-
function addTask(index, warmup, kind) {
|
|
4344
|
-
const key = `${warmup ? "warmup-" : ""}${kind}-${index}`;
|
|
4345
|
-
const request = {
|
|
4346
|
-
kind
|
|
4347
|
-
};
|
|
4348
|
-
taskQueue.addTask(key, request, (response) => {
|
|
4349
|
-
if (!warmup && response.runTimeL !== void 0) {
|
|
4350
|
-
statsL.addRun(response.runTimeL);
|
|
4351
|
-
}
|
|
4352
|
-
if (!warmup && response.runTimeR !== void 0) {
|
|
4353
|
-
statsR.addRun(response.runTimeR);
|
|
4354
|
-
}
|
|
4355
|
-
});
|
|
4575
|
+
const scenarioSpec = allInputsAtPositionSpec("at-default");
|
|
4576
|
+
const warmupCount = (_b = (_a = this.options) == null ? void 0 : _a.warmupCount) != null ? _b : 5;
|
|
4577
|
+
const runCount = (_d = (_c = this.options) == null ? void 0 : _c.runCount) != null ? _d : 100;
|
|
4578
|
+
let totalTasks = 0;
|
|
4579
|
+
if (((_e = this.options) == null ? void 0 : _e.mode) === "parallel") {
|
|
4580
|
+
totalTasks = warmupCount + runCount;
|
|
4581
|
+
} else {
|
|
4582
|
+
totalTasks = (warmupCount + runCount) * 2;
|
|
4356
4583
|
}
|
|
4584
|
+
let tasksCompleted = 0;
|
|
4585
|
+
let perfTaskId = 1;
|
|
4586
|
+
const addTask = (warmup, kind) => {
|
|
4587
|
+
const task = {
|
|
4588
|
+
key: `perf-runner-${perfTaskId++}`,
|
|
4589
|
+
kind: "perf-runner",
|
|
4590
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
4591
|
+
var _a2, _b2, _c2, _d2;
|
|
4592
|
+
this.pendingTaskKeys.delete(task.key);
|
|
4593
|
+
try {
|
|
4594
|
+
let runTimeL;
|
|
4595
|
+
let runTimeR;
|
|
4596
|
+
switch (kind) {
|
|
4597
|
+
case "left": {
|
|
4598
|
+
const result = yield bundleModels.L.getDatasetsForScenario(scenarioSpec, []);
|
|
4599
|
+
runTimeL = result.modelRunTime;
|
|
4600
|
+
break;
|
|
4601
|
+
}
|
|
4602
|
+
case "right": {
|
|
4603
|
+
const result = yield bundleModels.R.getDatasetsForScenario(scenarioSpec, []);
|
|
4604
|
+
runTimeR = result.modelRunTime;
|
|
4605
|
+
break;
|
|
4606
|
+
}
|
|
4607
|
+
case "both": {
|
|
4608
|
+
const [resultL, resultR] = yield Promise.all([
|
|
4609
|
+
bundleModels.L.getDatasetsForScenario(scenarioSpec, []),
|
|
4610
|
+
bundleModels.R.getDatasetsForScenario(scenarioSpec, [])
|
|
4611
|
+
]);
|
|
4612
|
+
runTimeL = resultL.modelRunTime;
|
|
4613
|
+
runTimeR = resultR.modelRunTime;
|
|
4614
|
+
break;
|
|
4615
|
+
}
|
|
4616
|
+
default:
|
|
4617
|
+
assertNever11(kind);
|
|
4618
|
+
}
|
|
4619
|
+
if (!warmup) {
|
|
4620
|
+
if (runTimeL !== void 0) {
|
|
4621
|
+
statsL.addRun(runTimeL);
|
|
4622
|
+
}
|
|
4623
|
+
if (runTimeR !== void 0) {
|
|
4624
|
+
statsR.addRun(runTimeR);
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
tasksCompleted++;
|
|
4628
|
+
if (tasksCompleted === totalTasks) {
|
|
4629
|
+
(_b2 = (_a2 = this.callbacks).onComplete) == null ? void 0 : _b2.call(_a2, statsL.toReport(), statsR.toReport());
|
|
4630
|
+
}
|
|
4631
|
+
} catch (error) {
|
|
4632
|
+
(_d2 = (_c2 = this.callbacks).onError) == null ? void 0 : _d2.call(_c2, error);
|
|
4633
|
+
}
|
|
4634
|
+
})
|
|
4635
|
+
};
|
|
4636
|
+
this.taskQueue.addTask(task);
|
|
4637
|
+
this.pendingTaskKeys.add(task.key);
|
|
4638
|
+
};
|
|
4357
4639
|
function addTasks(kind) {
|
|
4358
4640
|
for (let i = 0; i < warmupCount; i++) {
|
|
4359
|
-
addTask(
|
|
4641
|
+
addTask(true, kind);
|
|
4360
4642
|
}
|
|
4361
4643
|
for (let i = 0; i < runCount; i++) {
|
|
4362
|
-
addTask(
|
|
4644
|
+
addTask(false, kind);
|
|
4363
4645
|
}
|
|
4364
4646
|
}
|
|
4365
|
-
if (this.mode === "parallel") {
|
|
4647
|
+
if (((_f = this.options) == null ? void 0 : _f.mode) === "parallel") {
|
|
4366
4648
|
addTasks("both");
|
|
4367
4649
|
} else {
|
|
4368
4650
|
addTasks("left");
|
|
@@ -4371,6 +4653,303 @@ var PerfRunner = class {
|
|
|
4371
4653
|
}
|
|
4372
4654
|
};
|
|
4373
4655
|
|
|
4656
|
+
// src/trace/trace-runner.ts
|
|
4657
|
+
import { assertNever as assertNever12 } from "assert-never";
|
|
4658
|
+
function runTraceWithTaskQueue(modelSpec, taskQueue, callbacks, options) {
|
|
4659
|
+
const traceRunner = new TraceRunner(taskQueue, callbacks);
|
|
4660
|
+
traceRunner.start(modelSpec, options);
|
|
4661
|
+
return () => {
|
|
4662
|
+
traceRunner.cancel();
|
|
4663
|
+
};
|
|
4664
|
+
}
|
|
4665
|
+
function runTrace(modelSpec, callbacks, options) {
|
|
4666
|
+
const taskQueue = TaskQueue.getInstance();
|
|
4667
|
+
return runTraceWithTaskQueue(modelSpec, taskQueue, callbacks, options);
|
|
4668
|
+
}
|
|
4669
|
+
var TraceRunner = class {
|
|
4670
|
+
constructor(taskQueue, callbacks) {
|
|
4671
|
+
this.taskQueue = taskQueue;
|
|
4672
|
+
this.callbacks = callbacks;
|
|
4673
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4674
|
+
this.stopped = false;
|
|
4675
|
+
}
|
|
4676
|
+
cancel() {
|
|
4677
|
+
if (!this.stopped) {
|
|
4678
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
4679
|
+
this.taskQueue.cancelTask(taskKey);
|
|
4680
|
+
}
|
|
4681
|
+
this.stopped = true;
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
start(modelSpec, options) {
|
|
4685
|
+
const allDatasetKeys = [...modelSpec.implVars.keys()];
|
|
4686
|
+
const traceRequests = [];
|
|
4687
|
+
const batchSize = 2e3;
|
|
4688
|
+
for (let i = 0; i < allDatasetKeys.length; i += batchSize) {
|
|
4689
|
+
const datasetKeysForBatch = allDatasetKeys.slice(i, i + batchSize);
|
|
4690
|
+
switch (options.kind) {
|
|
4691
|
+
case "compare-to-bundle":
|
|
4692
|
+
traceRequests.push({
|
|
4693
|
+
kind: "compare-to-bundle",
|
|
4694
|
+
datasetKeys: datasetKeysForBatch,
|
|
4695
|
+
bundleSide0: options.bundleSide0,
|
|
4696
|
+
scenarioSpec0: options.scenarioSpec0,
|
|
4697
|
+
bundleSide1: options.bundleSide1,
|
|
4698
|
+
scenarioSpec1: options.scenarioSpec1
|
|
4699
|
+
});
|
|
4700
|
+
break;
|
|
4701
|
+
case "compare-to-ext-data":
|
|
4702
|
+
traceRequests.push({
|
|
4703
|
+
kind: "compare-to-ext-data",
|
|
4704
|
+
datasetKeys: datasetKeysForBatch,
|
|
4705
|
+
extData: options.extData,
|
|
4706
|
+
bundleSide: options.bundleSide,
|
|
4707
|
+
scenarioSpec: options.scenarioSpec
|
|
4708
|
+
});
|
|
4709
|
+
break;
|
|
4710
|
+
default:
|
|
4711
|
+
assertNever12(options);
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
const allDatasetReports = /* @__PURE__ */ new Map();
|
|
4715
|
+
const taskCount = traceRequests.length;
|
|
4716
|
+
let tasksCompleted = 0;
|
|
4717
|
+
let traceTaskId = 1;
|
|
4718
|
+
for (const traceRequest of traceRequests) {
|
|
4719
|
+
const task = {
|
|
4720
|
+
key: `trace-runner-${traceTaskId++}`,
|
|
4721
|
+
kind: "trace-runner",
|
|
4722
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
4723
|
+
var _a, _b;
|
|
4724
|
+
this.pendingTaskKeys.delete(task.key);
|
|
4725
|
+
let datasetReports;
|
|
4726
|
+
switch (traceRequest.kind) {
|
|
4727
|
+
case "compare-to-bundle":
|
|
4728
|
+
datasetReports = yield processCompareToBundleRequest(traceRequest, bundleModels);
|
|
4729
|
+
break;
|
|
4730
|
+
case "compare-to-ext-data":
|
|
4731
|
+
datasetReports = yield processCompareToExtDataRequest(traceRequest, bundleModels);
|
|
4732
|
+
break;
|
|
4733
|
+
default:
|
|
4734
|
+
assertNever12(traceRequest);
|
|
4735
|
+
}
|
|
4736
|
+
for (const datasetReport of datasetReports) {
|
|
4737
|
+
allDatasetReports.set(datasetReport.datasetKey, datasetReport);
|
|
4738
|
+
}
|
|
4739
|
+
tasksCompleted++;
|
|
4740
|
+
if (tasksCompleted === taskCount) {
|
|
4741
|
+
const traceReport = {
|
|
4742
|
+
datasetReports: allDatasetReports
|
|
4743
|
+
};
|
|
4744
|
+
(_b = (_a = this.callbacks).onComplete) == null ? void 0 : _b.call(_a, traceReport);
|
|
4745
|
+
}
|
|
4746
|
+
})
|
|
4747
|
+
};
|
|
4748
|
+
this.taskQueue.addTask(task);
|
|
4749
|
+
this.pendingTaskKeys.add(task.key);
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
};
|
|
4753
|
+
function processCompareToBundleRequest(request, bundleModels) {
|
|
4754
|
+
return __async(this, null, function* () {
|
|
4755
|
+
const bundleModel0 = request.bundleSide0 === "left" ? bundleModels.L : bundleModels.R;
|
|
4756
|
+
const bundleModel1 = request.bundleSide1 === "left" ? bundleModels.L : bundleModels.R;
|
|
4757
|
+
let result0;
|
|
4758
|
+
let result1;
|
|
4759
|
+
if (bundleModel1 === bundleModel0) {
|
|
4760
|
+
result0 = yield bundleModel0.getDatasetsForScenario(request.scenarioSpec0, request.datasetKeys);
|
|
4761
|
+
result1 = yield bundleModel1.getDatasetsForScenario(request.scenarioSpec1, request.datasetKeys);
|
|
4762
|
+
} else {
|
|
4763
|
+
;
|
|
4764
|
+
[result0, result1] = yield Promise.all([
|
|
4765
|
+
bundleModel0.getDatasetsForScenario(request.scenarioSpec0, request.datasetKeys),
|
|
4766
|
+
bundleModel1.getDatasetsForScenario(request.scenarioSpec1, request.datasetKeys)
|
|
4767
|
+
]);
|
|
4768
|
+
}
|
|
4769
|
+
const datasetReports = [];
|
|
4770
|
+
for (const datasetKey of request.datasetKeys) {
|
|
4771
|
+
const dataset0 = result0.datasetMap.get(datasetKey);
|
|
4772
|
+
const dataset1 = result1.datasetMap.get(datasetKey);
|
|
4773
|
+
const datasetReport = diffDatasets2(
|
|
4774
|
+
datasetKey,
|
|
4775
|
+
dataset0,
|
|
4776
|
+
dataset1,
|
|
4777
|
+
/*matchPrecisionOfLeft=*/
|
|
4778
|
+
false
|
|
4779
|
+
);
|
|
4780
|
+
datasetReports.push(datasetReport);
|
|
4781
|
+
}
|
|
4782
|
+
return datasetReports;
|
|
4783
|
+
});
|
|
4784
|
+
}
|
|
4785
|
+
function processCompareToExtDataRequest(request, bundleModels) {
|
|
4786
|
+
return __async(this, null, function* () {
|
|
4787
|
+
const bundleModel = request.bundleSide === "left" ? bundleModels.L : bundleModels.R;
|
|
4788
|
+
const resultR = yield bundleModel.getDatasetsForScenario(request.scenarioSpec, request.datasetKeys);
|
|
4789
|
+
const datasetReports = [];
|
|
4790
|
+
for (const datasetKey of request.datasetKeys) {
|
|
4791
|
+
let datasetL = request.extData.get(datasetKey);
|
|
4792
|
+
if (datasetL === void 0) {
|
|
4793
|
+
const datasetKeyParts = datasetKey.split("[");
|
|
4794
|
+
if (datasetKeyParts.length === 2) {
|
|
4795
|
+
const baseKey = datasetKeyParts[0];
|
|
4796
|
+
const keySubParts = datasetKeyParts[1].replace("]", "");
|
|
4797
|
+
const keySubIds = keySubParts.split(",");
|
|
4798
|
+
const subIdPermutations = permutationsOf(keySubIds);
|
|
4799
|
+
for (const subIds of subIdPermutations) {
|
|
4800
|
+
const datDatasetKey = `${baseKey}[${subIds.join(",")}]`;
|
|
4801
|
+
datasetL = request.extData.get(datDatasetKey);
|
|
4802
|
+
if (datasetL !== void 0) {
|
|
4803
|
+
break;
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
if (datasetL === void 0) {
|
|
4808
|
+
console.warn(`WARNING: Failed to find data in dat file for key=${datasetKey}`);
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
const datasetR = resultR.datasetMap.get(datasetKey);
|
|
4812
|
+
const datasetReport = diffDatasets2(
|
|
4813
|
+
datasetKey,
|
|
4814
|
+
datasetL,
|
|
4815
|
+
datasetR,
|
|
4816
|
+
/*matchPrecisionOfLeft=*/
|
|
4817
|
+
true
|
|
4818
|
+
);
|
|
4819
|
+
datasetReports.push(datasetReport);
|
|
4820
|
+
}
|
|
4821
|
+
return datasetReports;
|
|
4822
|
+
});
|
|
4823
|
+
}
|
|
4824
|
+
function diffDatasets2(datasetKey, datasetL, datasetR, matchPrecisionOfLeft) {
|
|
4825
|
+
const points = /* @__PURE__ */ new Map();
|
|
4826
|
+
let minValueL = Number.MAX_VALUE;
|
|
4827
|
+
let maxValueL = Number.MIN_VALUE;
|
|
4828
|
+
let minValueR = Number.MAX_VALUE;
|
|
4829
|
+
let maxValueR = Number.MIN_VALUE;
|
|
4830
|
+
let minValue = Number.MAX_VALUE;
|
|
4831
|
+
let maxValue = Number.MIN_VALUE;
|
|
4832
|
+
let minRawDiff = Number.MAX_VALUE;
|
|
4833
|
+
let maxRawDiff = -1;
|
|
4834
|
+
let maxDiffPoint;
|
|
4835
|
+
let diffCount = 0;
|
|
4836
|
+
let totalRawDiff = 0;
|
|
4837
|
+
if (datasetL && datasetR) {
|
|
4838
|
+
const times = /* @__PURE__ */ new Set([...datasetL.keys(), ...datasetR.keys()]);
|
|
4839
|
+
for (const t of times) {
|
|
4840
|
+
const valueL = datasetL.get(t);
|
|
4841
|
+
if (valueL !== void 0) {
|
|
4842
|
+
if (valueL < minValueL) minValueL = valueL;
|
|
4843
|
+
if (valueL > maxValueL) maxValueL = valueL;
|
|
4844
|
+
if (valueL < minValue) minValue = valueL;
|
|
4845
|
+
if (valueL > maxValue) maxValue = valueL;
|
|
4846
|
+
}
|
|
4847
|
+
let valueR;
|
|
4848
|
+
const rawValueR = datasetR.get(t);
|
|
4849
|
+
if (rawValueR !== void 0) {
|
|
4850
|
+
if (matchPrecisionOfLeft && valueL !== void 0) {
|
|
4851
|
+
valueR = matchPrecision(rawValueR, valueL);
|
|
4852
|
+
} else {
|
|
4853
|
+
valueR = rawValueR;
|
|
4854
|
+
}
|
|
4855
|
+
if (valueR < minValueR) minValueR = valueR;
|
|
4856
|
+
if (valueR > maxValueR) maxValueR = valueR;
|
|
4857
|
+
if (valueR < minValue) minValue = valueR;
|
|
4858
|
+
if (valueR > maxValue) maxValue = valueR;
|
|
4859
|
+
}
|
|
4860
|
+
if (valueL === void 0 || valueR === void 0) {
|
|
4861
|
+
continue;
|
|
4862
|
+
}
|
|
4863
|
+
const point = {
|
|
4864
|
+
time: t,
|
|
4865
|
+
valueL,
|
|
4866
|
+
valueR
|
|
4867
|
+
};
|
|
4868
|
+
points.set(t, point);
|
|
4869
|
+
const rawDiff = Math.abs(valueR - valueL);
|
|
4870
|
+
if (rawDiff < minRawDiff) {
|
|
4871
|
+
minRawDiff = rawDiff;
|
|
4872
|
+
}
|
|
4873
|
+
if (rawDiff > maxRawDiff) {
|
|
4874
|
+
maxRawDiff = rawDiff;
|
|
4875
|
+
maxDiffPoint = point;
|
|
4876
|
+
}
|
|
4877
|
+
diffCount++;
|
|
4878
|
+
totalRawDiff += rawDiff;
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
function pct(x) {
|
|
4882
|
+
return x * 100;
|
|
4883
|
+
}
|
|
4884
|
+
let minDiff;
|
|
4885
|
+
let maxDiff;
|
|
4886
|
+
let avgDiff;
|
|
4887
|
+
if (minValueL === maxValueL && minValueR === maxValueR) {
|
|
4888
|
+
const diff = pct(maxValueL !== 0 ? Math.abs((maxValueR - maxValueL) / maxValueL) : 1);
|
|
4889
|
+
minDiff = diff;
|
|
4890
|
+
maxDiff = diff;
|
|
4891
|
+
avgDiff = diff;
|
|
4892
|
+
} else {
|
|
4893
|
+
const spread = maxValue - minValue;
|
|
4894
|
+
minDiff = pct(spread > 0 ? minRawDiff / spread : 0);
|
|
4895
|
+
maxDiff = pct(spread > 0 ? maxRawDiff / spread : 0);
|
|
4896
|
+
const avgRawDiff = totalRawDiff / diffCount;
|
|
4897
|
+
avgDiff = pct(spread > 0 ? avgRawDiff / spread : 0);
|
|
4898
|
+
}
|
|
4899
|
+
let validity;
|
|
4900
|
+
if (datasetL && datasetR) {
|
|
4901
|
+
validity = "both";
|
|
4902
|
+
} else if (datasetL) {
|
|
4903
|
+
validity = "left-only";
|
|
4904
|
+
} else if (datasetR) {
|
|
4905
|
+
validity = "right-only";
|
|
4906
|
+
} else {
|
|
4907
|
+
validity = "neither";
|
|
4908
|
+
}
|
|
4909
|
+
return {
|
|
4910
|
+
datasetKey,
|
|
4911
|
+
validity,
|
|
4912
|
+
points,
|
|
4913
|
+
minValue,
|
|
4914
|
+
maxValue,
|
|
4915
|
+
avgDiff,
|
|
4916
|
+
minDiff,
|
|
4917
|
+
maxDiff,
|
|
4918
|
+
maxDiffPoint
|
|
4919
|
+
};
|
|
4920
|
+
}
|
|
4921
|
+
function matchPrecision(x, baseline) {
|
|
4922
|
+
const s = baseline.toString();
|
|
4923
|
+
if (s.includes("e")) {
|
|
4924
|
+
return x;
|
|
4925
|
+
}
|
|
4926
|
+
const parts = s.split(".");
|
|
4927
|
+
if (parts.length < 2) {
|
|
4928
|
+
return x;
|
|
4929
|
+
}
|
|
4930
|
+
const sigDigits = parts[1].replace(/0+$/, "").length;
|
|
4931
|
+
if (sigDigits > 21) {
|
|
4932
|
+
return x;
|
|
4933
|
+
}
|
|
4934
|
+
return parseFloat(x.toFixed(sigDigits));
|
|
4935
|
+
}
|
|
4936
|
+
function permutationsOf(inputArr) {
|
|
4937
|
+
const result = [];
|
|
4938
|
+
const permute = (arr, m = []) => {
|
|
4939
|
+
if (arr.length === 0) {
|
|
4940
|
+
result.push(m);
|
|
4941
|
+
} else {
|
|
4942
|
+
for (let i = 0; i < arr.length; i++) {
|
|
4943
|
+
const curr = arr.slice();
|
|
4944
|
+
const next = curr.splice(i, 1);
|
|
4945
|
+
permute(curr.slice(), m.concat(next));
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
};
|
|
4949
|
+
permute(inputArr);
|
|
4950
|
+
return result;
|
|
4951
|
+
}
|
|
4952
|
+
|
|
4374
4953
|
// src/data/data-planner.ts
|
|
4375
4954
|
var DataPlanner = class {
|
|
4376
4955
|
/**
|
|
@@ -4557,10 +5136,10 @@ function scenarioPairUid(scenarioSpecL, scenarioSpecR) {
|
|
|
4557
5136
|
}
|
|
4558
5137
|
|
|
4559
5138
|
// src/check/check-runner.ts
|
|
4560
|
-
function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner,
|
|
4561
|
-
const modelSpec = checkConfig.bundle.
|
|
5139
|
+
function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, skipChecks) {
|
|
5140
|
+
const modelSpec = checkConfig.bundle.modelSpec;
|
|
4562
5141
|
const checkPlanner = new CheckPlanner(modelSpec);
|
|
4563
|
-
checkPlanner.addAllChecks(checkSpec,
|
|
5142
|
+
checkPlanner.addAllChecks(checkSpec, skipChecks);
|
|
4564
5143
|
const checkPlan = checkPlanner.buildPlan();
|
|
4565
5144
|
const refDatasets = /* @__PURE__ */ new Map();
|
|
4566
5145
|
for (const [dataRefKey, dataRef] of checkPlan.dataRefs.entries()) {
|
|
@@ -4573,11 +5152,15 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
|
|
|
4573
5152
|
}
|
|
4574
5153
|
const checkResults = /* @__PURE__ */ new Map();
|
|
4575
5154
|
for (const [checkKey, checkTask] of checkPlan.tasks.entries()) {
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
5155
|
+
if (checkTask.skip === true) {
|
|
5156
|
+
checkResults.set(checkKey, { status: "skipped" });
|
|
5157
|
+
} else {
|
|
5158
|
+
dataPlanner.addRequest(void 0, checkTask.scenario.spec, checkTask.dataset.datasetKey, (datasets) => {
|
|
5159
|
+
const dataset = datasets.datasetR;
|
|
5160
|
+
const checkResult = runCheck(checkTask, dataset, refDatasets);
|
|
5161
|
+
checkResults.set(checkKey, checkResult);
|
|
5162
|
+
});
|
|
5163
|
+
}
|
|
4581
5164
|
}
|
|
4582
5165
|
return () => {
|
|
4583
5166
|
return buildCheckReport(checkPlan, checkResults);
|
|
@@ -4642,21 +5225,73 @@ function runCheck(checkTask, dataset, refDatasets) {
|
|
|
4642
5225
|
}
|
|
4643
5226
|
|
|
4644
5227
|
// src/comparison/run/comparison-runner.ts
|
|
4645
|
-
function runComparisons(comparisonConfig, dataPlanner) {
|
|
5228
|
+
function runComparisons(comparisonConfig, dataPlanner, skipScenarios) {
|
|
5229
|
+
function skipScenarioKey(title, subtitle) {
|
|
5230
|
+
let key = title.toLowerCase();
|
|
5231
|
+
if (subtitle) {
|
|
5232
|
+
key += ` :: ${subtitle.toLowerCase()}`;
|
|
5233
|
+
}
|
|
5234
|
+
return key;
|
|
5235
|
+
}
|
|
5236
|
+
const skipScenariosSet = new Set(skipScenarios.map((scenario) => skipScenarioKey(scenario.title, scenario.subtitle)));
|
|
5237
|
+
const allScenarios = [...comparisonConfig.scenarios.getAllScenarios()];
|
|
5238
|
+
let baselineScenario;
|
|
5239
|
+
const baselineScenarioIndex = allScenarios.findIndex((scenario) => {
|
|
5240
|
+
const settings = scenario.settings;
|
|
5241
|
+
return settings.kind === "all-inputs-settings" && settings.position === "at-default";
|
|
5242
|
+
});
|
|
5243
|
+
if (baselineScenarioIndex !== -1) {
|
|
5244
|
+
baselineScenario = allScenarios.splice(baselineScenarioIndex, 1)[0];
|
|
5245
|
+
}
|
|
4646
5246
|
const testReports = [];
|
|
4647
|
-
|
|
5247
|
+
const baselineDiffReports = /* @__PURE__ */ new Map();
|
|
5248
|
+
function runComparisonsForScenario(scenario, isBaseline) {
|
|
4648
5249
|
const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
5250
|
+
const shouldSkip = skipScenariosSet.has(skipScenarioKey(scenario.title, scenario.subtitle));
|
|
5251
|
+
if (shouldSkip) {
|
|
5252
|
+
for (const datasetKey of datasetKeys) {
|
|
4652
5253
|
testReports.push({
|
|
4653
5254
|
scenarioKey: scenario.key,
|
|
4654
5255
|
datasetKey,
|
|
4655
|
-
diffReport
|
|
5256
|
+
diffReport: void 0
|
|
4656
5257
|
});
|
|
5258
|
+
}
|
|
5259
|
+
return;
|
|
5260
|
+
}
|
|
5261
|
+
for (const datasetKey of datasetKeys) {
|
|
5262
|
+
dataPlanner.addRequest(scenario.specL, scenario.specR, datasetKey, (datasets) => {
|
|
5263
|
+
const diffReport = diffDatasets(datasets.datasetL, datasets.datasetR);
|
|
5264
|
+
if (isBaseline) {
|
|
5265
|
+
baselineDiffReports.set(datasetKey, diffReport);
|
|
5266
|
+
testReports.push({
|
|
5267
|
+
scenarioKey: scenario.key,
|
|
5268
|
+
datasetKey,
|
|
5269
|
+
diffReport
|
|
5270
|
+
});
|
|
5271
|
+
} else {
|
|
5272
|
+
const baselineDiffReport = baselineDiffReports.get(datasetKey);
|
|
5273
|
+
testReports.push({
|
|
5274
|
+
scenarioKey: scenario.key,
|
|
5275
|
+
datasetKey,
|
|
5276
|
+
diffReport,
|
|
5277
|
+
baselineDiffReport
|
|
5278
|
+
});
|
|
5279
|
+
}
|
|
4657
5280
|
});
|
|
4658
5281
|
}
|
|
4659
5282
|
}
|
|
5283
|
+
runComparisonsForScenario(
|
|
5284
|
+
baselineScenario,
|
|
5285
|
+
/*isBaseline=*/
|
|
5286
|
+
true
|
|
5287
|
+
);
|
|
5288
|
+
for (const scenario of allScenarios) {
|
|
5289
|
+
runComparisonsForScenario(
|
|
5290
|
+
scenario,
|
|
5291
|
+
/*isBaseline=*/
|
|
5292
|
+
false
|
|
5293
|
+
);
|
|
5294
|
+
}
|
|
4660
5295
|
return () => {
|
|
4661
5296
|
return testReports;
|
|
4662
5297
|
};
|
|
@@ -4664,74 +5299,52 @@ function runComparisons(comparisonConfig, dataPlanner) {
|
|
|
4664
5299
|
|
|
4665
5300
|
// src/suite/suite-runner.ts
|
|
4666
5301
|
var SuiteRunner = class {
|
|
4667
|
-
constructor(config, callbacks) {
|
|
5302
|
+
constructor(config, taskQueue, callbacks) {
|
|
4668
5303
|
this.config = config;
|
|
5304
|
+
this.taskQueue = taskQueue;
|
|
4669
5305
|
this.callbacks = callbacks;
|
|
4670
5306
|
this.perfStatsL = new PerfStats();
|
|
4671
5307
|
this.perfStatsR = new PerfStats();
|
|
5308
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4672
5309
|
this.stopped = false;
|
|
4673
|
-
this.taskQueue = new TaskQueue({
|
|
4674
|
-
process: (request) => {
|
|
4675
|
-
return this.processRequest(request);
|
|
4676
|
-
}
|
|
4677
|
-
});
|
|
4678
5310
|
}
|
|
4679
5311
|
cancel() {
|
|
4680
5312
|
if (!this.stopped) {
|
|
5313
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
5314
|
+
this.taskQueue.cancelTask(taskKey);
|
|
5315
|
+
}
|
|
4681
5316
|
this.stopped = true;
|
|
4682
|
-
this.taskQueue.shutdown();
|
|
4683
5317
|
}
|
|
4684
5318
|
}
|
|
4685
5319
|
start(options) {
|
|
4686
5320
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4687
5321
|
(_b = (_a = this.callbacks).onProgress) == null ? void 0 : _b.call(_a, 0);
|
|
4688
|
-
const
|
|
4689
|
-
const dataPlanner = new DataPlanner(
|
|
4690
|
-
const refDataPlanner = new DataPlanner(
|
|
5322
|
+
const modelSpecR = this.config.check.bundle.modelSpec;
|
|
5323
|
+
const dataPlanner = new DataPlanner(modelSpecR.outputVars.size);
|
|
5324
|
+
const refDataPlanner = new DataPlanner(modelSpecR.outputVars.size);
|
|
4691
5325
|
const checkSpecResult = parseTestYaml(this.config.check.tests);
|
|
4692
5326
|
if (checkSpecResult.isErr()) {
|
|
4693
5327
|
(_d = (_c = this.callbacks).onError) == null ? void 0 : _d.call(_c, checkSpecResult.error);
|
|
4694
5328
|
return;
|
|
4695
5329
|
}
|
|
4696
5330
|
const checkSpec = checkSpecResult.value;
|
|
4697
|
-
const
|
|
4698
|
-
const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner,
|
|
5331
|
+
const skipChecks = (options == null ? void 0 : options.skipChecks) || [];
|
|
5332
|
+
const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner, skipChecks);
|
|
4699
5333
|
let buildComparisonTestReports;
|
|
4700
5334
|
if (this.config.comparison) {
|
|
4701
|
-
|
|
5335
|
+
const skipScenarios = (options == null ? void 0 : options.skipComparisonScenarios) || [];
|
|
5336
|
+
buildComparisonTestReports = runComparisons(this.config.comparison, dataPlanner, skipScenarios);
|
|
4702
5337
|
}
|
|
4703
|
-
this.taskQueue.onIdle = (error) => {
|
|
4704
|
-
var _a2, _b2, _c2, _d2;
|
|
4705
|
-
if (this.stopped) {
|
|
4706
|
-
return;
|
|
4707
|
-
}
|
|
4708
|
-
if (error) {
|
|
4709
|
-
(_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
|
|
4710
|
-
} else {
|
|
4711
|
-
const checkReport = buildCheckReport2();
|
|
4712
|
-
let comparisonReport;
|
|
4713
|
-
if (this.config.comparison) {
|
|
4714
|
-
comparisonReport = {
|
|
4715
|
-
testReports: buildComparisonTestReports(),
|
|
4716
|
-
perfReportL: this.perfStatsL.toReport(),
|
|
4717
|
-
perfReportR: this.perfStatsR.toReport()
|
|
4718
|
-
};
|
|
4719
|
-
}
|
|
4720
|
-
(_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
|
|
4721
|
-
checkReport,
|
|
4722
|
-
comparisonReport
|
|
4723
|
-
});
|
|
4724
|
-
}
|
|
4725
|
-
};
|
|
4726
5338
|
const refDataPlan = refDataPlanner.buildPlan();
|
|
4727
5339
|
const dataPlan = dataPlanner.buildPlan();
|
|
4728
5340
|
const dataRequests = [...refDataPlan.requests, ...dataPlan.requests];
|
|
4729
5341
|
const taskCount = dataRequests.length;
|
|
4730
5342
|
if (taskCount === 0) {
|
|
5343
|
+
const checkReport = buildCheckReport2();
|
|
4731
5344
|
let comparisonReport;
|
|
4732
5345
|
if (this.config.comparison) {
|
|
4733
5346
|
comparisonReport = {
|
|
4734
|
-
testReports:
|
|
5347
|
+
testReports: buildComparisonTestReports(),
|
|
4735
5348
|
perfReportL: this.perfStatsL.toReport(),
|
|
4736
5349
|
perfReportR: this.perfStatsR.toReport()
|
|
4737
5350
|
};
|
|
@@ -4739,26 +5352,54 @@ var SuiteRunner = class {
|
|
|
4739
5352
|
this.cancel();
|
|
4740
5353
|
(_f = (_e = this.callbacks).onProgress) == null ? void 0 : _f.call(_e, 1);
|
|
4741
5354
|
(_h = (_g = this.callbacks).onComplete) == null ? void 0 : _h.call(_g, {
|
|
4742
|
-
checkReport
|
|
4743
|
-
groups: []
|
|
4744
|
-
},
|
|
5355
|
+
checkReport,
|
|
4745
5356
|
comparisonReport
|
|
4746
5357
|
});
|
|
4747
5358
|
return;
|
|
4748
5359
|
}
|
|
5360
|
+
const buildReport = (error) => {
|
|
5361
|
+
var _a2, _b2, _c2, _d2;
|
|
5362
|
+
if (error) {
|
|
5363
|
+
(_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
|
|
5364
|
+
} else {
|
|
5365
|
+
const checkReport = buildCheckReport2();
|
|
5366
|
+
let comparisonReport;
|
|
5367
|
+
if (this.config.comparison) {
|
|
5368
|
+
comparisonReport = {
|
|
5369
|
+
testReports: buildComparisonTestReports(),
|
|
5370
|
+
perfReportL: this.perfStatsL.toReport(),
|
|
5371
|
+
perfReportR: this.perfStatsR.toReport()
|
|
5372
|
+
};
|
|
5373
|
+
}
|
|
5374
|
+
(_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
|
|
5375
|
+
checkReport,
|
|
5376
|
+
comparisonReport
|
|
5377
|
+
});
|
|
5378
|
+
}
|
|
5379
|
+
};
|
|
4749
5380
|
let tasksCompleted = 0;
|
|
4750
5381
|
let dataTaskId = 1;
|
|
4751
5382
|
for (const dataRequest of dataRequests) {
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
(
|
|
4756
|
-
|
|
5383
|
+
const task = {
|
|
5384
|
+
key: `suite-runner-${dataTaskId++}`,
|
|
5385
|
+
kind: "suite-runner",
|
|
5386
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
5387
|
+
var _a2, _b2;
|
|
5388
|
+
this.pendingTaskKeys.delete(task.key);
|
|
5389
|
+
yield this.processRequest(dataRequest, bundleModels);
|
|
5390
|
+
tasksCompleted++;
|
|
5391
|
+
(_b2 = (_a2 = this.callbacks).onProgress) == null ? void 0 : _b2.call(_a2, tasksCompleted / taskCount);
|
|
5392
|
+
if (tasksCompleted === taskCount) {
|
|
5393
|
+
buildReport();
|
|
5394
|
+
}
|
|
5395
|
+
})
|
|
5396
|
+
};
|
|
5397
|
+
this.taskQueue.addTask(task);
|
|
5398
|
+
this.pendingTaskKeys.add(task.key);
|
|
4757
5399
|
}
|
|
4758
5400
|
}
|
|
4759
|
-
processRequest(request) {
|
|
5401
|
+
processRequest(request, bundleModels) {
|
|
4760
5402
|
return __async(this, null, function* () {
|
|
4761
|
-
var _a, _b;
|
|
4762
5403
|
const datasetKeySet = /* @__PURE__ */ new Set();
|
|
4763
5404
|
for (const dataTask of request.dataTasks) {
|
|
4764
5405
|
datasetKeySet.add(dataTask.datasetKey);
|
|
@@ -4773,8 +5414,8 @@ var SuiteRunner = class {
|
|
|
4773
5414
|
}
|
|
4774
5415
|
});
|
|
4775
5416
|
}
|
|
4776
|
-
const bundleModelL =
|
|
4777
|
-
const bundleModelR =
|
|
5417
|
+
const bundleModelL = bundleModels.L;
|
|
5418
|
+
const bundleModelR = bundleModels.R;
|
|
4778
5419
|
const [datasetsResultL, datasetsResultR] = yield Promise.all([
|
|
4779
5420
|
getDatasets(bundleModelL, request.scenarioSpecL),
|
|
4780
5421
|
getDatasets(bundleModelR, request.scenarioSpecR)
|
|
@@ -4798,22 +5439,29 @@ var SuiteRunner = class {
|
|
|
4798
5439
|
});
|
|
4799
5440
|
}
|
|
4800
5441
|
};
|
|
4801
|
-
function
|
|
4802
|
-
const suiteRunner = new SuiteRunner(config, callbacks);
|
|
5442
|
+
function runSuiteWithTaskQueue(config, taskQueue, callbacks, options) {
|
|
5443
|
+
const suiteRunner = new SuiteRunner(config, taskQueue, callbacks);
|
|
4803
5444
|
suiteRunner.start(options);
|
|
4804
5445
|
return () => {
|
|
4805
5446
|
suiteRunner.cancel();
|
|
4806
5447
|
};
|
|
4807
5448
|
}
|
|
5449
|
+
function runSuite(config, callbacks, options) {
|
|
5450
|
+
const taskQueue = TaskQueue.getInstance();
|
|
5451
|
+
return runSuiteWithTaskQueue(config, taskQueue, callbacks, options);
|
|
5452
|
+
}
|
|
4808
5453
|
|
|
4809
5454
|
// src/suite/suite-reporting.ts
|
|
4810
|
-
function suiteSummaryFromReport(suiteReport) {
|
|
5455
|
+
function suiteSummaryFromReport(suiteReport, elapsedMillis) {
|
|
4811
5456
|
const checkSummary = checkSummaryFromReport(suiteReport.checkReport);
|
|
4812
5457
|
let comparisonSummary;
|
|
4813
5458
|
if (suiteReport.comparisonReport) {
|
|
4814
5459
|
comparisonSummary = comparisonSummaryFromReport(suiteReport.comparisonReport);
|
|
4815
5460
|
}
|
|
5461
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
4816
5462
|
return {
|
|
5463
|
+
date,
|
|
5464
|
+
elapsed: elapsedMillis,
|
|
4817
5465
|
checkSummary,
|
|
4818
5466
|
comparisonSummary
|
|
4819
5467
|
};
|
|
@@ -4821,20 +5469,27 @@ function suiteSummaryFromReport(suiteReport) {
|
|
|
4821
5469
|
export {
|
|
4822
5470
|
CheckDataCoordinator,
|
|
4823
5471
|
ComparisonDataCoordinator,
|
|
4824
|
-
PerfRunner,
|
|
4825
5472
|
PerfStats,
|
|
4826
5473
|
categorizeComparisonTestSummaries,
|
|
4827
5474
|
checkReportFromSummary,
|
|
4828
5475
|
checkSummaryFromReport,
|
|
4829
5476
|
comparisonSummaryFromReport,
|
|
5477
|
+
createCheckDataCoordinator,
|
|
5478
|
+
createCheckDataCoordinatorForTests,
|
|
5479
|
+
createComparisonDataCoordinator,
|
|
4830
5480
|
createConfig,
|
|
4831
5481
|
datasetMessage,
|
|
5482
|
+
decodeImplVars,
|
|
4832
5483
|
diffDatasets,
|
|
4833
5484
|
diffGraphs,
|
|
5485
|
+
encodeImplVars,
|
|
4834
5486
|
getScoresForTestSummaries,
|
|
4835
5487
|
predicateMessage,
|
|
5488
|
+
runPerf,
|
|
4836
5489
|
runSuite,
|
|
5490
|
+
runTrace,
|
|
4837
5491
|
scenarioMessage,
|
|
4838
|
-
suiteSummaryFromReport
|
|
5492
|
+
suiteSummaryFromReport,
|
|
5493
|
+
testSummaryFromReport
|
|
4839
5494
|
};
|
|
4840
5495
|
//# sourceMappingURL=index.js.map
|