@mark1russell7/harness 0.15.0 → 0.15.2
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/build/{cell-biffSiEJ.d.ts → cell-OwQdpSkd.d.ts} +9 -2
- package/build/{image-BxVTFZ1o.js → image-B8yh_FF7.js} +9 -2
- package/build/{image-BxVTFZ1o.js.map → image-B8yh_FF7.js.map} +1 -1
- package/build/index.d.ts +61 -4
- package/build/index.js +134 -25
- package/build/index.js.map +1 -1
- package/build/schema.d.ts +1 -1
- package/build/schema.js +1 -1
- package/image/native/src/bin/client.rs +64 -2
- package/package.json +2 -2
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as ProxyHop, A as ImageSource, At as Subject, B as LoadStream, C as Hop, Ct as RunTopology, D as HopWrite, Dt as ShippedImage, E as HopSignal, Et as Shipped, F as LineCount, Ft as
|
|
1
|
+
import { $ as ProxyHop, A as ImageSource, At as Subject, B as LoadStream, C as Hop, Ct as RunTopology, D as HopWrite, Dt as ShippedImage, E as HopSignal, Et as Shipped, F as LineCount, Ft as environmentProblems, G as Outcomes, H as MiddleboxExpectation, I as LineMatch, It as isHopPlace, J as PausePrediction, K as Pair, L as LoadBand, Lt as latestEndOf, M as Kafka, Mt as Topology, N as KafkaPause, Nt as Toxic, O as HostSysctl, Ot as Stage, P as KernelRecord, Pt as WsProbe, Q as ProbeEvent, R as LoadPlan, S as GroupRole, St as RunStream, T as HopPlace, Tt as SentinelStage, U as MiddleboxForm, V as MiddleboxEvent, W as Observer, X as PortsPrediction, Y as PinnedImage, Z as Prediction, _ as Fault, _t as RunFabric, a as ClientCapability, at as Reconnects, b as GroupPlace, bt as RunPause, c as ClusterClientAt, ct as ReplicaSet, d as CountBand, dt as RequestPrediction, et as ProxyTime, f as Drill, ft as RouterHop, g as FabricManifest, gt as RunDrill, h as Fabric, ht as RunBackup, i as Client, it as QueuePrediction, j as Jitter, jt as Target, k as HttpProbe, kt as StageBand, l as ClusterStage, lt as ReplicaSetStage, m as DriverStep, mt as Run, n as CLIENT_CAPABILITIES, nt as QueueConnection, o as ClientImage, ot as Recovers, p as DriverBand, pt as RttRange, q as PauseBand, r as Cell, rt as QueueEnd, s as Cluster, st as Reference, t as BuildImage, tt as QueueBand, u as ConntrackPrediction, ut as Replies, v as FaultPlace, vt as RunGroup, w as HopEvent, wt as SentinelEvent, x as GroupPrediction, xt as RunRoute, y as Group, yt as RunPart, z as LoadPrediction } from "./cell-OwQdpSkd.js";
|
|
2
2
|
import { Quantity } from "@mark1russell7/quantity";
|
|
3
3
|
import { LoadMeasure, Schedule } from "@mark1russell7/rigor-chaos";
|
|
4
4
|
import { StartedTestContainer } from "testcontainers";
|
|
@@ -181,6 +181,35 @@ export declare const streamsLoadOf: (events: readonly ProbeEvent[], streams: rea
|
|
|
181
181
|
readonly pool: RunLoad;
|
|
182
182
|
readonly streams: Readonly<Record<string, RunLoad>>;
|
|
183
183
|
} | null;
|
|
184
|
+
/** This function gives the pool of some measures: it sums the counts and joins the times, in the order of the measures. */
|
|
185
|
+
export declare const poolOf: (measures: readonly RunLoad[]) => RunLoad & {
|
|
186
|
+
readonly failed: number;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* This time is the tolerance of a closed-loop estimate, in ms. A send later than its expected time
|
|
190
|
+
* by more than this tolerance is a pause of the client: a driver gap.
|
|
191
|
+
*/
|
|
192
|
+
export declare const CLOSED_TOLERANCE = 5;
|
|
193
|
+
/**
|
|
194
|
+
* A run estimate is the latency of the open loop that a closed-loop stream hid (SYS-91). The package
|
|
195
|
+
* rigor-chaos puts back each send that a stall or a pause of the client hid (`closedLoopPlan`).
|
|
196
|
+
* `hidden` counts those sends, and `driverGaps` counts the pauses of the client. Its times are in ms.
|
|
197
|
+
*/
|
|
198
|
+
type RunEstimate = LoadMeasure & {
|
|
199
|
+
readonly hidden: number;
|
|
200
|
+
readonly driverGaps: number;
|
|
201
|
+
readonly driverGapTotal: number;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* This function gives the estimate of one closed-loop stream from its requests, in the order of their
|
|
205
|
+
* sends. Each time is a time of a line of the client. The client waits `interval` ms after each reply,
|
|
206
|
+
* thus the interval is also the pause of the driver. The function gives undefined for no request, and
|
|
207
|
+
* for a request with no reply before the last request.
|
|
208
|
+
*/
|
|
209
|
+
export declare const estimateOf: (requests: ReadonlyArray<{
|
|
210
|
+
readonly sent: number;
|
|
211
|
+
readonly done: number | null;
|
|
212
|
+
}>, end: number, interval: number) => RunEstimate | undefined;
|
|
184
213
|
/** A load spread is a part of the distribution of one measure of an open-loop cell, over its counted runs. */
|
|
185
214
|
interface LoadSpread {
|
|
186
215
|
readonly p50: Quantity;
|
|
@@ -224,6 +253,22 @@ export declare const loadVerdict: (prediction: LoadPrediction, runs: ReadonlyArr
|
|
|
224
253
|
readonly name: string;
|
|
225
254
|
readonly load: RunLoad | undefined;
|
|
226
255
|
}>) => LoadJudgement;
|
|
256
|
+
/**
|
|
257
|
+
* An estimate verdict sums the closed-loop estimates of a cell over its counted runs. Its latency
|
|
258
|
+
* is an estimate of the open loop, not a measure of it: a record of an open-loop client stays the
|
|
259
|
+
* better measure. Each hidden send after a request with no reply counts at its age at the end.
|
|
260
|
+
*/
|
|
261
|
+
interface EstimateVerdict {
|
|
262
|
+
readonly planned: number;
|
|
263
|
+
readonly hidden: number;
|
|
264
|
+
readonly driverGaps: number;
|
|
265
|
+
readonly driverGapTotal: Quantity;
|
|
266
|
+
readonly latency: LoadSpread | null;
|
|
267
|
+
/** This text gives the estimate in words, for the verdict of the cell. */
|
|
268
|
+
readonly words: string;
|
|
269
|
+
}
|
|
270
|
+
/** This function gives the estimate verdict of the counted runs, or undefined when no run has an estimate. */
|
|
271
|
+
export declare const estimateVerdict: (estimates: ReadonlyArray<RunEstimate | undefined>) => EstimateVerdict | undefined;
|
|
227
272
|
//#endregion
|
|
228
273
|
//#region src/driver.d.ts
|
|
229
274
|
/**
|
|
@@ -785,6 +830,8 @@ interface Verdict {
|
|
|
785
830
|
readonly reordering?: Reordering;
|
|
786
831
|
/** This record is the load of an open-loop cell over its counted runs. */
|
|
787
832
|
readonly load?: LoadVerdict;
|
|
833
|
+
/** This record is the estimate of the open loop of a closed-loop stream over its counted runs (SYS-91). */
|
|
834
|
+
readonly estimate?: EstimateVerdict;
|
|
788
835
|
/** This record is the time of the proxy of a calibration cell, in each direction. */
|
|
789
836
|
readonly proxy?: {
|
|
790
837
|
readonly hop: string;
|
|
@@ -974,6 +1021,8 @@ interface Measured {
|
|
|
974
1021
|
readonly samples?: readonly Quantity[];
|
|
975
1022
|
/** This measure is the run of an open-loop cell against its schedule (`Run.schedule`), with its failed replies. Its times are in ms. */
|
|
976
1023
|
readonly load?: RunLoad;
|
|
1024
|
+
/** This estimate is the open loop that a closed-loop stream of the client of the harness hid (SYS-91). Its times are in ms. */
|
|
1025
|
+
readonly estimate?: RunEstimate;
|
|
977
1026
|
/** This count is the number of keepalive probes that the kernel sent. */
|
|
978
1027
|
readonly probes: number;
|
|
979
1028
|
/** This count is the number of segments that the kernel sent again. */
|
|
@@ -1415,9 +1464,11 @@ export declare const targetImageOf: (target: Target) => Promise<string>;
|
|
|
1415
1464
|
* A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this
|
|
1416
1465
|
* time.
|
|
1417
1466
|
*/
|
|
1418
|
-
|
|
1467
|
+
export declare const LAYERS: readonly ["E0", "E1", "E2", "E3", "E4", "E5", "E6"];
|
|
1468
|
+
type Layer = (typeof LAYERS)[number];
|
|
1419
1469
|
/** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */
|
|
1420
|
-
|
|
1470
|
+
export declare const CLOUDS: readonly ["azure", "aws", "unknown"];
|
|
1471
|
+
type Cloud = (typeof CLOUDS)[number];
|
|
1421
1472
|
/** A host is what a process reads about its own machine. */
|
|
1422
1473
|
interface Host {
|
|
1423
1474
|
/** This text is the kernel release. */
|
|
@@ -2650,6 +2701,12 @@ export declare const QUIET_MS = 250;
|
|
|
2650
2701
|
export declare const LINGER_MS = 1e3;
|
|
2651
2702
|
/** This function divides a count of runs across environments, as equally as possible. */
|
|
2652
2703
|
export declare const spread: (runs: number, environments: number) => number[];
|
|
2704
|
+
/**
|
|
2705
|
+
* This function gives the count of runs of each new environment of a cell, for `runs` more runs. A
|
|
2706
|
+
* pair cell has an environment for each run, because its run promotes the standby. Other cells
|
|
2707
|
+
* go across their environments, and at least one for each environment at the same time.
|
|
2708
|
+
*/
|
|
2709
|
+
export declare const environmentCounts: (cell: Cell, runs: number) => number[];
|
|
2653
2710
|
/**
|
|
2654
2711
|
* This function does the runs of a cell. They go across new environments, and each environment records
|
|
2655
2712
|
* its manifest. Then the verdict judges the runs. A median across the edge of the band extends
|
|
@@ -2661,5 +2718,5 @@ export declare const spread: (runs: number, environments: number) => number[];
|
|
|
2661
2718
|
*/
|
|
2662
2719
|
export declare const runCell: (cell: Cell, say?: (line: string) => void) => Promise<CellResult>;
|
|
2663
2720
|
//#endregion
|
|
2664
|
-
export { type Agent, type BuildImage, type BuildRecord, CLIENT_CAPABILITIES, type CallReading, type Cell, type CellResult, type Client, type ClientCapability, type ClientImage, type ClockPair, type Cloud, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type ConntrackPrediction, type ConntrackReading, type ContextFile, type CountBand, type Crossings, type Cut, type Decision, type Drill, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type Fabric, type FabricLab, type FabricManifest, type FabricParts, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type Host, type HostSetting, type HostSysctl, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type Jitter, type Kafka, type KafkaLab, type KafkaMember, type KafkaPause, type KernelRecord, type Lab, type Layer, type LeafViews, type LineCount, type LineMatch, type LoadBand, type LoadJudgement, type LoadPlan, type LoadPrediction, type LoadSpread, type LoadStream, type LoadVerdict, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type OplogRead, type OplogTime, type Outcome, type Outcomes, type Pair, type PairSets, type Pairing, type PartitionView, type PauseBand, type PauseCommit, type PausePrediction, type PauseReading, type Pinnable, type PinnedImage, type PortsPrediction, type PortsReading, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type QueueBand, type QueueConnection, type QueueConnectionReading, type QueueEnd, type QueuePrediction, type QueueReading, type ReconnectReading, type ReconnectVerdict, type Reconnects, type RecordCode, type Recovers, type RecoveryMeasured, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouteLine, type RouterHop, type RttRange, type Run, type RunBackup, type RunDrill, type RunFabric, type RunGroup, type RunLoad, type RunPart, type RunPause, type RunRoute, type RunStream, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type Sibling, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type StallReading, type Stamp, type Status, type StatusRow, type Subject, type Substrate, type SubstrateSource, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
|
|
2721
|
+
export { type Agent, type BuildImage, type BuildRecord, CLIENT_CAPABILITIES, type CallReading, type Cell, type CellResult, type Client, type ClientCapability, type ClientImage, type ClockPair, type Cloud, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type ConntrackPrediction, type ConntrackReading, type ContextFile, type CountBand, type Crossings, type Cut, type Decision, type Drill, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type EstimateVerdict, type Fabric, type FabricLab, type FabricManifest, type FabricParts, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type Host, type HostSetting, type HostSysctl, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type Jitter, type Kafka, type KafkaLab, type KafkaMember, type KafkaPause, type KernelRecord, type Lab, type Layer, type LeafViews, type LineCount, type LineMatch, type LoadBand, type LoadJudgement, type LoadPlan, type LoadPrediction, type LoadSpread, type LoadStream, type LoadVerdict, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type OplogRead, type OplogTime, type Outcome, type Outcomes, type Pair, type PairSets, type Pairing, type PartitionView, type PauseBand, type PauseCommit, type PausePrediction, type PauseReading, type Pinnable, type PinnedImage, type PortsPrediction, type PortsReading, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type QueueBand, type QueueConnection, type QueueConnectionReading, type QueueEnd, type QueuePrediction, type QueueReading, type ReconnectReading, type ReconnectVerdict, type Reconnects, type RecordCode, type Recovers, type RecoveryMeasured, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouteLine, type RouterHop, type RttRange, type Run, type RunBackup, type RunDrill, type RunEstimate, type RunFabric, type RunGroup, type RunLoad, type RunPart, type RunPause, type RunRoute, type RunStream, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type Sibling, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type StallReading, type Stamp, type Status, type StatusRow, type Subject, type Substrate, type SubstrateSource, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, environmentProblems, isHopPlace, latestEndOf };
|
|
2665
2722
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as unlockedManifests, B as
|
|
1
|
+
import { A as unlockedManifests, B as environmentProblems, C as programOf, D as subjectProblems, E as subjectClient, F as jarVersions, H as latestEndOf, I as locksOf, L as npmVersions, M as LOCK_NAMES, N as cargoVersions, O as targetImageOf, P as goVersions, R as versionsOf, S as planOf, T as shippedSource, U as requestFirst, V as isHopPlace, _ as kafkaClientImage, a as SHIPPED_NAMES, b as nodeHttpImage, c as buildRecordOf, d as harnessImage, f as harnessVersion, g as inContext, h as imageProblems, i as SHIPPED_CLIENTS, j as unpinnedBases, k as targetSourceOf, l as goHttpImage, m as imageOf, n as PINNED, o as amqpClientImage, p as hikariClientImage, r as REPOSITORY, s as basesOf, t as CLIENT_NAMES, u as grpcClientImage, v as mongoClientImage, w as routerImage, x as pgClientImage, y as nodeClientImage, z as CLIENT_CAPABILITIES } from "./image-B8yh_FF7.js";
|
|
2
2
|
import { quantity, valueIn } from "@mark1russell7/quantity";
|
|
3
3
|
import { median, medianInterval as medianInterval$1, quantile, quantileSorted } from "@mark1russell7/rigor-statistics";
|
|
4
4
|
import { rungVerdict } from "@mark1russell7/rigor-bench";
|
|
5
|
-
import { measureLoad, schedule, scheduleHeld } from "@mark1russell7/rigor-chaos";
|
|
5
|
+
import { closedLoopPlan, measureLoad, schedule, scheduleHeld } from "@mark1russell7/rigor-chaos";
|
|
6
6
|
import { createHash, randomBytes } from "node:crypto";
|
|
7
7
|
import { execFile } from "node:child_process";
|
|
8
8
|
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
@@ -99,21 +99,56 @@ const streamsLoadOf = (events, streams) => {
|
|
|
99
99
|
const start = events.find((event) => event.ev === "scheduled")?.t;
|
|
100
100
|
if (start === void 0) return null;
|
|
101
101
|
const each = streams.map((stream) => [stream.key, measureOf(events, start, stream.schedule, stream.key)]);
|
|
102
|
-
|
|
102
|
+
return {
|
|
103
|
+
pool: poolOf(each.map(([, measure]) => measure)),
|
|
104
|
+
streams: Object.fromEntries(each)
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/** This function gives the pool of some measures: it sums the counts and joins the times, in the order of the measures. */
|
|
108
|
+
const poolOf = (measures) => {
|
|
103
109
|
const sum = (count) => measures.reduce((total, measure) => total + count(measure), 0);
|
|
104
110
|
const join = (times) => measures.flatMap(times);
|
|
105
111
|
return {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
planned: sum((measure) => measure.planned),
|
|
113
|
+
unsent: sum((measure) => measure.unsent),
|
|
114
|
+
unfinished: sum((measure) => measure.unfinished),
|
|
115
|
+
failed: sum((measure) => measure.failed ?? 0),
|
|
116
|
+
latency: join((measure) => measure.latency),
|
|
117
|
+
service: join((measure) => measure.service),
|
|
118
|
+
lag: join((measure) => measure.lag),
|
|
119
|
+
censored: join((measure) => measure.censored)
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* This time is the tolerance of a closed-loop estimate, in ms. A send later than its expected time
|
|
124
|
+
* by more than this tolerance is a pause of the client: a driver gap.
|
|
125
|
+
*/
|
|
126
|
+
const CLOSED_TOLERANCE = 5;
|
|
127
|
+
/**
|
|
128
|
+
* This function gives the estimate of one closed-loop stream from its requests, in the order of their
|
|
129
|
+
* sends. Each time is a time of a line of the client. The client waits `interval` ms after each reply,
|
|
130
|
+
* thus the interval is also the pause of the driver. The function gives undefined for no request, and
|
|
131
|
+
* for a request with no reply before the last request.
|
|
132
|
+
*/
|
|
133
|
+
const estimateOf = (requests, end, interval) => {
|
|
134
|
+
const start = requests[0]?.sent;
|
|
135
|
+
if (start === void 0 || requests.slice(0, -1).some((request) => request.done === null)) return void 0;
|
|
136
|
+
const loop = requests.map((request) => ({
|
|
137
|
+
sent: fromStart(start, request.sent),
|
|
138
|
+
done: request.done === null ? null : fromStart(start, request.done)
|
|
139
|
+
}));
|
|
140
|
+
const stop = Math.max(fromStart(start, end), ...loop.map((request) => request.done ?? request.sent), interval);
|
|
141
|
+
const run = closedLoopPlan(loop, {
|
|
142
|
+
interval,
|
|
143
|
+
end: stop,
|
|
144
|
+
tolerance: 5,
|
|
145
|
+
pause: interval
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
...measureLoad(run.plan, run.completions, stop),
|
|
149
|
+
hidden: run.hidden,
|
|
150
|
+
driverGaps: run.driverGaps,
|
|
151
|
+
driverGapTotal: run.driverGapTotal
|
|
117
152
|
};
|
|
118
153
|
};
|
|
119
154
|
/** This function gives the spread of a list of times in ms, or null for no time. */
|
|
@@ -246,6 +281,28 @@ const loadVerdict = (prediction, runs) => {
|
|
|
246
281
|
}
|
|
247
282
|
};
|
|
248
283
|
};
|
|
284
|
+
/** This function gives the estimate verdict of the counted runs, or undefined when no run has an estimate. */
|
|
285
|
+
const estimateVerdict = (estimates) => {
|
|
286
|
+
const runs = estimates.filter((estimate) => estimate !== void 0);
|
|
287
|
+
if (runs.length === 0) return void 0;
|
|
288
|
+
const pool = poolOf(runs);
|
|
289
|
+
const total = (count) => runs.reduce((sum, estimate) => sum + count(estimate), 0);
|
|
290
|
+
const hidden = total((estimate) => estimate.hidden);
|
|
291
|
+
const driverGaps = total((estimate) => estimate.driverGaps);
|
|
292
|
+
const driverGapTotal = total((estimate) => estimate.driverGapTotal);
|
|
293
|
+
const latency = spreadOf$1([...pool.latency, ...pool.censored]);
|
|
294
|
+
const seconds = (time) => (valueIn(time, "ms") / 1e3).toFixed(3);
|
|
295
|
+
const spread = latency === null ? "no latency" : `median ${seconds(latency.p50)} s, p99 ${seconds(latency.p99)} s, slowest ${seconds(latency.max)} s`;
|
|
296
|
+
const gaps = driverGaps === 0 ? "no pause of the client" : `${driverGaps} pauses of the client, ${Math.round(driverGapTotal)} ms in all`;
|
|
297
|
+
return {
|
|
298
|
+
planned: pool.planned,
|
|
299
|
+
hidden,
|
|
300
|
+
driverGaps,
|
|
301
|
+
driverGapTotal: quantity(driverGapTotal, "ms"),
|
|
302
|
+
latency,
|
|
303
|
+
words: `The estimate of the open loop puts back ${hidden} hidden sends, with ${gaps}: ${spread}.`
|
|
304
|
+
};
|
|
305
|
+
};
|
|
249
306
|
//#endregion
|
|
250
307
|
//#region src/verdict.ts
|
|
251
308
|
/** This function gives the words of the outcome of a second request: its connection, a retry, and its end. */
|
|
@@ -687,7 +744,9 @@ const verdictOfBand = (prediction, runs, delta = NOISE) => {
|
|
|
687
744
|
reordering.fast,
|
|
688
745
|
reordering.seen
|
|
689
746
|
].some((count) => (count ?? 0) > 0) ? ` Reordering: ${reorderingWords(reordering)}.` : "";
|
|
690
|
-
const
|
|
747
|
+
const estimate = estimateVerdict(counted.map((run) => run.estimate));
|
|
748
|
+
const estimated = estimate === void 0 ? "" : ` ${estimate.words}`;
|
|
749
|
+
const why = samples.length === 0 ? `${counted.length} runs measured, with no reply: ${prediction.why}` : `${counted.length} runs, ${samples.length} replies: median ${s(median(samples)).value} s, p99 ${s(quantileOf(samples, .99)).value} s, slowest ${s(samples.at(-1)).value} s, ${retransmissions} retransmissions, ${ended.length} connections ended.${reordered}${estimated} ${prediction.why}`;
|
|
691
750
|
return {
|
|
692
751
|
...empty,
|
|
693
752
|
decision: "measured",
|
|
@@ -696,6 +755,7 @@ const verdictOfBand = (prediction, runs, delta = NOISE) => {
|
|
|
696
755
|
median: samples.length === 0 ? null : s(median(samples)),
|
|
697
756
|
...samples.length === 0 ? {} : { slowest: s(samples.at(-1)) },
|
|
698
757
|
...reordering === void 0 ? {} : { reordering },
|
|
758
|
+
...estimate === void 0 ? {} : { estimate },
|
|
699
759
|
why
|
|
700
760
|
};
|
|
701
761
|
}
|
|
@@ -3019,11 +3079,18 @@ const measureSocket = (cell, run) => {
|
|
|
3019
3079
|
};
|
|
3020
3080
|
const sends = load === void 0 ? events.filter((event) => event.ev === "sent").slice(1) : [];
|
|
3021
3081
|
const answers = events.some((event) => event.ev === "replied") ? "replied" : "data";
|
|
3022
|
-
const
|
|
3082
|
+
const requests = sends.map((send, n) => {
|
|
3023
3083
|
const next = sends[n + 1]?.t ?? Infinity;
|
|
3024
|
-
|
|
3025
|
-
|
|
3084
|
+
return {
|
|
3085
|
+
send,
|
|
3086
|
+
reply: events.find((event) => event.ev === answers && event.t > send.t && event.t < next)
|
|
3087
|
+
};
|
|
3026
3088
|
});
|
|
3089
|
+
const samples = requests.flatMap(({ send, reply }) => reply === void 0 ? [] : [between(send.t, reply.t)]);
|
|
3090
|
+
const estimate = cell.probe.mode === "stream" && cell.probe.driver === void 0 && cell.probe.interval !== void 0 ? estimateOf(requests.map(({ send, reply }) => ({
|
|
3091
|
+
sent: send.t,
|
|
3092
|
+
done: reply?.t ?? null
|
|
3093
|
+
})), events.reduce((latest, event) => Math.max(latest, event.t), 0), valueIn(cell.probe.interval, "ms")) : void 0;
|
|
3027
3094
|
const from = prediction.from === void 0 ? void 0 : referenceAt(prediction.from);
|
|
3028
3095
|
const until = ended ?? after.at(-1)?.t;
|
|
3029
3096
|
const peerRecords = peerCookie === void 0 ? [] : kernel.filter((record) => record.netns === peerNetns && record.cookie === peerCookie);
|
|
@@ -3056,6 +3123,7 @@ const measureSocket = (cell, run) => {
|
|
|
3056
3123
|
steps: retransmitted.filter((record) => record.mono > request.t).map((record) => between(request.t, record.mono)),
|
|
3057
3124
|
samples,
|
|
3058
3125
|
...load === void 0 ? {} : { load },
|
|
3126
|
+
...estimate === void 0 ? {} : { estimate },
|
|
3059
3127
|
reordering: reorderingOf(socket.filter((record) => record.mono > request.t), peerRecords.filter((record) => record.mono > request.t)),
|
|
3060
3128
|
...crossings,
|
|
3061
3129
|
void: voided
|
|
@@ -3664,6 +3732,27 @@ const openFabric = async (parts) => {
|
|
|
3664
3732
|
};
|
|
3665
3733
|
//#endregion
|
|
3666
3734
|
//#region src/substrate.ts
|
|
3735
|
+
/**
|
|
3736
|
+
* A layer is a rung of the laboratory (`docs/S7.md`). E1 is containers on one kernel, and E2 is a
|
|
3737
|
+
* cluster of containers on one kernel. A lab with `Topology.fabric` writes E3: routers in containers.
|
|
3738
|
+
* A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this
|
|
3739
|
+
* time.
|
|
3740
|
+
*/
|
|
3741
|
+
const LAYERS = [
|
|
3742
|
+
"E0",
|
|
3743
|
+
"E1",
|
|
3744
|
+
"E2",
|
|
3745
|
+
"E3",
|
|
3746
|
+
"E4",
|
|
3747
|
+
"E5",
|
|
3748
|
+
"E6"
|
|
3749
|
+
];
|
|
3750
|
+
/** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */
|
|
3751
|
+
const CLOUDS = [
|
|
3752
|
+
"azure",
|
|
3753
|
+
"aws",
|
|
3754
|
+
"unknown"
|
|
3755
|
+
];
|
|
3667
3756
|
/** GitHub announced Linux jobs on AWS on this date. Each earlier hosted job ran on Azure. */
|
|
3668
3757
|
const AWS_FROM = "2026-10-28";
|
|
3669
3758
|
/** This function gives the cloud of a DMI vendor. A kernel name does not tell: one image can start on each cloud. */
|
|
@@ -7493,6 +7582,19 @@ const clusterOnce = async (lab, cell, environment, index) => {
|
|
|
7493
7582
|
* not in the namespace that the prober watches. The record of a run is the lines of the client and
|
|
7494
7583
|
* the whole partition, read to its high watermark after the group converged.
|
|
7495
7584
|
*/
|
|
7585
|
+
/**
|
|
7586
|
+
* This function gives the record of the Kafka client for a manifest: its image, its source and its
|
|
7587
|
+
* build record. The pins check refuses a record of a built client without its build record.
|
|
7588
|
+
*/
|
|
7589
|
+
const kafkaClientRecord = (image) => {
|
|
7590
|
+
const source = shippedSource("kafka");
|
|
7591
|
+
return {
|
|
7592
|
+
kind: "image",
|
|
7593
|
+
image,
|
|
7594
|
+
source,
|
|
7595
|
+
...buildOf(source)
|
|
7596
|
+
};
|
|
7597
|
+
};
|
|
7496
7598
|
/** This path is the class path of the Kafka image: the JVM expands the star itself. */
|
|
7497
7599
|
const CLASS_PATH = "/opt/harness/kafka/classes:/opt/harness/kafka/lib/*";
|
|
7498
7600
|
/** This option is the heap of the client and of the admin. It has no source: the two hold a producer or a read of one partition. */
|
|
@@ -7892,12 +7994,10 @@ const openKafkaLab = async (kafka) => {
|
|
|
7892
7994
|
"apk",
|
|
7893
7995
|
"info",
|
|
7894
7996
|
"-v"
|
|
7895
|
-
])).split("\n").sort()
|
|
7896
|
-
|
|
7897
|
-
client: {
|
|
7898
|
-
kind: "image",
|
|
7899
|
-
image: clientImage
|
|
7997
|
+
])).split("\n").sort(),
|
|
7998
|
+
...harnessRecord()
|
|
7900
7999
|
},
|
|
8000
|
+
client: kafkaClientRecord(clientImage),
|
|
7901
8001
|
netns: {
|
|
7902
8002
|
client: clientNetns,
|
|
7903
8003
|
target: members[kafka.brokers[0]].netns
|
|
@@ -8663,6 +8763,12 @@ const once = async (lab, cell, environment, index, dry = false) => {
|
|
|
8663
8763
|
/** This function divides a count of runs across environments, as equally as possible. */
|
|
8664
8764
|
const spread = (runs, environments) => Array.from({ length: environments }, (_, at) => Math.floor(runs / environments) + (at < runs % environments ? 1 : 0)).filter((count) => count > 0);
|
|
8665
8765
|
/**
|
|
8766
|
+
* This function gives the count of runs of each new environment of a cell, for `runs` more runs. A
|
|
8767
|
+
* pair cell has an environment for each run, because its run promotes the standby. Other cells
|
|
8768
|
+
* go across their environments, and at least one for each environment at the same time.
|
|
8769
|
+
*/
|
|
8770
|
+
const environmentCounts = (cell, runs) => spread(runs, cell.pair !== void 0 ? runs : Math.max(cell.environments, Math.max(1, cell.concurrency ?? 1)));
|
|
8771
|
+
/**
|
|
8666
8772
|
* This function tells if the fault of a cell ends its environment. A server that stopped cannot serve
|
|
8667
8773
|
* the next run. Also, a cell can say that its fault changes the environment (`fresh`).
|
|
8668
8774
|
*/
|
|
@@ -8799,6 +8905,7 @@ const inReplicaSetEnvironment = async (cell, environment, count, say) => {
|
|
|
8799
8905
|
* run. The run promotes the standby, thus a pair cell has an environment for each run.
|
|
8800
8906
|
*/
|
|
8801
8907
|
const inPairEnvironment = async (cell, environment, count, say) => {
|
|
8908
|
+
if (count !== 1) throw new Error(`${cell.name}: a pair environment has one run, not ${count}: the run promotes the standby`);
|
|
8802
8909
|
const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? "tcp", cell.topology);
|
|
8803
8910
|
try {
|
|
8804
8911
|
await lab.warm();
|
|
@@ -8891,6 +8998,8 @@ const inKafkaEnvironment = async (cell, environment, count, say) => {
|
|
|
8891
8998
|
* Each environment does a warm-up first, and the result keeps it apart from the counted runs.
|
|
8892
8999
|
*/
|
|
8893
9000
|
const runCell = async (cell, say = () => {}) => {
|
|
9001
|
+
const problems = environmentProblems(cell);
|
|
9002
|
+
if (problems.length > 0) throw new Error(problems.join(", "));
|
|
8894
9003
|
const started = (/* @__PURE__ */ new Date()).toISOString();
|
|
8895
9004
|
const manifests = [];
|
|
8896
9005
|
const runs = [];
|
|
@@ -8899,7 +9008,7 @@ const runCell = async (cell, say = () => {}) => {
|
|
|
8899
9008
|
let target = cell.runs;
|
|
8900
9009
|
let next = 0;
|
|
8901
9010
|
for (;;) {
|
|
8902
|
-
const counts =
|
|
9011
|
+
const counts = environmentCounts(cell, target - runs.length);
|
|
8903
9012
|
for (let at = 0; at < counts.length; at += concurrency) {
|
|
8904
9013
|
const batch = counts.slice(at, at + concurrency).map((count) => ({
|
|
8905
9014
|
count,
|
|
@@ -8935,6 +9044,6 @@ const runCell = async (cell, say = () => {}) => {
|
|
|
8935
9044
|
}
|
|
8936
9045
|
};
|
|
8937
9046
|
//#endregion
|
|
8938
|
-
export { AWS_FROM, CLIENT_CAPABILITIES, CLIENT_NAMES, CLUSTER_STAGES, CONVERGE_MS, DAEMONS, DEBUG, DIRTY, DROP_HANDLING, FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, FRR_IMAGE, GIVES_AWAY, HASH_SCRIPT, INJECT, INSERT, KAFKA_TAIL_MS, KEPT, LINGER_MS, LISTING, LOAD_FORMAT, LOAD_PATH, LOCK_NAMES, LOSS_MARGIN, MEMBER_MARKS, MONITOR_DOWN, NODE_MARKS, NOISE, PINNED, PUMP, PUMP_SLACK, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, RESTART, ROUTERS, SCHEDULE_PATH, SEED_DOCUMENT, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STANDBY_READY, STATUS_SCRIPT, STEPS, STEP_DOWN, amqpClientImage, basesOf, bootstrapOf, brokerEnv, buildOf, buildRecordOf, callOf, cancelsOf, cargoVersions, clockOffsetOf, closeOrExit, cloudOf, clusterArgs, clusterConf, clusterCutOf, clusterHostsOf, clusterOnce, clusterStagesOf, clusterViewOf, commitProblems, comparable, controllerEnv, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, drillOnce, drillSpan, dropFinding, dropOf, endpointAfter, envOf, errorsOf, exitOf, fieldOf, fieldsOf, firstUnanswered, frrConf, goHttpImage, goVersions, groupOnce, groupVerdictOf, grpcClientImage, harnessImage, harnessRecord, harnessVersion, hashOf, highestHeld, hikariClientImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isFenceLine, isHopPlace, jarVersions, jitterOf, jitterOfLines, judge, kafkaArgs, kafkaClientImage, kafkaCutOf, kafkaOnce, kafkaPauseOnce, kafkaViewOf, lagsOf, laterMove, latestEndOf, leafLacks, leftAfter, loadOf, loadPlanOf, loadVerdict, locksOf, logNameOf, logTimeOf, manifestProblems, matches, measure, measureConntrack, measureDriver, measureGroup, measurePause, measurePorts, measureQueue, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, monotonicAt, monotonicOf, namesGroup, nodeClientImage, nodeCommand, nodeHttpImage, nodeIdOf, nodeLineOf, nodeNameOf, nodesOnMonotonic, noiseOf, npmVersions, numbersOf, onMonotonic, openClusterLab, openFabric, openGroupLab, openKafkaLab, openLab, openReplicaSetLab, openStandby, pairArgs, pairOnce, pairingOf, pairingsOf, pauseReady, peersOf, pgClientImage, pingsOf, plainOf, planOf, programLines, programOf, quantileOf, readCpu, readHost, readOplog, reconnectFinding, reconnectOf, recordProblems, recoveryFindings, recoveryOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, restamped, routeLine, routerImage, routesOf, runCell, seedScript, sentinelConfig, sessionsOf, shippedClientRecord, shippedSource, sliceQuery, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, standaloneCommand, standbyCommand, statusViewOf, stealShare, stopScript, streamsLoadOf, subjectClient, subjectProblems, subscriptionsOf, substrateHere, substrateKey, substrateOf, substrateOn, targetImageOf, targetSourceOf, templated, toolJsonOf, topicOf, topologyOf, toxicBody, unlockedManifests, unpinnedBases, unpoolable, verdictOf, versionsOf, viewOf, writesOf };
|
|
9047
|
+
export { AWS_FROM, CLIENT_CAPABILITIES, CLIENT_NAMES, CLOSED_TOLERANCE, CLOUDS, CLUSTER_STAGES, CONVERGE_MS, DAEMONS, DEBUG, DIRTY, DROP_HANDLING, FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, FRR_IMAGE, GIVES_AWAY, HASH_SCRIPT, INJECT, INSERT, KAFKA_TAIL_MS, KEPT, LAYERS, LINGER_MS, LISTING, LOAD_FORMAT, LOAD_PATH, LOCK_NAMES, LOSS_MARGIN, MEMBER_MARKS, MONITOR_DOWN, NODE_MARKS, NOISE, PINNED, PUMP, PUMP_SLACK, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, RESTART, ROUTERS, SCHEDULE_PATH, SEED_DOCUMENT, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STANDBY_READY, STATUS_SCRIPT, STEPS, STEP_DOWN, amqpClientImage, basesOf, bootstrapOf, brokerEnv, buildOf, buildRecordOf, callOf, cancelsOf, cargoVersions, clockOffsetOf, closeOrExit, cloudOf, clusterArgs, clusterConf, clusterCutOf, clusterHostsOf, clusterOnce, clusterStagesOf, clusterViewOf, commitProblems, comparable, controllerEnv, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, drillOnce, drillSpan, dropFinding, dropOf, endpointAfter, envOf, environmentCounts, environmentProblems, errorsOf, estimateOf, estimateVerdict, exitOf, fieldOf, fieldsOf, firstUnanswered, frrConf, goHttpImage, goVersions, groupOnce, groupVerdictOf, grpcClientImage, harnessImage, harnessRecord, harnessVersion, hashOf, highestHeld, hikariClientImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isFenceLine, isHopPlace, jarVersions, jitterOf, jitterOfLines, judge, kafkaArgs, kafkaClientImage, kafkaCutOf, kafkaOnce, kafkaPauseOnce, kafkaViewOf, lagsOf, laterMove, latestEndOf, leafLacks, leftAfter, loadOf, loadPlanOf, loadVerdict, locksOf, logNameOf, logTimeOf, manifestProblems, matches, measure, measureConntrack, measureDriver, measureGroup, measurePause, measurePorts, measureQueue, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, monotonicAt, monotonicOf, namesGroup, nodeClientImage, nodeCommand, nodeHttpImage, nodeIdOf, nodeLineOf, nodeNameOf, nodesOnMonotonic, noiseOf, npmVersions, numbersOf, onMonotonic, openClusterLab, openFabric, openGroupLab, openKafkaLab, openLab, openReplicaSetLab, openStandby, pairArgs, pairOnce, pairingOf, pairingsOf, pauseReady, peersOf, pgClientImage, pingsOf, plainOf, planOf, poolOf, programLines, programOf, quantileOf, readCpu, readHost, readOplog, reconnectFinding, reconnectOf, recordProblems, recoveryFindings, recoveryOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, restamped, routeLine, routerImage, routesOf, runCell, seedScript, sentinelConfig, sessionsOf, shippedClientRecord, shippedSource, sliceQuery, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, standaloneCommand, standbyCommand, statusViewOf, stealShare, stopScript, streamsLoadOf, subjectClient, subjectProblems, subscriptionsOf, substrateHere, substrateKey, substrateOf, substrateOn, targetImageOf, targetSourceOf, templated, toolJsonOf, topicOf, topologyOf, toxicBody, unlockedManifests, unpinnedBases, unpoolable, verdictOf, versionsOf, viewOf, writesOf };
|
|
8939
9048
|
|
|
8940
9049
|
//# sourceMappingURL=index.js.map
|