@sdeverywhere/check-core 0.1.5 → 0.1.6
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 +1098 -439
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +469 -103
- package/dist/index.d.ts +469 -103
- package/dist/index.js +1089 -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(this, 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(this, 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,115 @@ 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(this, 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
|
+
if (scenarioSpec) {
|
|
2086
|
+
return bundleModel.getGraphDataForScenario(scenarioSpec, graphId);
|
|
2087
|
+
} else {
|
|
2088
|
+
return void 0;
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
const task = {
|
|
2093
|
+
key: requestKey,
|
|
2094
|
+
kind: "comparison-data-coordinator",
|
|
2095
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
2096
|
+
const modelL = sourceL === "left" ? bundleModels.L : bundleModels.R;
|
|
2097
|
+
const modelR = sourceR === "left" ? bundleModels.L : bundleModels.R;
|
|
2098
|
+
let graphDataL;
|
|
2099
|
+
let graphDataR;
|
|
2100
|
+
if (modelL === modelR) {
|
|
2101
|
+
graphDataL = yield fetchGraphData(modelL, scenarioSpecL);
|
|
2102
|
+
graphDataR = yield fetchGraphData(modelR, scenarioSpecR);
|
|
2103
|
+
} else {
|
|
2104
|
+
const results = yield Promise.all([
|
|
2105
|
+
fetchGraphData(modelL, scenarioSpecL),
|
|
2106
|
+
fetchGraphData(modelR, scenarioSpecR)
|
|
2107
|
+
]);
|
|
2108
|
+
graphDataL = results[0];
|
|
2109
|
+
graphDataR = results[1];
|
|
2110
|
+
}
|
|
2111
|
+
onResponse(graphDataL, graphDataR);
|
|
2112
|
+
})
|
|
1912
2113
|
};
|
|
1913
|
-
this.taskQueue.addTask(
|
|
1914
|
-
if (response.kind === "graph-data") {
|
|
1915
|
-
onResponse(response.graphDataL, response.graphDataR);
|
|
1916
|
-
}
|
|
1917
|
-
});
|
|
2114
|
+
this.taskQueue.addTask(task);
|
|
1918
2115
|
}
|
|
1919
2116
|
cancelRequest(key) {
|
|
1920
2117
|
this.taskQueue.cancelTask(key);
|
|
1921
2118
|
}
|
|
1922
2119
|
};
|
|
2120
|
+
function createComparisonDataCoordinator() {
|
|
2121
|
+
return new ComparisonDataCoordinator(TaskQueue.getInstance());
|
|
2122
|
+
}
|
|
1923
2123
|
|
|
1924
2124
|
// src/comparison/diff-datasets/diff-datasets.ts
|
|
1925
2125
|
function diffDatasets(datasetL, datasetR) {
|
|
@@ -2069,14 +2269,14 @@ function diffGraphs(graphL, graphR, scenarioKey, testSummaries) {
|
|
|
2069
2269
|
|
|
2070
2270
|
// src/comparison/report/comparison-reporting.ts
|
|
2071
2271
|
function comparisonSummaryFromReport(comparisonReport) {
|
|
2272
|
+
var _a, _b;
|
|
2072
2273
|
const terseSummaries = [];
|
|
2073
2274
|
for (const r of comparisonReport.testReports) {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
});
|
|
2275
|
+
const baselineMaxDiff = (_a = r.baselineDiffReport) == null ? void 0 : _a.maxDiff;
|
|
2276
|
+
const baselineAvgDiff = (_b = r.baselineDiffReport) == null ? void 0 : _b.avgDiff;
|
|
2277
|
+
const summary = testSummaryFromReport(r, baselineMaxDiff, baselineAvgDiff);
|
|
2278
|
+
if (summary) {
|
|
2279
|
+
terseSummaries.push(summary);
|
|
2080
2280
|
}
|
|
2081
2281
|
}
|
|
2082
2282
|
return {
|
|
@@ -2085,6 +2285,43 @@ function comparisonSummaryFromReport(comparisonReport) {
|
|
|
2085
2285
|
perfReportR: comparisonReport.perfReportR
|
|
2086
2286
|
};
|
|
2087
2287
|
}
|
|
2288
|
+
function testSummaryFromReport(r, baselineMaxDiff, baselineAvgDiff) {
|
|
2289
|
+
var _a;
|
|
2290
|
+
function baselineRelativeDiff(diffValue, baselineDiffValue) {
|
|
2291
|
+
if (baselineDiffValue !== void 0) {
|
|
2292
|
+
const epsilon = 1e-6;
|
|
2293
|
+
if (baselineDiffValue === 0) {
|
|
2294
|
+
baselineDiffValue = epsilon;
|
|
2295
|
+
}
|
|
2296
|
+
return diffValue / baselineDiffValue;
|
|
2297
|
+
} else {
|
|
2298
|
+
if (diffValue === 0) {
|
|
2299
|
+
return 0;
|
|
2300
|
+
} else {
|
|
2301
|
+
return 1;
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
if (r.diffReport === void 0) {
|
|
2306
|
+
return {
|
|
2307
|
+
s: r.scenarioKey,
|
|
2308
|
+
d: r.datasetKey
|
|
2309
|
+
};
|
|
2310
|
+
} else if (((_a = r.diffReport) == null ? void 0 : _a.validity) === "both" && r.diffReport.maxDiff > 0) {
|
|
2311
|
+
const maxDiffRelativeToBaseline = baselineRelativeDiff(r.diffReport.maxDiff, baselineMaxDiff);
|
|
2312
|
+
const avgDiffRelativeToBaseline = baselineRelativeDiff(r.diffReport.avgDiff, baselineAvgDiff);
|
|
2313
|
+
return {
|
|
2314
|
+
s: r.scenarioKey,
|
|
2315
|
+
d: r.datasetKey,
|
|
2316
|
+
md: r.diffReport.maxDiff,
|
|
2317
|
+
ad: r.diffReport.avgDiff,
|
|
2318
|
+
mdb: maxDiffRelativeToBaseline,
|
|
2319
|
+
adb: avgDiffRelativeToBaseline
|
|
2320
|
+
};
|
|
2321
|
+
} else {
|
|
2322
|
+
return void 0;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2088
2325
|
function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
|
|
2089
2326
|
const existingSummaries = /* @__PURE__ */ new Map();
|
|
2090
2327
|
for (const summary of terseSummaries) {
|
|
@@ -2097,24 +2334,33 @@ function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
|
|
|
2097
2334
|
for (const datasetKey of datasetKeys) {
|
|
2098
2335
|
const key = `${scenario.key}::${datasetKey}`;
|
|
2099
2336
|
const existingSummary = existingSummaries.get(key);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2337
|
+
if (existingSummary) {
|
|
2338
|
+
allTestSummaries.push(existingSummary);
|
|
2339
|
+
} else {
|
|
2340
|
+
allTestSummaries.push({
|
|
2341
|
+
s: scenario.key,
|
|
2342
|
+
d: datasetKey,
|
|
2343
|
+
md: 0,
|
|
2344
|
+
ad: 0,
|
|
2345
|
+
mdb: 0,
|
|
2346
|
+
adb: 0
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2106
2349
|
}
|
|
2107
2350
|
}
|
|
2108
2351
|
return allTestSummaries;
|
|
2109
2352
|
}
|
|
2110
2353
|
|
|
2111
2354
|
// src/comparison/report/buckets.ts
|
|
2112
|
-
function getBucketIndex(
|
|
2113
|
-
if (
|
|
2355
|
+
function getBucketIndex(diff, thresholds) {
|
|
2356
|
+
if (diff === void 0) {
|
|
2357
|
+
return thresholds.length + 2;
|
|
2358
|
+
}
|
|
2359
|
+
if (diff === 0) {
|
|
2114
2360
|
return 0;
|
|
2115
2361
|
}
|
|
2116
2362
|
for (let i = 0; i < thresholds.length; i++) {
|
|
2117
|
-
if (
|
|
2363
|
+
if (diff < thresholds[i]) {
|
|
2118
2364
|
return i + 1;
|
|
2119
2365
|
}
|
|
2120
2366
|
}
|
|
@@ -2122,14 +2368,32 @@ function getBucketIndex(diffPct, thresholds) {
|
|
|
2122
2368
|
}
|
|
2123
2369
|
|
|
2124
2370
|
// src/comparison/report/comparison-group-scores.ts
|
|
2125
|
-
function getScoresForTestSummaries(testSummaries, thresholds) {
|
|
2126
|
-
const diffCountByBucket = Array(thresholds.length +
|
|
2127
|
-
const
|
|
2371
|
+
function getScoresForTestSummaries(testSummaries, thresholds, sortMode) {
|
|
2372
|
+
const diffCountByBucket = Array(thresholds.length + 3).fill(0);
|
|
2373
|
+
const totalDiffByBucket = Array(thresholds.length + 3).fill(0);
|
|
2128
2374
|
let totalDiffCount = 0;
|
|
2375
|
+
let valueKey;
|
|
2376
|
+
switch (sortMode) {
|
|
2377
|
+
case "max-diff":
|
|
2378
|
+
valueKey = "md";
|
|
2379
|
+
break;
|
|
2380
|
+
case "avg-diff":
|
|
2381
|
+
valueKey = "ad";
|
|
2382
|
+
break;
|
|
2383
|
+
case "max-diff-relative":
|
|
2384
|
+
valueKey = "mdb";
|
|
2385
|
+
break;
|
|
2386
|
+
case "avg-diff-relative":
|
|
2387
|
+
valueKey = "adb";
|
|
2388
|
+
break;
|
|
2389
|
+
}
|
|
2129
2390
|
for (const testSummary of testSummaries) {
|
|
2130
|
-
const
|
|
2391
|
+
const value = testSummary[valueKey];
|
|
2392
|
+
const bucketIndex = getBucketIndex(value, thresholds);
|
|
2131
2393
|
diffCountByBucket[bucketIndex]++;
|
|
2132
|
-
|
|
2394
|
+
if (value !== void 0) {
|
|
2395
|
+
totalDiffByBucket[bucketIndex] += value;
|
|
2396
|
+
}
|
|
2133
2397
|
totalDiffCount++;
|
|
2134
2398
|
}
|
|
2135
2399
|
let diffPercentByBucket;
|
|
@@ -2140,20 +2404,20 @@ function getScoresForTestSummaries(testSummaries, thresholds) {
|
|
|
2140
2404
|
}
|
|
2141
2405
|
return {
|
|
2142
2406
|
totalDiffCount,
|
|
2143
|
-
|
|
2407
|
+
totalDiffByBucket,
|
|
2144
2408
|
diffCountByBucket,
|
|
2145
2409
|
diffPercentByBucket
|
|
2146
2410
|
};
|
|
2147
2411
|
}
|
|
2148
2412
|
|
|
2149
2413
|
// src/comparison/report/comparison-grouping.ts
|
|
2150
|
-
import { assertNever as
|
|
2151
|
-
function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
|
|
2414
|
+
import { assertNever as assertNever7 } from "assert-never";
|
|
2415
|
+
function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries, sortMode) {
|
|
2152
2416
|
const allTestSummaries = restoreFromTerseSummaries(comparisonConfig, terseSummaries);
|
|
2153
2417
|
const groupsByScenario = groupComparisonTestSummaries(allTestSummaries, "by-scenario");
|
|
2154
|
-
const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()]);
|
|
2418
|
+
const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()], sortMode);
|
|
2155
2419
|
const groupsByDataset = groupComparisonTestSummaries(allTestSummaries, "by-dataset");
|
|
2156
|
-
const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()]);
|
|
2420
|
+
const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()], sortMode);
|
|
2157
2421
|
return {
|
|
2158
2422
|
allTestSummaries,
|
|
2159
2423
|
byScenario,
|
|
@@ -2172,7 +2436,7 @@ function groupComparisonTestSummaries(testSummaries, groupKind) {
|
|
|
2172
2436
|
groupKey = testSummary.s;
|
|
2173
2437
|
break;
|
|
2174
2438
|
default:
|
|
2175
|
-
|
|
2439
|
+
assertNever7(groupKind);
|
|
2176
2440
|
}
|
|
2177
2441
|
const group = groups.get(groupKey);
|
|
2178
2442
|
if (group) {
|
|
@@ -2187,7 +2451,7 @@ function groupComparisonTestSummaries(testSummaries, groupKind) {
|
|
|
2187
2451
|
}
|
|
2188
2452
|
return groups;
|
|
2189
2453
|
}
|
|
2190
|
-
function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
2454
|
+
function categorizeComparisonGroups(comparisonConfig, allGroups, sortMode) {
|
|
2191
2455
|
const allGroupSummaries = /* @__PURE__ */ new Map();
|
|
2192
2456
|
const withErrors = [];
|
|
2193
2457
|
const onlyInLeft = [];
|
|
@@ -2197,7 +2461,9 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2197
2461
|
function addSummaryForGroup(group, root, validInL, validInR) {
|
|
2198
2462
|
let scores;
|
|
2199
2463
|
if (validInL && validInR) {
|
|
2200
|
-
|
|
2464
|
+
const isRelativeMode = sortMode === "max-diff-relative" || sortMode === "avg-diff-relative";
|
|
2465
|
+
const thresholds = isRelativeMode ? comparisonConfig.ratioThresholds : comparisonConfig.thresholds;
|
|
2466
|
+
scores = getScoresForTestSummaries(group.testSummaries, thresholds, sortMode);
|
|
2201
2467
|
}
|
|
2202
2468
|
const groupSummary = {
|
|
2203
2469
|
root,
|
|
@@ -2206,7 +2472,9 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2206
2472
|
};
|
|
2207
2473
|
allGroupSummaries.set(group.key, groupSummary);
|
|
2208
2474
|
if (validInL && validInR) {
|
|
2209
|
-
|
|
2475
|
+
const noDiffCount = scores.diffCountByBucket[0];
|
|
2476
|
+
const skippedCount = scores.diffCountByBucket[5];
|
|
2477
|
+
if (scores.totalDiffCount !== noDiffCount + skippedCount) {
|
|
2210
2478
|
withDiffs.push(groupSummary);
|
|
2211
2479
|
} else {
|
|
2212
2480
|
withoutDiffs.push(groupSummary);
|
|
@@ -2236,7 +2504,7 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
|
|
|
2236
2504
|
break;
|
|
2237
2505
|
}
|
|
2238
2506
|
default:
|
|
2239
|
-
|
|
2507
|
+
assertNever7(group.kind);
|
|
2240
2508
|
}
|
|
2241
2509
|
}
|
|
2242
2510
|
if (withDiffs.length > 1) {
|
|
@@ -2298,13 +2566,13 @@ function sortScenarioGroupSummaries(summaries) {
|
|
|
2298
2566
|
});
|
|
2299
2567
|
}
|
|
2300
2568
|
function compareScores(a, b) {
|
|
2301
|
-
if (a.
|
|
2569
|
+
if (a.totalDiffByBucket.length !== b.totalDiffByBucket.length) {
|
|
2302
2570
|
return 0;
|
|
2303
2571
|
}
|
|
2304
|
-
const len = a.
|
|
2572
|
+
const len = a.totalDiffByBucket.length;
|
|
2305
2573
|
for (let i = len - 1; i >= 0; i--) {
|
|
2306
|
-
const aTotal = a.
|
|
2307
|
-
const bTotal = b.
|
|
2574
|
+
const aTotal = a.totalDiffByBucket[i];
|
|
2575
|
+
const bTotal = b.totalDiffByBucket[i];
|
|
2308
2576
|
if (aTotal > bTotal) {
|
|
2309
2577
|
return 1;
|
|
2310
2578
|
} else if (aTotal < bTotal) {
|
|
@@ -2316,7 +2584,7 @@ function compareScores(a, b) {
|
|
|
2316
2584
|
|
|
2317
2585
|
// src/comparison/config/parse/comparison-parser.ts
|
|
2318
2586
|
import Ajv2 from "ajv";
|
|
2319
|
-
import
|
|
2587
|
+
import assertNever8 from "assert-never";
|
|
2320
2588
|
import { err as err2, ok as ok2 } from "neverthrow";
|
|
2321
2589
|
import yaml2 from "yaml";
|
|
2322
2590
|
|
|
@@ -2852,7 +3120,7 @@ function parseComparisonSpecs(specSource) {
|
|
|
2852
3120
|
parsed = yaml2.parse(specSource.content);
|
|
2853
3121
|
break;
|
|
2854
3122
|
default:
|
|
2855
|
-
|
|
3123
|
+
assertNever8(specSource.kind);
|
|
2856
3124
|
}
|
|
2857
3125
|
if (validate(parsed)) {
|
|
2858
3126
|
for (const specItem of parsed) {
|
|
@@ -3079,7 +3347,7 @@ function viewGroupSpecFromParsed(parsedViewGroup) {
|
|
|
3079
3347
|
}
|
|
3080
3348
|
|
|
3081
3349
|
// src/comparison/config/resolve/comparison-resolver.ts
|
|
3082
|
-
import { assertNever as
|
|
3350
|
+
import { assertNever as assertNever10 } from "assert-never";
|
|
3083
3351
|
|
|
3084
3352
|
// src/bundle/model-inputs.ts
|
|
3085
3353
|
var ModelInputs = class {
|
|
@@ -3142,7 +3410,7 @@ var ModelInputs = class {
|
|
|
3142
3410
|
};
|
|
3143
3411
|
|
|
3144
3412
|
// src/comparison/config/resolve/comparison-scenario-specs.ts
|
|
3145
|
-
import { assertNever as
|
|
3413
|
+
import { assertNever as assertNever9 } from "assert-never";
|
|
3146
3414
|
function scenarioSpecsFromSettings(settings) {
|
|
3147
3415
|
switch (settings.kind) {
|
|
3148
3416
|
case "all-inputs-settings": {
|
|
@@ -3155,7 +3423,7 @@ function scenarioSpecsFromSettings(settings) {
|
|
|
3155
3423
|
return [specL, specR];
|
|
3156
3424
|
}
|
|
3157
3425
|
default:
|
|
3158
|
-
|
|
3426
|
+
assertNever9(settings);
|
|
3159
3427
|
}
|
|
3160
3428
|
}
|
|
3161
3429
|
function scenarioSpecFromInputs(inputs, side) {
|
|
@@ -3374,7 +3642,7 @@ function resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genK
|
|
|
3374
3642
|
];
|
|
3375
3643
|
}
|
|
3376
3644
|
default:
|
|
3377
|
-
|
|
3645
|
+
assertNever10(scenarioSpec);
|
|
3378
3646
|
}
|
|
3379
3647
|
}
|
|
3380
3648
|
function resolveScenarioMatrix(modelInputsL, modelInputsR, genKey) {
|
|
@@ -3430,7 +3698,7 @@ function resolveScenarioForInputSpecs(modelInputsL, modelInputsR, key, id, title
|
|
|
3430
3698
|
case "input-at-value":
|
|
3431
3699
|
return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.value);
|
|
3432
3700
|
default:
|
|
3433
|
-
|
|
3701
|
+
assertNever10(inputSpec);
|
|
3434
3702
|
}
|
|
3435
3703
|
});
|
|
3436
3704
|
const settings = {
|
|
@@ -3463,7 +3731,7 @@ function resolveScenarioForDistinctInputSpecs(modelInputsL, modelInputsR, key, i
|
|
|
3463
3731
|
inputState = resolveInputForNameInModel(modelInputs, inputSpec.inputName, inputSpec.value);
|
|
3464
3732
|
break;
|
|
3465
3733
|
default:
|
|
3466
|
-
|
|
3734
|
+
assertNever10(inputSpec);
|
|
3467
3735
|
}
|
|
3468
3736
|
if (inputState.error !== void 0) {
|
|
3469
3737
|
inputsWithErrors.push({
|
|
@@ -3679,7 +3947,7 @@ function inputValueAtPosition2(inputVar, position) {
|
|
|
3679
3947
|
case "at-maximum":
|
|
3680
3948
|
return inputVar.maxValue;
|
|
3681
3949
|
default:
|
|
3682
|
-
|
|
3950
|
+
assertNever10(position);
|
|
3683
3951
|
}
|
|
3684
3952
|
}
|
|
3685
3953
|
var ResolvedScenarioGroups = class {
|
|
@@ -3738,7 +4006,7 @@ function resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, grap
|
|
|
3738
4006
|
return [...graphIds];
|
|
3739
4007
|
}
|
|
3740
4008
|
default:
|
|
3741
|
-
|
|
4009
|
+
assertNever10(graphsSpec.preset);
|
|
3742
4010
|
}
|
|
3743
4011
|
}
|
|
3744
4012
|
// eslint-disable-next-line no-fallthrough
|
|
@@ -3752,7 +4020,7 @@ function resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, grap
|
|
|
3752
4020
|
return groupSpec.graphIds;
|
|
3753
4021
|
}
|
|
3754
4022
|
default:
|
|
3755
|
-
|
|
4023
|
+
assertNever10(graphsSpec);
|
|
3756
4024
|
}
|
|
3757
4025
|
}
|
|
3758
4026
|
function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphIds, graphOrder) {
|
|
@@ -3926,7 +4194,7 @@ function resolveViewGroupFromSpec(modelSpecL, modelSpecR, modelOutputs, resolved
|
|
|
3926
4194
|
views.push(resolveViewForScenario(void 0, void 0, scenario, graphIds, graphOrder));
|
|
3927
4195
|
break;
|
|
3928
4196
|
default:
|
|
3929
|
-
|
|
4197
|
+
assertNever10(scenario);
|
|
3930
4198
|
}
|
|
3931
4199
|
}
|
|
3932
4200
|
} else {
|
|
@@ -3935,13 +4203,13 @@ function resolveViewGroupFromSpec(modelSpecL, modelSpecR, modelOutputs, resolved
|
|
|
3935
4203
|
break;
|
|
3936
4204
|
}
|
|
3937
4205
|
default:
|
|
3938
|
-
|
|
4206
|
+
assertNever10(refSpec);
|
|
3939
4207
|
}
|
|
3940
4208
|
}
|
|
3941
4209
|
break;
|
|
3942
4210
|
}
|
|
3943
4211
|
default:
|
|
3944
|
-
|
|
4212
|
+
assertNever10(viewGroupSpec);
|
|
3945
4213
|
}
|
|
3946
4214
|
return {
|
|
3947
4215
|
kind: "view-group",
|
|
@@ -4004,9 +4272,9 @@ var ComparisonDatasetsImpl = class {
|
|
|
4004
4272
|
}
|
|
4005
4273
|
const allOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
4006
4274
|
const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
4007
|
-
function addOutputVars(outputVars,
|
|
4275
|
+
function addOutputVars(outputVars, handleRenames2) {
|
|
4008
4276
|
outputVars.forEach((outputVar, key) => {
|
|
4009
|
-
const remappedKey =
|
|
4277
|
+
const remappedKey = handleRenames2 ? leftKeyForRightKey(key) : key;
|
|
4010
4278
|
allOutputVarKeysSet.add(remappedKey);
|
|
4011
4279
|
if (outputVar.sourceName === void 0) {
|
|
4012
4280
|
modelOutputVarKeysSet.add(remappedKey);
|
|
@@ -4120,109 +4388,41 @@ var ComparisonScenariosImpl = class {
|
|
|
4120
4388
|
}
|
|
4121
4389
|
};
|
|
4122
4390
|
|
|
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
4391
|
// src/config/config.ts
|
|
4175
4392
|
function createConfig(options) {
|
|
4176
4393
|
return __async(this, null, function* () {
|
|
4177
|
-
var _a;
|
|
4178
|
-
|
|
4394
|
+
var _a, _b, _c, _d, _e;
|
|
4395
|
+
let concurrentModels;
|
|
4396
|
+
if (options.concurrency === void 0) {
|
|
4397
|
+
concurrentModels = 1;
|
|
4398
|
+
} else if (options.concurrency === 0) {
|
|
4399
|
+
let coreCount;
|
|
4400
|
+
if (typeof navigator !== "undefined") {
|
|
4401
|
+
coreCount = navigator.hardwareConcurrency;
|
|
4402
|
+
}
|
|
4403
|
+
if (coreCount === void 0 || coreCount < 1) {
|
|
4404
|
+
coreCount = 1;
|
|
4405
|
+
}
|
|
4406
|
+
concurrentModels = Math.max(1, Math.floor(coreCount / 2));
|
|
4407
|
+
} else {
|
|
4408
|
+
concurrentModels = Math.max(1, options.concurrency);
|
|
4409
|
+
}
|
|
4410
|
+
const origCurrentBundle = yield loadBundle(options.current, concurrentModels);
|
|
4179
4411
|
let currentBundle;
|
|
4180
4412
|
let comparisonConfig;
|
|
4181
4413
|
if (options.comparison === void 0) {
|
|
4182
4414
|
currentBundle = origCurrentBundle;
|
|
4183
4415
|
} 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;
|
|
4416
|
+
const baselineBundle = yield loadBundle(options.comparison.baseline, concurrentModels);
|
|
4417
|
+
currentBundle = handleRenames(origCurrentBundle, (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys);
|
|
4418
|
+
const modelSpecL = baselineBundle.modelSpec;
|
|
4419
|
+
const modelSpecR = currentBundle.modelSpec;
|
|
4221
4420
|
const comparisonDefs = resolveComparisonSpecsFromSources(modelSpecL, modelSpecR, options.comparison.specs);
|
|
4222
4421
|
comparisonConfig = {
|
|
4223
4422
|
bundleL: baselineBundle,
|
|
4224
4423
|
bundleR: currentBundle,
|
|
4225
|
-
thresholds: options.comparison.thresholds,
|
|
4424
|
+
thresholds: (_b = options.comparison.thresholds) != null ? _b : [1, 5, 10],
|
|
4425
|
+
ratioThresholds: (_c = options.comparison.ratioThresholds) != null ? _c : [1, 2, 3],
|
|
4226
4426
|
scenarios: getComparisonScenarios(comparisonDefs.scenarios),
|
|
4227
4427
|
datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
|
|
4228
4428
|
viewGroups: comparisonDefs.viewGroups,
|
|
@@ -4233,26 +4433,75 @@ function createConfig(options) {
|
|
|
4233
4433
|
bundle: currentBundle,
|
|
4234
4434
|
tests: options.check.tests
|
|
4235
4435
|
};
|
|
4436
|
+
const executors = /* @__PURE__ */ new Map();
|
|
4437
|
+
for (let i = 0; i < checkConfig.bundle.models.length; i++) {
|
|
4438
|
+
const bundleModelL = (_d = comparisonConfig == null ? void 0 : comparisonConfig.bundleL.models) == null ? void 0 : _d[i];
|
|
4439
|
+
const bundleModelR = ((_e = comparisonConfig == null ? void 0 : comparisonConfig.bundleR.models) == null ? void 0 : _e[i]) || checkConfig.bundle.models[i];
|
|
4440
|
+
const executor = createExecutor(bundleModelL, bundleModelR);
|
|
4441
|
+
executors.set(`executor-${i}`, executor);
|
|
4442
|
+
}
|
|
4443
|
+
TaskQueue.initialize(executors);
|
|
4236
4444
|
return {
|
|
4237
4445
|
check: checkConfig,
|
|
4238
4446
|
comparison: comparisonConfig
|
|
4239
4447
|
};
|
|
4240
4448
|
});
|
|
4241
4449
|
}
|
|
4242
|
-
function
|
|
4450
|
+
function loadBundle(bundle, concurrentModels) {
|
|
4243
4451
|
return __async(this, null, function* () {
|
|
4244
|
-
const
|
|
4245
|
-
const
|
|
4452
|
+
const initCalls = Array.from({ length: concurrentModels }, () => bundle.bundle.initModel());
|
|
4453
|
+
const models = yield Promise.all(initCalls);
|
|
4246
4454
|
return {
|
|
4247
|
-
name:
|
|
4248
|
-
version:
|
|
4249
|
-
|
|
4455
|
+
name: bundle.name,
|
|
4456
|
+
version: bundle.bundle.version,
|
|
4457
|
+
modelSpec: bundle.bundle.modelSpec,
|
|
4458
|
+
models
|
|
4459
|
+
};
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4462
|
+
function handleRenames(origCurrentBundle, renamedDatasetKeys) {
|
|
4463
|
+
if (renamedDatasetKeys === void 0 || renamedDatasetKeys.size === 0) {
|
|
4464
|
+
return origCurrentBundle;
|
|
4465
|
+
}
|
|
4466
|
+
const invertedRenamedKeys = /* @__PURE__ */ new Map();
|
|
4467
|
+
renamedDatasetKeys.forEach((newKey, oldKey) => {
|
|
4468
|
+
invertedRenamedKeys.set(newKey, oldKey);
|
|
4469
|
+
});
|
|
4470
|
+
const rightKeyForLeftKey = (leftKey) => {
|
|
4471
|
+
return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
|
|
4472
|
+
};
|
|
4473
|
+
const leftKeyForRightKey = (rightKey) => {
|
|
4474
|
+
return invertedRenamedKeys.get(rightKey) || rightKey;
|
|
4475
|
+
};
|
|
4476
|
+
function wrapModel(origBundleModelR) {
|
|
4477
|
+
return {
|
|
4478
|
+
modelSpec: origBundleModelR.modelSpec,
|
|
4479
|
+
getDatasetsForScenario: (scenarioSpec, datasetKeys) => __async(this, null, function* () {
|
|
4480
|
+
const rightKeys = datasetKeys.map(rightKeyForLeftKey);
|
|
4481
|
+
const result = yield origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
|
|
4482
|
+
const mapWithRightKeys = result.datasetMap;
|
|
4483
|
+
const mapWithLeftKeys = /* @__PURE__ */ new Map();
|
|
4484
|
+
for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
|
|
4485
|
+
const leftKey = leftKeyForRightKey(rightKey);
|
|
4486
|
+
mapWithLeftKeys.set(leftKey, dataset);
|
|
4487
|
+
}
|
|
4488
|
+
return {
|
|
4489
|
+
datasetMap: mapWithLeftKeys,
|
|
4490
|
+
modelRunTime: result.modelRunTime
|
|
4491
|
+
};
|
|
4492
|
+
}),
|
|
4493
|
+
getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
|
|
4494
|
+
getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
|
|
4250
4495
|
};
|
|
4496
|
+
}
|
|
4497
|
+
const wrappedModels = origCurrentBundle.models.map(wrapModel);
|
|
4498
|
+
return __spreadProps(__spreadValues({}, origCurrentBundle), {
|
|
4499
|
+
models: wrappedModels
|
|
4251
4500
|
});
|
|
4252
4501
|
}
|
|
4253
4502
|
|
|
4254
4503
|
// src/perf/perf-runner.ts
|
|
4255
|
-
import { assertNever as
|
|
4504
|
+
import { assertNever as assertNever11 } from "assert-never";
|
|
4256
4505
|
|
|
4257
4506
|
// src/perf/perf-stats.ts
|
|
4258
4507
|
var PerfStats = class {
|
|
@@ -4289,80 +4538,110 @@ var PerfStats = class {
|
|
|
4289
4538
|
};
|
|
4290
4539
|
|
|
4291
4540
|
// src/perf/perf-runner.ts
|
|
4292
|
-
|
|
4293
|
-
|
|
4541
|
+
function runPerfWithTaskQueue(taskQueue, callbacks, options) {
|
|
4542
|
+
const perfRunner = new PerfRunner(taskQueue, callbacks, options);
|
|
4543
|
+
perfRunner.start();
|
|
4544
|
+
return () => {
|
|
4545
|
+
perfRunner.cancel();
|
|
4546
|
+
};
|
|
4547
|
+
}
|
|
4548
|
+
function runPerf(callbacks, options) {
|
|
4549
|
+
const taskQueue = TaskQueue.getInstance();
|
|
4550
|
+
return runPerfWithTaskQueue(taskQueue, callbacks, options);
|
|
4551
|
+
}
|
|
4294
4552
|
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
|
-
});
|
|
4553
|
+
constructor(taskQueue, callbacks, options) {
|
|
4554
|
+
this.taskQueue = taskQueue;
|
|
4555
|
+
this.callbacks = callbacks;
|
|
4556
|
+
this.options = options;
|
|
4557
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4558
|
+
this.stopped = false;
|
|
4559
|
+
}
|
|
4560
|
+
cancel() {
|
|
4561
|
+
if (!this.stopped) {
|
|
4562
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
4563
|
+
this.taskQueue.cancelTask(taskKey);
|
|
4564
|
+
}
|
|
4565
|
+
this.stopped = true;
|
|
4566
|
+
}
|
|
4330
4567
|
}
|
|
4331
4568
|
start() {
|
|
4569
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4332
4570
|
const statsL = new PerfStats();
|
|
4333
4571
|
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
|
-
});
|
|
4572
|
+
const scenarioSpec = allInputsAtPositionSpec("at-default");
|
|
4573
|
+
const warmupCount = (_b = (_a = this.options) == null ? void 0 : _a.warmupCount) != null ? _b : 5;
|
|
4574
|
+
const runCount = (_d = (_c = this.options) == null ? void 0 : _c.runCount) != null ? _d : 100;
|
|
4575
|
+
let totalTasks = 0;
|
|
4576
|
+
if (((_e = this.options) == null ? void 0 : _e.mode) === "parallel") {
|
|
4577
|
+
totalTasks = warmupCount + runCount;
|
|
4578
|
+
} else {
|
|
4579
|
+
totalTasks = (warmupCount + runCount) * 2;
|
|
4356
4580
|
}
|
|
4581
|
+
let tasksCompleted = 0;
|
|
4582
|
+
let perfTaskId = 1;
|
|
4583
|
+
const addTask = (warmup, kind) => {
|
|
4584
|
+
const task = {
|
|
4585
|
+
key: `perf-runner-${perfTaskId++}`,
|
|
4586
|
+
kind: "perf-runner",
|
|
4587
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
4588
|
+
var _a2, _b2, _c2, _d2;
|
|
4589
|
+
this.pendingTaskKeys.delete(task.key);
|
|
4590
|
+
try {
|
|
4591
|
+
let runTimeL;
|
|
4592
|
+
let runTimeR;
|
|
4593
|
+
switch (kind) {
|
|
4594
|
+
case "left": {
|
|
4595
|
+
const result = yield bundleModels.L.getDatasetsForScenario(scenarioSpec, []);
|
|
4596
|
+
runTimeL = result.modelRunTime;
|
|
4597
|
+
break;
|
|
4598
|
+
}
|
|
4599
|
+
case "right": {
|
|
4600
|
+
const result = yield bundleModels.R.getDatasetsForScenario(scenarioSpec, []);
|
|
4601
|
+
runTimeR = result.modelRunTime;
|
|
4602
|
+
break;
|
|
4603
|
+
}
|
|
4604
|
+
case "both": {
|
|
4605
|
+
const [resultL, resultR] = yield Promise.all([
|
|
4606
|
+
bundleModels.L.getDatasetsForScenario(scenarioSpec, []),
|
|
4607
|
+
bundleModels.R.getDatasetsForScenario(scenarioSpec, [])
|
|
4608
|
+
]);
|
|
4609
|
+
runTimeL = resultL.modelRunTime;
|
|
4610
|
+
runTimeR = resultR.modelRunTime;
|
|
4611
|
+
break;
|
|
4612
|
+
}
|
|
4613
|
+
default:
|
|
4614
|
+
assertNever11(kind);
|
|
4615
|
+
}
|
|
4616
|
+
if (!warmup) {
|
|
4617
|
+
if (runTimeL !== void 0) {
|
|
4618
|
+
statsL.addRun(runTimeL);
|
|
4619
|
+
}
|
|
4620
|
+
if (runTimeR !== void 0) {
|
|
4621
|
+
statsR.addRun(runTimeR);
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
tasksCompleted++;
|
|
4625
|
+
if (tasksCompleted === totalTasks) {
|
|
4626
|
+
(_b2 = (_a2 = this.callbacks).onComplete) == null ? void 0 : _b2.call(_a2, statsL.toReport(), statsR.toReport());
|
|
4627
|
+
}
|
|
4628
|
+
} catch (error) {
|
|
4629
|
+
(_d2 = (_c2 = this.callbacks).onError) == null ? void 0 : _d2.call(_c2, error);
|
|
4630
|
+
}
|
|
4631
|
+
})
|
|
4632
|
+
};
|
|
4633
|
+
this.taskQueue.addTask(task);
|
|
4634
|
+
this.pendingTaskKeys.add(task.key);
|
|
4635
|
+
};
|
|
4357
4636
|
function addTasks(kind) {
|
|
4358
4637
|
for (let i = 0; i < warmupCount; i++) {
|
|
4359
|
-
addTask(
|
|
4638
|
+
addTask(true, kind);
|
|
4360
4639
|
}
|
|
4361
4640
|
for (let i = 0; i < runCount; i++) {
|
|
4362
|
-
addTask(
|
|
4641
|
+
addTask(false, kind);
|
|
4363
4642
|
}
|
|
4364
4643
|
}
|
|
4365
|
-
if (this.mode === "parallel") {
|
|
4644
|
+
if (((_f = this.options) == null ? void 0 : _f.mode) === "parallel") {
|
|
4366
4645
|
addTasks("both");
|
|
4367
4646
|
} else {
|
|
4368
4647
|
addTasks("left");
|
|
@@ -4371,6 +4650,303 @@ var PerfRunner = class {
|
|
|
4371
4650
|
}
|
|
4372
4651
|
};
|
|
4373
4652
|
|
|
4653
|
+
// src/trace/trace-runner.ts
|
|
4654
|
+
import { assertNever as assertNever12 } from "assert-never";
|
|
4655
|
+
function runTraceWithTaskQueue(modelSpec, taskQueue, callbacks, options) {
|
|
4656
|
+
const traceRunner = new TraceRunner(taskQueue, callbacks);
|
|
4657
|
+
traceRunner.start(modelSpec, options);
|
|
4658
|
+
return () => {
|
|
4659
|
+
traceRunner.cancel();
|
|
4660
|
+
};
|
|
4661
|
+
}
|
|
4662
|
+
function runTrace(modelSpec, callbacks, options) {
|
|
4663
|
+
const taskQueue = TaskQueue.getInstance();
|
|
4664
|
+
return runTraceWithTaskQueue(modelSpec, taskQueue, callbacks, options);
|
|
4665
|
+
}
|
|
4666
|
+
var TraceRunner = class {
|
|
4667
|
+
constructor(taskQueue, callbacks) {
|
|
4668
|
+
this.taskQueue = taskQueue;
|
|
4669
|
+
this.callbacks = callbacks;
|
|
4670
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4671
|
+
this.stopped = false;
|
|
4672
|
+
}
|
|
4673
|
+
cancel() {
|
|
4674
|
+
if (!this.stopped) {
|
|
4675
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
4676
|
+
this.taskQueue.cancelTask(taskKey);
|
|
4677
|
+
}
|
|
4678
|
+
this.stopped = true;
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
start(modelSpec, options) {
|
|
4682
|
+
const allDatasetKeys = [...modelSpec.implVars.keys()];
|
|
4683
|
+
const traceRequests = [];
|
|
4684
|
+
const batchSize = 2e3;
|
|
4685
|
+
for (let i = 0; i < allDatasetKeys.length; i += batchSize) {
|
|
4686
|
+
const datasetKeysForBatch = allDatasetKeys.slice(i, i + batchSize);
|
|
4687
|
+
switch (options.kind) {
|
|
4688
|
+
case "compare-to-bundle":
|
|
4689
|
+
traceRequests.push({
|
|
4690
|
+
kind: "compare-to-bundle",
|
|
4691
|
+
datasetKeys: datasetKeysForBatch,
|
|
4692
|
+
bundleSide0: options.bundleSide0,
|
|
4693
|
+
scenarioSpec0: options.scenarioSpec0,
|
|
4694
|
+
bundleSide1: options.bundleSide1,
|
|
4695
|
+
scenarioSpec1: options.scenarioSpec1
|
|
4696
|
+
});
|
|
4697
|
+
break;
|
|
4698
|
+
case "compare-to-ext-data":
|
|
4699
|
+
traceRequests.push({
|
|
4700
|
+
kind: "compare-to-ext-data",
|
|
4701
|
+
datasetKeys: datasetKeysForBatch,
|
|
4702
|
+
extData: options.extData,
|
|
4703
|
+
bundleSide: options.bundleSide,
|
|
4704
|
+
scenarioSpec: options.scenarioSpec
|
|
4705
|
+
});
|
|
4706
|
+
break;
|
|
4707
|
+
default:
|
|
4708
|
+
assertNever12(options);
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
const allDatasetReports = /* @__PURE__ */ new Map();
|
|
4712
|
+
const taskCount = traceRequests.length;
|
|
4713
|
+
let tasksCompleted = 0;
|
|
4714
|
+
let traceTaskId = 1;
|
|
4715
|
+
for (const traceRequest of traceRequests) {
|
|
4716
|
+
const task = {
|
|
4717
|
+
key: `trace-runner-${traceTaskId++}`,
|
|
4718
|
+
kind: "trace-runner",
|
|
4719
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
4720
|
+
var _a, _b;
|
|
4721
|
+
this.pendingTaskKeys.delete(task.key);
|
|
4722
|
+
let datasetReports;
|
|
4723
|
+
switch (traceRequest.kind) {
|
|
4724
|
+
case "compare-to-bundle":
|
|
4725
|
+
datasetReports = yield processCompareToBundleRequest(traceRequest, bundleModels);
|
|
4726
|
+
break;
|
|
4727
|
+
case "compare-to-ext-data":
|
|
4728
|
+
datasetReports = yield processCompareToExtDataRequest(traceRequest, bundleModels);
|
|
4729
|
+
break;
|
|
4730
|
+
default:
|
|
4731
|
+
assertNever12(traceRequest);
|
|
4732
|
+
}
|
|
4733
|
+
for (const datasetReport of datasetReports) {
|
|
4734
|
+
allDatasetReports.set(datasetReport.datasetKey, datasetReport);
|
|
4735
|
+
}
|
|
4736
|
+
tasksCompleted++;
|
|
4737
|
+
if (tasksCompleted === taskCount) {
|
|
4738
|
+
const traceReport = {
|
|
4739
|
+
datasetReports: allDatasetReports
|
|
4740
|
+
};
|
|
4741
|
+
(_b = (_a = this.callbacks).onComplete) == null ? void 0 : _b.call(_a, traceReport);
|
|
4742
|
+
}
|
|
4743
|
+
})
|
|
4744
|
+
};
|
|
4745
|
+
this.taskQueue.addTask(task);
|
|
4746
|
+
this.pendingTaskKeys.add(task.key);
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
};
|
|
4750
|
+
function processCompareToBundleRequest(request, bundleModels) {
|
|
4751
|
+
return __async(this, null, function* () {
|
|
4752
|
+
const bundleModel0 = request.bundleSide0 === "left" ? bundleModels.L : bundleModels.R;
|
|
4753
|
+
const bundleModel1 = request.bundleSide1 === "left" ? bundleModels.L : bundleModels.R;
|
|
4754
|
+
let result0;
|
|
4755
|
+
let result1;
|
|
4756
|
+
if (bundleModel1 === bundleModel0) {
|
|
4757
|
+
result0 = yield bundleModel0.getDatasetsForScenario(request.scenarioSpec0, request.datasetKeys);
|
|
4758
|
+
result1 = yield bundleModel1.getDatasetsForScenario(request.scenarioSpec1, request.datasetKeys);
|
|
4759
|
+
} else {
|
|
4760
|
+
;
|
|
4761
|
+
[result0, result1] = yield Promise.all([
|
|
4762
|
+
bundleModel0.getDatasetsForScenario(request.scenarioSpec0, request.datasetKeys),
|
|
4763
|
+
bundleModel1.getDatasetsForScenario(request.scenarioSpec1, request.datasetKeys)
|
|
4764
|
+
]);
|
|
4765
|
+
}
|
|
4766
|
+
const datasetReports = [];
|
|
4767
|
+
for (const datasetKey of request.datasetKeys) {
|
|
4768
|
+
const dataset0 = result0.datasetMap.get(datasetKey);
|
|
4769
|
+
const dataset1 = result1.datasetMap.get(datasetKey);
|
|
4770
|
+
const datasetReport = diffDatasets2(
|
|
4771
|
+
datasetKey,
|
|
4772
|
+
dataset0,
|
|
4773
|
+
dataset1,
|
|
4774
|
+
/*matchPrecisionOfLeft=*/
|
|
4775
|
+
false
|
|
4776
|
+
);
|
|
4777
|
+
datasetReports.push(datasetReport);
|
|
4778
|
+
}
|
|
4779
|
+
return datasetReports;
|
|
4780
|
+
});
|
|
4781
|
+
}
|
|
4782
|
+
function processCompareToExtDataRequest(request, bundleModels) {
|
|
4783
|
+
return __async(this, null, function* () {
|
|
4784
|
+
const bundleModel = request.bundleSide === "left" ? bundleModels.L : bundleModels.R;
|
|
4785
|
+
const resultR = yield bundleModel.getDatasetsForScenario(request.scenarioSpec, request.datasetKeys);
|
|
4786
|
+
const datasetReports = [];
|
|
4787
|
+
for (const datasetKey of request.datasetKeys) {
|
|
4788
|
+
let datasetL = request.extData.get(datasetKey);
|
|
4789
|
+
if (datasetL === void 0) {
|
|
4790
|
+
const datasetKeyParts = datasetKey.split("[");
|
|
4791
|
+
if (datasetKeyParts.length === 2) {
|
|
4792
|
+
const baseKey = datasetKeyParts[0];
|
|
4793
|
+
const keySubParts = datasetKeyParts[1].replace("]", "");
|
|
4794
|
+
const keySubIds = keySubParts.split(",");
|
|
4795
|
+
const subIdPermutations = permutationsOf(keySubIds);
|
|
4796
|
+
for (const subIds of subIdPermutations) {
|
|
4797
|
+
const datDatasetKey = `${baseKey}[${subIds.join(",")}]`;
|
|
4798
|
+
datasetL = request.extData.get(datDatasetKey);
|
|
4799
|
+
if (datasetL !== void 0) {
|
|
4800
|
+
break;
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
}
|
|
4804
|
+
if (datasetL === void 0) {
|
|
4805
|
+
console.warn(`WARNING: Failed to find data in dat file for key=${datasetKey}`);
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
const datasetR = resultR.datasetMap.get(datasetKey);
|
|
4809
|
+
const datasetReport = diffDatasets2(
|
|
4810
|
+
datasetKey,
|
|
4811
|
+
datasetL,
|
|
4812
|
+
datasetR,
|
|
4813
|
+
/*matchPrecisionOfLeft=*/
|
|
4814
|
+
true
|
|
4815
|
+
);
|
|
4816
|
+
datasetReports.push(datasetReport);
|
|
4817
|
+
}
|
|
4818
|
+
return datasetReports;
|
|
4819
|
+
});
|
|
4820
|
+
}
|
|
4821
|
+
function diffDatasets2(datasetKey, datasetL, datasetR, matchPrecisionOfLeft) {
|
|
4822
|
+
const points = /* @__PURE__ */ new Map();
|
|
4823
|
+
let minValueL = Number.MAX_VALUE;
|
|
4824
|
+
let maxValueL = Number.MIN_VALUE;
|
|
4825
|
+
let minValueR = Number.MAX_VALUE;
|
|
4826
|
+
let maxValueR = Number.MIN_VALUE;
|
|
4827
|
+
let minValue = Number.MAX_VALUE;
|
|
4828
|
+
let maxValue = Number.MIN_VALUE;
|
|
4829
|
+
let minRawDiff = Number.MAX_VALUE;
|
|
4830
|
+
let maxRawDiff = -1;
|
|
4831
|
+
let maxDiffPoint;
|
|
4832
|
+
let diffCount = 0;
|
|
4833
|
+
let totalRawDiff = 0;
|
|
4834
|
+
if (datasetL && datasetR) {
|
|
4835
|
+
const times = /* @__PURE__ */ new Set([...datasetL.keys(), ...datasetR.keys()]);
|
|
4836
|
+
for (const t of times) {
|
|
4837
|
+
const valueL = datasetL.get(t);
|
|
4838
|
+
if (valueL !== void 0) {
|
|
4839
|
+
if (valueL < minValueL) minValueL = valueL;
|
|
4840
|
+
if (valueL > maxValueL) maxValueL = valueL;
|
|
4841
|
+
if (valueL < minValue) minValue = valueL;
|
|
4842
|
+
if (valueL > maxValue) maxValue = valueL;
|
|
4843
|
+
}
|
|
4844
|
+
let valueR;
|
|
4845
|
+
const rawValueR = datasetR.get(t);
|
|
4846
|
+
if (rawValueR !== void 0) {
|
|
4847
|
+
if (matchPrecisionOfLeft && valueL !== void 0) {
|
|
4848
|
+
valueR = matchPrecision(rawValueR, valueL);
|
|
4849
|
+
} else {
|
|
4850
|
+
valueR = rawValueR;
|
|
4851
|
+
}
|
|
4852
|
+
if (valueR < minValueR) minValueR = valueR;
|
|
4853
|
+
if (valueR > maxValueR) maxValueR = valueR;
|
|
4854
|
+
if (valueR < minValue) minValue = valueR;
|
|
4855
|
+
if (valueR > maxValue) maxValue = valueR;
|
|
4856
|
+
}
|
|
4857
|
+
if (valueL === void 0 || valueR === void 0) {
|
|
4858
|
+
continue;
|
|
4859
|
+
}
|
|
4860
|
+
const point = {
|
|
4861
|
+
time: t,
|
|
4862
|
+
valueL,
|
|
4863
|
+
valueR
|
|
4864
|
+
};
|
|
4865
|
+
points.set(t, point);
|
|
4866
|
+
const rawDiff = Math.abs(valueR - valueL);
|
|
4867
|
+
if (rawDiff < minRawDiff) {
|
|
4868
|
+
minRawDiff = rawDiff;
|
|
4869
|
+
}
|
|
4870
|
+
if (rawDiff > maxRawDiff) {
|
|
4871
|
+
maxRawDiff = rawDiff;
|
|
4872
|
+
maxDiffPoint = point;
|
|
4873
|
+
}
|
|
4874
|
+
diffCount++;
|
|
4875
|
+
totalRawDiff += rawDiff;
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4878
|
+
function pct(x) {
|
|
4879
|
+
return x * 100;
|
|
4880
|
+
}
|
|
4881
|
+
let minDiff;
|
|
4882
|
+
let maxDiff;
|
|
4883
|
+
let avgDiff;
|
|
4884
|
+
if (minValueL === maxValueL && minValueR === maxValueR) {
|
|
4885
|
+
const diff = pct(maxValueL !== 0 ? Math.abs((maxValueR - maxValueL) / maxValueL) : 1);
|
|
4886
|
+
minDiff = diff;
|
|
4887
|
+
maxDiff = diff;
|
|
4888
|
+
avgDiff = diff;
|
|
4889
|
+
} else {
|
|
4890
|
+
const spread = maxValue - minValue;
|
|
4891
|
+
minDiff = pct(spread > 0 ? minRawDiff / spread : 0);
|
|
4892
|
+
maxDiff = pct(spread > 0 ? maxRawDiff / spread : 0);
|
|
4893
|
+
const avgRawDiff = totalRawDiff / diffCount;
|
|
4894
|
+
avgDiff = pct(spread > 0 ? avgRawDiff / spread : 0);
|
|
4895
|
+
}
|
|
4896
|
+
let validity;
|
|
4897
|
+
if (datasetL && datasetR) {
|
|
4898
|
+
validity = "both";
|
|
4899
|
+
} else if (datasetL) {
|
|
4900
|
+
validity = "left-only";
|
|
4901
|
+
} else if (datasetR) {
|
|
4902
|
+
validity = "right-only";
|
|
4903
|
+
} else {
|
|
4904
|
+
validity = "neither";
|
|
4905
|
+
}
|
|
4906
|
+
return {
|
|
4907
|
+
datasetKey,
|
|
4908
|
+
validity,
|
|
4909
|
+
points,
|
|
4910
|
+
minValue,
|
|
4911
|
+
maxValue,
|
|
4912
|
+
avgDiff,
|
|
4913
|
+
minDiff,
|
|
4914
|
+
maxDiff,
|
|
4915
|
+
maxDiffPoint
|
|
4916
|
+
};
|
|
4917
|
+
}
|
|
4918
|
+
function matchPrecision(x, baseline) {
|
|
4919
|
+
const s = baseline.toString();
|
|
4920
|
+
if (s.includes("e")) {
|
|
4921
|
+
return x;
|
|
4922
|
+
}
|
|
4923
|
+
const parts = s.split(".");
|
|
4924
|
+
if (parts.length < 2) {
|
|
4925
|
+
return x;
|
|
4926
|
+
}
|
|
4927
|
+
const sigDigits = parts[1].replace(/0+$/, "").length;
|
|
4928
|
+
if (sigDigits > 21) {
|
|
4929
|
+
return x;
|
|
4930
|
+
}
|
|
4931
|
+
return parseFloat(x.toFixed(sigDigits));
|
|
4932
|
+
}
|
|
4933
|
+
function permutationsOf(inputArr) {
|
|
4934
|
+
const result = [];
|
|
4935
|
+
const permute = (arr, m = []) => {
|
|
4936
|
+
if (arr.length === 0) {
|
|
4937
|
+
result.push(m);
|
|
4938
|
+
} else {
|
|
4939
|
+
for (let i = 0; i < arr.length; i++) {
|
|
4940
|
+
const curr = arr.slice();
|
|
4941
|
+
const next = curr.splice(i, 1);
|
|
4942
|
+
permute(curr.slice(), m.concat(next));
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
};
|
|
4946
|
+
permute(inputArr);
|
|
4947
|
+
return result;
|
|
4948
|
+
}
|
|
4949
|
+
|
|
4374
4950
|
// src/data/data-planner.ts
|
|
4375
4951
|
var DataPlanner = class {
|
|
4376
4952
|
/**
|
|
@@ -4557,10 +5133,10 @@ function scenarioPairUid(scenarioSpecL, scenarioSpecR) {
|
|
|
4557
5133
|
}
|
|
4558
5134
|
|
|
4559
5135
|
// src/check/check-runner.ts
|
|
4560
|
-
function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner,
|
|
4561
|
-
const modelSpec = checkConfig.bundle.
|
|
5136
|
+
function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, skipChecks) {
|
|
5137
|
+
const modelSpec = checkConfig.bundle.modelSpec;
|
|
4562
5138
|
const checkPlanner = new CheckPlanner(modelSpec);
|
|
4563
|
-
checkPlanner.addAllChecks(checkSpec,
|
|
5139
|
+
checkPlanner.addAllChecks(checkSpec, skipChecks);
|
|
4564
5140
|
const checkPlan = checkPlanner.buildPlan();
|
|
4565
5141
|
const refDatasets = /* @__PURE__ */ new Map();
|
|
4566
5142
|
for (const [dataRefKey, dataRef] of checkPlan.dataRefs.entries()) {
|
|
@@ -4573,11 +5149,15 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
|
|
|
4573
5149
|
}
|
|
4574
5150
|
const checkResults = /* @__PURE__ */ new Map();
|
|
4575
5151
|
for (const [checkKey, checkTask] of checkPlan.tasks.entries()) {
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
5152
|
+
if (checkTask.skip === true) {
|
|
5153
|
+
checkResults.set(checkKey, { status: "skipped" });
|
|
5154
|
+
} else {
|
|
5155
|
+
dataPlanner.addRequest(void 0, checkTask.scenario.spec, checkTask.dataset.datasetKey, (datasets) => {
|
|
5156
|
+
const dataset = datasets.datasetR;
|
|
5157
|
+
const checkResult = runCheck(checkTask, dataset, refDatasets);
|
|
5158
|
+
checkResults.set(checkKey, checkResult);
|
|
5159
|
+
});
|
|
5160
|
+
}
|
|
4581
5161
|
}
|
|
4582
5162
|
return () => {
|
|
4583
5163
|
return buildCheckReport(checkPlan, checkResults);
|
|
@@ -4642,21 +5222,73 @@ function runCheck(checkTask, dataset, refDatasets) {
|
|
|
4642
5222
|
}
|
|
4643
5223
|
|
|
4644
5224
|
// src/comparison/run/comparison-runner.ts
|
|
4645
|
-
function runComparisons(comparisonConfig, dataPlanner) {
|
|
5225
|
+
function runComparisons(comparisonConfig, dataPlanner, skipScenarios) {
|
|
5226
|
+
function skipScenarioKey(title, subtitle) {
|
|
5227
|
+
let key = title.toLowerCase();
|
|
5228
|
+
if (subtitle) {
|
|
5229
|
+
key += ` :: ${subtitle.toLowerCase()}`;
|
|
5230
|
+
}
|
|
5231
|
+
return key;
|
|
5232
|
+
}
|
|
5233
|
+
const skipScenariosSet = new Set(skipScenarios.map((scenario) => skipScenarioKey(scenario.title, scenario.subtitle)));
|
|
5234
|
+
const allScenarios = [...comparisonConfig.scenarios.getAllScenarios()];
|
|
5235
|
+
let baselineScenario;
|
|
5236
|
+
const baselineScenarioIndex = allScenarios.findIndex((scenario) => {
|
|
5237
|
+
const settings = scenario.settings;
|
|
5238
|
+
return settings.kind === "all-inputs-settings" && settings.position === "at-default";
|
|
5239
|
+
});
|
|
5240
|
+
if (baselineScenarioIndex !== -1) {
|
|
5241
|
+
baselineScenario = allScenarios.splice(baselineScenarioIndex, 1)[0];
|
|
5242
|
+
}
|
|
4646
5243
|
const testReports = [];
|
|
4647
|
-
|
|
5244
|
+
const baselineDiffReports = /* @__PURE__ */ new Map();
|
|
5245
|
+
function runComparisonsForScenario(scenario, isBaseline) {
|
|
4648
5246
|
const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
5247
|
+
const shouldSkip = skipScenariosSet.has(skipScenarioKey(scenario.title, scenario.subtitle));
|
|
5248
|
+
if (shouldSkip) {
|
|
5249
|
+
for (const datasetKey of datasetKeys) {
|
|
4652
5250
|
testReports.push({
|
|
4653
5251
|
scenarioKey: scenario.key,
|
|
4654
5252
|
datasetKey,
|
|
4655
|
-
diffReport
|
|
5253
|
+
diffReport: void 0
|
|
4656
5254
|
});
|
|
5255
|
+
}
|
|
5256
|
+
return;
|
|
5257
|
+
}
|
|
5258
|
+
for (const datasetKey of datasetKeys) {
|
|
5259
|
+
dataPlanner.addRequest(scenario.specL, scenario.specR, datasetKey, (datasets) => {
|
|
5260
|
+
const diffReport = diffDatasets(datasets.datasetL, datasets.datasetR);
|
|
5261
|
+
if (isBaseline) {
|
|
5262
|
+
baselineDiffReports.set(datasetKey, diffReport);
|
|
5263
|
+
testReports.push({
|
|
5264
|
+
scenarioKey: scenario.key,
|
|
5265
|
+
datasetKey,
|
|
5266
|
+
diffReport
|
|
5267
|
+
});
|
|
5268
|
+
} else {
|
|
5269
|
+
const baselineDiffReport = baselineDiffReports.get(datasetKey);
|
|
5270
|
+
testReports.push({
|
|
5271
|
+
scenarioKey: scenario.key,
|
|
5272
|
+
datasetKey,
|
|
5273
|
+
diffReport,
|
|
5274
|
+
baselineDiffReport
|
|
5275
|
+
});
|
|
5276
|
+
}
|
|
4657
5277
|
});
|
|
4658
5278
|
}
|
|
4659
5279
|
}
|
|
5280
|
+
runComparisonsForScenario(
|
|
5281
|
+
baselineScenario,
|
|
5282
|
+
/*isBaseline=*/
|
|
5283
|
+
true
|
|
5284
|
+
);
|
|
5285
|
+
for (const scenario of allScenarios) {
|
|
5286
|
+
runComparisonsForScenario(
|
|
5287
|
+
scenario,
|
|
5288
|
+
/*isBaseline=*/
|
|
5289
|
+
false
|
|
5290
|
+
);
|
|
5291
|
+
}
|
|
4660
5292
|
return () => {
|
|
4661
5293
|
return testReports;
|
|
4662
5294
|
};
|
|
@@ -4664,74 +5296,52 @@ function runComparisons(comparisonConfig, dataPlanner) {
|
|
|
4664
5296
|
|
|
4665
5297
|
// src/suite/suite-runner.ts
|
|
4666
5298
|
var SuiteRunner = class {
|
|
4667
|
-
constructor(config, callbacks) {
|
|
5299
|
+
constructor(config, taskQueue, callbacks) {
|
|
4668
5300
|
this.config = config;
|
|
5301
|
+
this.taskQueue = taskQueue;
|
|
4669
5302
|
this.callbacks = callbacks;
|
|
4670
5303
|
this.perfStatsL = new PerfStats();
|
|
4671
5304
|
this.perfStatsR = new PerfStats();
|
|
5305
|
+
this.pendingTaskKeys = /* @__PURE__ */ new Set();
|
|
4672
5306
|
this.stopped = false;
|
|
4673
|
-
this.taskQueue = new TaskQueue({
|
|
4674
|
-
process: (request) => {
|
|
4675
|
-
return this.processRequest(request);
|
|
4676
|
-
}
|
|
4677
|
-
});
|
|
4678
5307
|
}
|
|
4679
5308
|
cancel() {
|
|
4680
5309
|
if (!this.stopped) {
|
|
5310
|
+
for (const taskKey of this.pendingTaskKeys) {
|
|
5311
|
+
this.taskQueue.cancelTask(taskKey);
|
|
5312
|
+
}
|
|
4681
5313
|
this.stopped = true;
|
|
4682
|
-
this.taskQueue.shutdown();
|
|
4683
5314
|
}
|
|
4684
5315
|
}
|
|
4685
5316
|
start(options) {
|
|
4686
5317
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4687
5318
|
(_b = (_a = this.callbacks).onProgress) == null ? void 0 : _b.call(_a, 0);
|
|
4688
|
-
const
|
|
4689
|
-
const dataPlanner = new DataPlanner(
|
|
4690
|
-
const refDataPlanner = new DataPlanner(
|
|
5319
|
+
const modelSpecR = this.config.check.bundle.modelSpec;
|
|
5320
|
+
const dataPlanner = new DataPlanner(modelSpecR.outputVars.size);
|
|
5321
|
+
const refDataPlanner = new DataPlanner(modelSpecR.outputVars.size);
|
|
4691
5322
|
const checkSpecResult = parseTestYaml(this.config.check.tests);
|
|
4692
5323
|
if (checkSpecResult.isErr()) {
|
|
4693
5324
|
(_d = (_c = this.callbacks).onError) == null ? void 0 : _d.call(_c, checkSpecResult.error);
|
|
4694
5325
|
return;
|
|
4695
5326
|
}
|
|
4696
5327
|
const checkSpec = checkSpecResult.value;
|
|
4697
|
-
const
|
|
4698
|
-
const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner,
|
|
5328
|
+
const skipChecks = (options == null ? void 0 : options.skipChecks) || [];
|
|
5329
|
+
const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner, skipChecks);
|
|
4699
5330
|
let buildComparisonTestReports;
|
|
4700
5331
|
if (this.config.comparison) {
|
|
4701
|
-
|
|
5332
|
+
const skipScenarios = (options == null ? void 0 : options.skipComparisonScenarios) || [];
|
|
5333
|
+
buildComparisonTestReports = runComparisons(this.config.comparison, dataPlanner, skipScenarios);
|
|
4702
5334
|
}
|
|
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
5335
|
const refDataPlan = refDataPlanner.buildPlan();
|
|
4727
5336
|
const dataPlan = dataPlanner.buildPlan();
|
|
4728
5337
|
const dataRequests = [...refDataPlan.requests, ...dataPlan.requests];
|
|
4729
5338
|
const taskCount = dataRequests.length;
|
|
4730
5339
|
if (taskCount === 0) {
|
|
5340
|
+
const checkReport = buildCheckReport2();
|
|
4731
5341
|
let comparisonReport;
|
|
4732
5342
|
if (this.config.comparison) {
|
|
4733
5343
|
comparisonReport = {
|
|
4734
|
-
testReports:
|
|
5344
|
+
testReports: buildComparisonTestReports(),
|
|
4735
5345
|
perfReportL: this.perfStatsL.toReport(),
|
|
4736
5346
|
perfReportR: this.perfStatsR.toReport()
|
|
4737
5347
|
};
|
|
@@ -4739,26 +5349,54 @@ var SuiteRunner = class {
|
|
|
4739
5349
|
this.cancel();
|
|
4740
5350
|
(_f = (_e = this.callbacks).onProgress) == null ? void 0 : _f.call(_e, 1);
|
|
4741
5351
|
(_h = (_g = this.callbacks).onComplete) == null ? void 0 : _h.call(_g, {
|
|
4742
|
-
checkReport
|
|
4743
|
-
groups: []
|
|
4744
|
-
},
|
|
5352
|
+
checkReport,
|
|
4745
5353
|
comparisonReport
|
|
4746
5354
|
});
|
|
4747
5355
|
return;
|
|
4748
5356
|
}
|
|
5357
|
+
const buildReport = (error) => {
|
|
5358
|
+
var _a2, _b2, _c2, _d2;
|
|
5359
|
+
if (error) {
|
|
5360
|
+
(_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
|
|
5361
|
+
} else {
|
|
5362
|
+
const checkReport = buildCheckReport2();
|
|
5363
|
+
let comparisonReport;
|
|
5364
|
+
if (this.config.comparison) {
|
|
5365
|
+
comparisonReport = {
|
|
5366
|
+
testReports: buildComparisonTestReports(),
|
|
5367
|
+
perfReportL: this.perfStatsL.toReport(),
|
|
5368
|
+
perfReportR: this.perfStatsR.toReport()
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
(_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
|
|
5372
|
+
checkReport,
|
|
5373
|
+
comparisonReport
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
5376
|
+
};
|
|
4749
5377
|
let tasksCompleted = 0;
|
|
4750
5378
|
let dataTaskId = 1;
|
|
4751
5379
|
for (const dataRequest of dataRequests) {
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
(
|
|
4756
|
-
|
|
5380
|
+
const task = {
|
|
5381
|
+
key: `suite-runner-${dataTaskId++}`,
|
|
5382
|
+
kind: "suite-runner",
|
|
5383
|
+
process: (bundleModels) => __async(this, null, function* () {
|
|
5384
|
+
var _a2, _b2;
|
|
5385
|
+
this.pendingTaskKeys.delete(task.key);
|
|
5386
|
+
yield this.processRequest(dataRequest, bundleModels);
|
|
5387
|
+
tasksCompleted++;
|
|
5388
|
+
(_b2 = (_a2 = this.callbacks).onProgress) == null ? void 0 : _b2.call(_a2, tasksCompleted / taskCount);
|
|
5389
|
+
if (tasksCompleted === taskCount) {
|
|
5390
|
+
buildReport();
|
|
5391
|
+
}
|
|
5392
|
+
})
|
|
5393
|
+
};
|
|
5394
|
+
this.taskQueue.addTask(task);
|
|
5395
|
+
this.pendingTaskKeys.add(task.key);
|
|
4757
5396
|
}
|
|
4758
5397
|
}
|
|
4759
|
-
processRequest(request) {
|
|
5398
|
+
processRequest(request, bundleModels) {
|
|
4760
5399
|
return __async(this, null, function* () {
|
|
4761
|
-
var _a, _b;
|
|
4762
5400
|
const datasetKeySet = /* @__PURE__ */ new Set();
|
|
4763
5401
|
for (const dataTask of request.dataTasks) {
|
|
4764
5402
|
datasetKeySet.add(dataTask.datasetKey);
|
|
@@ -4773,8 +5411,8 @@ var SuiteRunner = class {
|
|
|
4773
5411
|
}
|
|
4774
5412
|
});
|
|
4775
5413
|
}
|
|
4776
|
-
const bundleModelL =
|
|
4777
|
-
const bundleModelR =
|
|
5414
|
+
const bundleModelL = bundleModels.L;
|
|
5415
|
+
const bundleModelR = bundleModels.R;
|
|
4778
5416
|
const [datasetsResultL, datasetsResultR] = yield Promise.all([
|
|
4779
5417
|
getDatasets(bundleModelL, request.scenarioSpecL),
|
|
4780
5418
|
getDatasets(bundleModelR, request.scenarioSpecR)
|
|
@@ -4798,22 +5436,29 @@ var SuiteRunner = class {
|
|
|
4798
5436
|
});
|
|
4799
5437
|
}
|
|
4800
5438
|
};
|
|
4801
|
-
function
|
|
4802
|
-
const suiteRunner = new SuiteRunner(config, callbacks);
|
|
5439
|
+
function runSuiteWithTaskQueue(config, taskQueue, callbacks, options) {
|
|
5440
|
+
const suiteRunner = new SuiteRunner(config, taskQueue, callbacks);
|
|
4803
5441
|
suiteRunner.start(options);
|
|
4804
5442
|
return () => {
|
|
4805
5443
|
suiteRunner.cancel();
|
|
4806
5444
|
};
|
|
4807
5445
|
}
|
|
5446
|
+
function runSuite(config, callbacks, options) {
|
|
5447
|
+
const taskQueue = TaskQueue.getInstance();
|
|
5448
|
+
return runSuiteWithTaskQueue(config, taskQueue, callbacks, options);
|
|
5449
|
+
}
|
|
4808
5450
|
|
|
4809
5451
|
// src/suite/suite-reporting.ts
|
|
4810
|
-
function suiteSummaryFromReport(suiteReport) {
|
|
5452
|
+
function suiteSummaryFromReport(suiteReport, elapsedMillis) {
|
|
4811
5453
|
const checkSummary = checkSummaryFromReport(suiteReport.checkReport);
|
|
4812
5454
|
let comparisonSummary;
|
|
4813
5455
|
if (suiteReport.comparisonReport) {
|
|
4814
5456
|
comparisonSummary = comparisonSummaryFromReport(suiteReport.comparisonReport);
|
|
4815
5457
|
}
|
|
5458
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
4816
5459
|
return {
|
|
5460
|
+
date,
|
|
5461
|
+
elapsed: elapsedMillis,
|
|
4817
5462
|
checkSummary,
|
|
4818
5463
|
comparisonSummary
|
|
4819
5464
|
};
|
|
@@ -4821,20 +5466,27 @@ function suiteSummaryFromReport(suiteReport) {
|
|
|
4821
5466
|
export {
|
|
4822
5467
|
CheckDataCoordinator,
|
|
4823
5468
|
ComparisonDataCoordinator,
|
|
4824
|
-
PerfRunner,
|
|
4825
5469
|
PerfStats,
|
|
4826
5470
|
categorizeComparisonTestSummaries,
|
|
4827
5471
|
checkReportFromSummary,
|
|
4828
5472
|
checkSummaryFromReport,
|
|
4829
5473
|
comparisonSummaryFromReport,
|
|
5474
|
+
createCheckDataCoordinator,
|
|
5475
|
+
createCheckDataCoordinatorForTests,
|
|
5476
|
+
createComparisonDataCoordinator,
|
|
4830
5477
|
createConfig,
|
|
4831
5478
|
datasetMessage,
|
|
5479
|
+
decodeImplVars,
|
|
4832
5480
|
diffDatasets,
|
|
4833
5481
|
diffGraphs,
|
|
5482
|
+
encodeImplVars,
|
|
4834
5483
|
getScoresForTestSummaries,
|
|
4835
5484
|
predicateMessage,
|
|
5485
|
+
runPerf,
|
|
4836
5486
|
runSuite,
|
|
5487
|
+
runTrace,
|
|
4837
5488
|
scenarioMessage,
|
|
4838
|
-
suiteSummaryFromReport
|
|
5489
|
+
suiteSummaryFromReport,
|
|
5490
|
+
testSummaryFromReport
|
|
4839
5491
|
};
|
|
4840
5492
|
//# sourceMappingURL=index.js.map
|