livedesk 0.1.461 → 0.1.463
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/README.md +28 -8
- package/bin/livedesk.js +36 -9
- package/client/bin/livedesk-client-node.js +506 -555
- package/client/bin/livedesk-client-update-bootstrap.cjs +59 -0
- package/client/bin/livedesk-client.js +195 -58
- package/client/package.json +11 -11
- package/client/src/runtime/agent-process-lifecycle.js +85 -23
- package/client/src/runtime/client-runtime-server.js +775 -127
- package/client/src/runtime/hub-wake-listener.js +42 -11
- package/diagnostics/livedesk-mac-physical-gate-core.mjs +992 -54
- package/diagnostics/livedesk-mac-physical-isolation.mjs +48 -5
- package/diagnostics/livedesk-mode3-capture-smoke.mjs +549 -88
- package/electron/bounded-desktop-log.mjs +609 -0
- package/electron/main.mjs +316 -132
- package/electron/runtime-process-owner.mjs +287 -0
- package/electron/update-manager.mjs +59 -18
- package/hub/package.json +2 -2
- package/hub/src/agents/agent-manager.js +27 -11
- package/hub/src/agents/codex-agent-runtime.js +325 -41
- package/hub/src/frame-packet-contract.mjs +427 -0
- package/hub/src/live-capture-transition-retry.mjs +297 -0
- package/hub/src/mode4-atlas-pool.js +17 -3
- package/hub/src/mode4-atlas-worker.js +134 -21
- package/hub/src/mode4-atlas.js +180 -16
- package/hub/src/remote-audio-subscription-contract.mjs +109 -0
- package/hub/src/remote-audio-subscription-contract.test.mjs +72 -0
- package/hub/src/remote-hub.js +6405 -4236
- package/hub/src/server.js +3234 -2206
- package/hub/src/transport/agent-binary-ingress.js +810 -0
- package/hub/src/transport/relay-hub-control.js +372 -56
- package/hub/src/transport/udp-hub-transport.js +186 -45
- package/hub/src/transport/udp-protocol.js +302 -70
- package/package.json +11 -11
- package/runtime-core/package.json +1 -1
- package/runtime-core/src/windows-owned-process-tree.js +172 -24
- package/scripts/sync-web-dist.js +1 -0
- package/web/dist/assets/index-Bjyg25Sq.js +186 -0
- package/web/dist/index.html +1 -1
- package/web/dist/livedesk-build-evidence.json +64 -0
- package/web/dist/assets/index-l4YzRK9d.js +0 -25
|
@@ -1,8 +1,97 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
|
|
3
4
|
const MAC_VIDEO_HELPER_NAME = 'livedesk-sck-h264';
|
|
4
5
|
const MAC_AUDIO_HELPER_NAME = 'livedesk-sck-audio';
|
|
5
6
|
|
|
7
|
+
// This physical gate intentionally uses the product's 960x540/30 Wall-sized
|
|
8
|
+
// ScreenCaptureKit + required hardware VideoToolbox path. These values are hard
|
|
9
|
+
// release ceilings, not a claim that untested Mac hardware is healthy. A real
|
|
10
|
+
// physical run must remain below both the aggregate and exact-role limits.
|
|
11
|
+
// CPU values are macOS `ps` percentages where 100 is one fully occupied core.
|
|
12
|
+
export const MAC_ACTIVE_MOTION_RESOURCE_BUDGET = Object.freeze({
|
|
13
|
+
profile: 'screencapturekit-hardware-vt-960x540-30',
|
|
14
|
+
width: 960,
|
|
15
|
+
height: 540,
|
|
16
|
+
fps: 30,
|
|
17
|
+
minimumFps: 24,
|
|
18
|
+
minimumSteadySamples: 4,
|
|
19
|
+
minimumMotionObservationMs: 1_500,
|
|
20
|
+
minimumMotionFrameCount: 36,
|
|
21
|
+
minimumDistinctAccessUnits: 12,
|
|
22
|
+
minimumDistinctDecodedFrames: 2,
|
|
23
|
+
minimumNativeCounterDelta: 20,
|
|
24
|
+
maximumMotionHashSamples: 48,
|
|
25
|
+
maximumIdleRatio: 0.1,
|
|
26
|
+
ownedCpuPercentP95Max: 140,
|
|
27
|
+
ownedCpuPercentPeakMax: 200,
|
|
28
|
+
ownedRssBytesPeakMax: 512 * 1024 * 1024,
|
|
29
|
+
// The gate runs the same two unified launcher roots as production. Their
|
|
30
|
+
// Hub, RemoteFast, and SCK descendants must still fit the unchanged CPU/RSS
|
|
31
|
+
// envelope; process ceilings describe topology, not permission to be heavy.
|
|
32
|
+
ownedProcessCountPeakMax: 5,
|
|
33
|
+
ownedChildProcessCountPeakMax: 3,
|
|
34
|
+
captureHelperCountPeakMax: 1,
|
|
35
|
+
roleBudgets: Object.freeze({
|
|
36
|
+
'hub-launcher': Object.freeze({
|
|
37
|
+
processCountPeakMax: 1,
|
|
38
|
+
cpuPercentP95Max: 5,
|
|
39
|
+
cpuPercentPeakMax: 15,
|
|
40
|
+
rssBytesPeakMax: 96 * 1024 * 1024
|
|
41
|
+
}),
|
|
42
|
+
'hub-runtime': Object.freeze({
|
|
43
|
+
processCountPeakMax: 1,
|
|
44
|
+
cpuPercentP95Max: 35,
|
|
45
|
+
cpuPercentPeakMax: 60,
|
|
46
|
+
rssBytesPeakMax: 160 * 1024 * 1024
|
|
47
|
+
}),
|
|
48
|
+
'client-launcher': Object.freeze({
|
|
49
|
+
processCountPeakMax: 1,
|
|
50
|
+
cpuPercentP95Max: 10,
|
|
51
|
+
cpuPercentPeakMax: 25,
|
|
52
|
+
rssBytesPeakMax: 128 * 1024 * 1024
|
|
53
|
+
}),
|
|
54
|
+
'remote-fast': Object.freeze({
|
|
55
|
+
processCountPeakMax: 1,
|
|
56
|
+
cpuPercentP95Max: 50,
|
|
57
|
+
cpuPercentPeakMax: 85,
|
|
58
|
+
rssBytesPeakMax: 256 * 1024 * 1024
|
|
59
|
+
}),
|
|
60
|
+
'capture-helper': Object.freeze({
|
|
61
|
+
processCountPeakMax: 1,
|
|
62
|
+
cpuPercentP95Max: 80,
|
|
63
|
+
cpuPercentPeakMax: 125,
|
|
64
|
+
rssBytesPeakMax: 192 * 1024 * 1024
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Cold helper prime is not allowed a relaxed "temporary" resource envelope.
|
|
70
|
+
// If source compilation exceeds the normal LiveDesk topology or load ceiling,
|
|
71
|
+
// the release must ship a lighter/prebuilt helper rather than hiding the cost.
|
|
72
|
+
export const MAC_STARTUP_PRIME_RESOURCE_BUDGET = Object.freeze({
|
|
73
|
+
profile: 'cold-sck-helper-prime-to-first-wall-frame',
|
|
74
|
+
minimumSamples: 2,
|
|
75
|
+
maximumDurationMs: 8_000,
|
|
76
|
+
ownedCpuPercentP95Max: MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedCpuPercentP95Max,
|
|
77
|
+
ownedCpuPercentPeakMax: MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedCpuPercentPeakMax,
|
|
78
|
+
ownedRssBytesPeakMax: MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedRssBytesPeakMax,
|
|
79
|
+
ownedProcessCountPeakMax: MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedProcessCountPeakMax,
|
|
80
|
+
ownedChildProcessCountPeakMax:
|
|
81
|
+
MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedChildProcessCountPeakMax,
|
|
82
|
+
captureHelperCountPeakMax: MAC_ACTIVE_MOTION_RESOURCE_BUDGET.captureHelperCountPeakMax
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export const MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL = 'unified-production-v1';
|
|
86
|
+
|
|
87
|
+
const MAC_PRODUCT_RESOURCE_ROLES = new Set([
|
|
88
|
+
'hub-launcher',
|
|
89
|
+
'hub-runtime',
|
|
90
|
+
'client-launcher',
|
|
91
|
+
'remote-fast',
|
|
92
|
+
'capture-helper'
|
|
93
|
+
]);
|
|
94
|
+
|
|
6
95
|
function normalizeProcessText(value) {
|
|
7
96
|
return String(value || '').trim().replaceAll('\\', '/');
|
|
8
97
|
}
|
|
@@ -76,6 +165,137 @@ function finite(value, fallback = 0) {
|
|
|
76
165
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
77
166
|
}
|
|
78
167
|
|
|
168
|
+
function boundedEvenlySpacedItems(items, limit) {
|
|
169
|
+
if (items.length <= limit) return [...items];
|
|
170
|
+
const selected = [];
|
|
171
|
+
for (let index = 0; index < limit; index += 1) {
|
|
172
|
+
const sourceIndex = Math.round(index * (items.length - 1) / Math.max(1, limit - 1));
|
|
173
|
+
selected.push(items[sourceIndex]);
|
|
174
|
+
}
|
|
175
|
+
return selected;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Produces fail-closed motion evidence from the exact received generation.
|
|
180
|
+
* It does not trust an operator label: two decoded pixel hashes, sustained
|
|
181
|
+
* frame delivery, changing encoded access units, and advancing native counters
|
|
182
|
+
* must all independently agree.
|
|
183
|
+
*/
|
|
184
|
+
export function buildMacActiveMotionProof(
|
|
185
|
+
frames = [],
|
|
186
|
+
{
|
|
187
|
+
decodedPixelHashes = [],
|
|
188
|
+
budget = MAC_ACTIVE_MOTION_RESOURCE_BUDGET
|
|
189
|
+
} = {}
|
|
190
|
+
) {
|
|
191
|
+
const normalizedFrames = (Array.isArray(frames) ? frames : [])
|
|
192
|
+
.filter(frame =>
|
|
193
|
+
frame
|
|
194
|
+
&& typeof frame === 'object'
|
|
195
|
+
&& Number.isFinite(Number(frame.receivedAt))
|
|
196
|
+
&& finite(frame.bytes ?? frame.payload?.byteLength ?? frame.payload?.length) > 0
|
|
197
|
+
);
|
|
198
|
+
const firstReceivedAt = finite(normalizedFrames[0]?.receivedAt);
|
|
199
|
+
const lastReceivedAt = finite(normalizedFrames.at(-1)?.receivedAt);
|
|
200
|
+
const observationMs = Math.max(0, lastReceivedAt - firstReceivedAt);
|
|
201
|
+
const hashCandidates = normalizedFrames.filter(frame =>
|
|
202
|
+
String(frame.payloadHash || '').trim() || frame.payload
|
|
203
|
+
);
|
|
204
|
+
const sampledFrames = boundedEvenlySpacedItems(
|
|
205
|
+
hashCandidates,
|
|
206
|
+
Math.max(1, Math.floor(finite(budget.maximumMotionHashSamples, 48)))
|
|
207
|
+
);
|
|
208
|
+
const accessUnitHashes = new Set(sampledFrames.map(frame =>
|
|
209
|
+
String(frame.payloadHash || '').trim()
|
|
210
|
+
|| createHash('sha256').update(frame.payload).digest('hex')
|
|
211
|
+
));
|
|
212
|
+
const telemetrySnapshots = normalizedFrames
|
|
213
|
+
.map(frame => frame.metadata || {})
|
|
214
|
+
.filter(metadata =>
|
|
215
|
+
finite(metadata.nativeCaptureTelemetryVersion) >= 4
|
|
216
|
+
&& metadata.nativeCaptureTelemetryAvailable === true
|
|
217
|
+
&& Number.isFinite(Number(metadata.nativeCaptureSampleCount))
|
|
218
|
+
&& Number.isFinite(Number(metadata.nativeCompressionOutputCount))
|
|
219
|
+
&& Number.isFinite(Number(metadata.nativeEncodedFrameCount))
|
|
220
|
+
&& Number.isFinite(Number(metadata.nativeIdleSkippedFrameCount))
|
|
221
|
+
&& Number.isFinite(Number(metadata.nativeBackpressureSkippedFrameCount))
|
|
222
|
+
);
|
|
223
|
+
const distinctTelemetry = [];
|
|
224
|
+
let previousTelemetryToken = '';
|
|
225
|
+
for (const metadata of telemetrySnapshots) {
|
|
226
|
+
const token = [
|
|
227
|
+
finite(metadata.nativeCaptureSampleCount),
|
|
228
|
+
finite(metadata.nativeCompressionOutputCount),
|
|
229
|
+
finite(metadata.nativeEncodedFrameCount),
|
|
230
|
+
finite(metadata.nativeIdleSkippedFrameCount),
|
|
231
|
+
finite(metadata.nativeBackpressureSkippedFrameCount)
|
|
232
|
+
].join(':');
|
|
233
|
+
if (token === previousTelemetryToken) continue;
|
|
234
|
+
distinctTelemetry.push(metadata);
|
|
235
|
+
previousTelemetryToken = token;
|
|
236
|
+
}
|
|
237
|
+
const firstTelemetry = distinctTelemetry[0] || {};
|
|
238
|
+
const lastTelemetry = distinctTelemetry.at(-1) || {};
|
|
239
|
+
const counterDelta = key => Math.max(0, finite(lastTelemetry[key]) - finite(firstTelemetry[key]));
|
|
240
|
+
const captureSampleDelta = counterDelta('nativeCaptureSampleCount');
|
|
241
|
+
const compressionOutputDelta = counterDelta('nativeCompressionOutputCount');
|
|
242
|
+
const stdoutWriteDelta = counterDelta('nativeEncodedFrameCount');
|
|
243
|
+
// These two native fields are one-second window counts rather than lifetime
|
|
244
|
+
// counters. Sum only the de-duplicated telemetry windows; subtracting them
|
|
245
|
+
// could falsely turn a later smaller unhealthy window into zero.
|
|
246
|
+
const idleSkippedObserved = distinctTelemetry.reduce(
|
|
247
|
+
(sum, metadata) => sum + Math.max(0, finite(metadata.nativeIdleSkippedFrameCount)),
|
|
248
|
+
0
|
|
249
|
+
);
|
|
250
|
+
const backpressureSkippedObserved = distinctTelemetry.reduce(
|
|
251
|
+
(sum, metadata) => sum + Math.max(0, finite(metadata.nativeBackpressureSkippedFrameCount)),
|
|
252
|
+
0
|
|
253
|
+
);
|
|
254
|
+
const normalizedPixelHashes = (Array.isArray(decodedPixelHashes) ? decodedPixelHashes : [])
|
|
255
|
+
.map(value => String(value || '').trim())
|
|
256
|
+
.filter(Boolean)
|
|
257
|
+
.slice(0, 4);
|
|
258
|
+
const distinctDecodedPixelHashCount = new Set(normalizedPixelHashes).size;
|
|
259
|
+
const nativeCounterMinimum = Math.max(1, Math.floor(finite(budget.minimumNativeCounterDelta, 20)));
|
|
260
|
+
const maximumIdleSkipped = Math.max(
|
|
261
|
+
1,
|
|
262
|
+
Math.floor(captureSampleDelta * Math.max(0, finite(budget.maximumIdleRatio, 0.1)))
|
|
263
|
+
);
|
|
264
|
+
const proof = {
|
|
265
|
+
method: 'decoded-pixels-native-counters-and-bounded-access-unit-hashes',
|
|
266
|
+
operatorRequirement: 'continuous-visible-motion-on-each-tested-display',
|
|
267
|
+
observationMs: Math.round(observationMs),
|
|
268
|
+
frameCount: normalizedFrames.length,
|
|
269
|
+
sampledAccessUnitCount: sampledFrames.length,
|
|
270
|
+
distinctAccessUnitHashCount: accessUnitHashes.size,
|
|
271
|
+
telemetrySnapshotCount: telemetrySnapshots.length,
|
|
272
|
+
distinctTelemetrySnapshotCount: distinctTelemetry.length,
|
|
273
|
+
captureSampleDelta,
|
|
274
|
+
compressionOutputDelta,
|
|
275
|
+
stdoutWriteDelta,
|
|
276
|
+
idleSkippedObserved,
|
|
277
|
+
backpressureSkippedObserved,
|
|
278
|
+
maximumAllowedIdleSkipped: maximumIdleSkipped,
|
|
279
|
+
decodedPixelHashCount: normalizedPixelHashes.length,
|
|
280
|
+
distinctDecodedPixelHashCount
|
|
281
|
+
};
|
|
282
|
+
return {
|
|
283
|
+
...proof,
|
|
284
|
+
detected: proof.observationMs >= finite(budget.minimumMotionObservationMs, 1_500)
|
|
285
|
+
&& proof.frameCount >= finite(budget.minimumMotionFrameCount, 36)
|
|
286
|
+
&& proof.sampledAccessUnitCount >= finite(budget.minimumDistinctAccessUnits, 12)
|
|
287
|
+
&& proof.distinctAccessUnitHashCount >= finite(budget.minimumDistinctAccessUnits, 12)
|
|
288
|
+
&& proof.distinctTelemetrySnapshotCount >= 2
|
|
289
|
+
&& proof.captureSampleDelta >= nativeCounterMinimum
|
|
290
|
+
&& proof.compressionOutputDelta >= nativeCounterMinimum
|
|
291
|
+
&& proof.stdoutWriteDelta >= nativeCounterMinimum
|
|
292
|
+
&& proof.idleSkippedObserved <= maximumIdleSkipped
|
|
293
|
+
&& proof.backpressureSkippedObserved === 0
|
|
294
|
+
&& proof.decodedPixelHashCount >= finite(budget.minimumDistinctDecodedFrames, 2)
|
|
295
|
+
&& proof.distinctDecodedPixelHashCount >= finite(budget.minimumDistinctDecodedFrames, 2)
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
79
299
|
export function createAsyncSingleFlightSampler(sampleImpl) {
|
|
80
300
|
if (typeof sampleImpl !== 'function') {
|
|
81
301
|
throw new TypeError('An async sample function is required.');
|
|
@@ -182,15 +402,30 @@ function classifyMacLiveDeskRuntimeRecord(record) {
|
|
|
182
402
|
return '';
|
|
183
403
|
}
|
|
184
404
|
|
|
185
|
-
function identifyMacLiveDeskRuntimeRecords(
|
|
405
|
+
function identifyMacLiveDeskRuntimeRecords(
|
|
406
|
+
records,
|
|
407
|
+
{
|
|
408
|
+
ignorePids = [],
|
|
409
|
+
ignoreDescendantsOfPids = []
|
|
410
|
+
} = {}
|
|
411
|
+
) {
|
|
186
412
|
const ignored = new Set(
|
|
187
413
|
(Array.isArray(ignorePids) ? ignorePids : [])
|
|
188
414
|
.map(Number)
|
|
189
415
|
.filter(pid => Number.isInteger(pid) && pid > 1)
|
|
190
416
|
);
|
|
417
|
+
const ignoredAncestorPids = normalizedOwnedPids(ignoreDescendantsOfPids);
|
|
418
|
+
const recordsByPid = new Map(records.map(record => [record.pid, record]));
|
|
191
419
|
const results = [];
|
|
192
420
|
for (const record of records) {
|
|
193
|
-
if (
|
|
421
|
+
if (
|
|
422
|
+
ignored.has(record.pid)
|
|
423
|
+
|| [...ignoredAncestorPids].some(ancestorPid =>
|
|
424
|
+
record.pid === ancestorPid || hasAncestorPid(record, ancestorPid, recordsByPid)
|
|
425
|
+
)
|
|
426
|
+
) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
194
429
|
const kind = classifyMacLiveDeskRuntimeRecord(record);
|
|
195
430
|
if (!kind) continue;
|
|
196
431
|
results.push({
|
|
@@ -218,6 +453,34 @@ function hasAncestorPid(record, ancestorPid, recordsByPid) {
|
|
|
218
453
|
return false;
|
|
219
454
|
}
|
|
220
455
|
|
|
456
|
+
function isUnifiedLauncherRoleRecord(record, role) {
|
|
457
|
+
if (classifyMacLiveDeskRuntimeRecord(record) !== 'unified-runtime') return false;
|
|
458
|
+
const commandLine = normalizeProcessText(record?.commandLine);
|
|
459
|
+
const escapedRole = String(role || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
460
|
+
return new RegExp(
|
|
461
|
+
`(?:--force-role|--role)(?:=|\\s+)${escapedRole}(?:\\s|$)`
|
|
462
|
+
+ `|(?:^|\\s)(?:hub|manager|client)(?:\\s|$)`,
|
|
463
|
+
'i'
|
|
464
|
+
).test(commandLine)
|
|
465
|
+
&& (
|
|
466
|
+
role === 'hub'
|
|
467
|
+
? /(?:--force-role|--role)(?:=|\s+)(?:hub|manager)(?:\s|$)|(?:^|\s)(?:hub|manager)(?:\s|$)/i
|
|
468
|
+
.test(commandLine)
|
|
469
|
+
: /(?:--force-role|--role)(?:=|\s+)client(?:\s|$)|(?:^|\s)client(?:\s|$)/i
|
|
470
|
+
.test(commandLine)
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function classifyOwnedMacProductRole(record, ownerRole, isRoot) {
|
|
475
|
+
if (isRoot) return `${ownerRole}-launcher`;
|
|
476
|
+
const kind = classifyMacLiveDeskRuntimeRecord(record);
|
|
477
|
+
if (kind === 'hub-runtime') return 'hub-runtime';
|
|
478
|
+
if (kind === 'client-agent') return 'remote-fast';
|
|
479
|
+
if (kind === 'capture-helper') return 'capture-helper';
|
|
480
|
+
if (kind) return kind;
|
|
481
|
+
return `${ownerRole}-owned-descendant`;
|
|
482
|
+
}
|
|
483
|
+
|
|
221
484
|
function normalizedOwnedPids(values) {
|
|
222
485
|
return new Set(
|
|
223
486
|
(Array.isArray(values) ? values : [])
|
|
@@ -234,17 +497,15 @@ export function buildMacDiagnosticResourceSample(
|
|
|
234
497
|
psOutput,
|
|
235
498
|
{
|
|
236
499
|
diagnosticPid = 0,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
500
|
+
hubLauncherPid = 0,
|
|
501
|
+
clientLauncherPid = 0,
|
|
502
|
+
observerPids = []
|
|
240
503
|
} = {}
|
|
241
504
|
) {
|
|
242
505
|
const records = parseMacProcessResourceRecords(psOutput);
|
|
243
506
|
const recordsByPid = new Map(records.map(record => [record.pid, record]));
|
|
244
507
|
const normalizedDiagnosticPid = Number(diagnosticPid);
|
|
245
|
-
const
|
|
246
|
-
const normalizedAgentPid = Number(agentPid);
|
|
247
|
-
const ownedDecoderPids = normalizedOwnedPids(decoderPids);
|
|
508
|
+
const ownedObserverPids = normalizedOwnedPids(observerPids);
|
|
248
509
|
const helpers = records.filter(isMacCaptureHelperRecord);
|
|
249
510
|
// The public `npx livedesk diagnose mac-physical` coordinator is itself
|
|
250
511
|
// classified as a unified LiveDesk runtime. Exclude only that exact,
|
|
@@ -253,44 +514,106 @@ export function buildMacDiagnosticResourceSample(
|
|
|
253
514
|
const liveDeskRecords = identifyMacLiveDeskRuntimeRecords(records, {
|
|
254
515
|
ignorePids: [normalizedDiagnosticPid]
|
|
255
516
|
});
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
517
|
+
const roots = [
|
|
518
|
+
{
|
|
519
|
+
ownerRole: 'hub',
|
|
520
|
+
pid: Number(hubLauncherPid),
|
|
521
|
+
role: 'hub-launcher'
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
ownerRole: 'client',
|
|
525
|
+
pid: Number(clientLauncherPid),
|
|
526
|
+
role: 'client-launcher'
|
|
527
|
+
}
|
|
528
|
+
].map(root => {
|
|
529
|
+
const record = recordsByPid.get(root.pid);
|
|
530
|
+
return {
|
|
531
|
+
...root,
|
|
532
|
+
record,
|
|
533
|
+
owned: Number.isInteger(root.pid)
|
|
534
|
+
&& root.pid > 1
|
|
535
|
+
&& isUnifiedLauncherRoleRecord(record, root.ownerRole)
|
|
536
|
+
};
|
|
537
|
+
});
|
|
260
538
|
const ownedLiveDeskPids = new Set();
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
539
|
+
const resourceRecordsByPid = new Map();
|
|
540
|
+
const addResource = (
|
|
541
|
+
record,
|
|
542
|
+
role,
|
|
543
|
+
ownedByDiagnostic,
|
|
544
|
+
{
|
|
545
|
+
ownerRole = '',
|
|
546
|
+
ownership = 'unowned',
|
|
547
|
+
productProcess = false
|
|
548
|
+
} = {}
|
|
549
|
+
) => {
|
|
272
550
|
if (!record) return;
|
|
273
|
-
|
|
551
|
+
resourceRecordsByPid.set(record.pid, {
|
|
274
552
|
role,
|
|
275
553
|
pid: record.pid,
|
|
276
554
|
ownedByDiagnostic: ownedByDiagnostic === true,
|
|
555
|
+
ownerRole,
|
|
556
|
+
ownership,
|
|
557
|
+
productProcess: productProcess === true,
|
|
277
558
|
cpuPercent: Math.round(record.cpuPercent * 100) / 100,
|
|
278
559
|
rssBytes: record.rssBytes
|
|
279
560
|
});
|
|
280
561
|
};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
562
|
+
|
|
563
|
+
for (const root of roots) {
|
|
564
|
+
addResource(root.record, root.role, root.owned, {
|
|
565
|
+
ownerRole: root.ownerRole,
|
|
566
|
+
ownership: 'exact-root',
|
|
567
|
+
productProcess: true
|
|
568
|
+
});
|
|
569
|
+
if (!root.owned) continue;
|
|
570
|
+
ownedLiveDeskPids.add(root.pid);
|
|
571
|
+
for (const record of records) {
|
|
572
|
+
if (record.pid === root.pid || !hasAncestorPid(record, root.pid, recordsByPid)) continue;
|
|
573
|
+
addResource(
|
|
574
|
+
record,
|
|
575
|
+
classifyOwnedMacProductRole(record, root.ownerRole, false),
|
|
576
|
+
true,
|
|
577
|
+
{
|
|
578
|
+
ownerRole: root.ownerRole,
|
|
579
|
+
ownership: 'exact-descendant',
|
|
580
|
+
productProcess: true
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
if (classifyMacLiveDeskRuntimeRecord(record)) {
|
|
584
|
+
ownedLiveDeskPids.add(record.pid);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
for (const observerPid of [...ownedObserverPids].sort((left, right) => left - right)) {
|
|
590
|
+
// ffmpeg exists only to observe diagnostic key frames. It is retained in
|
|
591
|
+
// report-safe telemetry when explicitly requested, but it is never product
|
|
592
|
+
// CPU/RSS/process evidence and therefore never enters owned aggregates.
|
|
593
|
+
addResource(recordsByPid.get(observerPid), 'diagnostic-observer', false, {
|
|
594
|
+
ownerRole: 'diagnostic',
|
|
595
|
+
ownership: 'exact-observer',
|
|
596
|
+
productProcess: false
|
|
597
|
+
});
|
|
285
598
|
}
|
|
286
599
|
for (const helper of helpers.sort((left, right) => left.pid - right.pid)) {
|
|
287
|
-
|
|
600
|
+
if (resourceRecordsByPid.has(helper.pid)) continue;
|
|
601
|
+
addResource(helper, 'capture-helper', false, {
|
|
602
|
+
ownerRole: 'unowned',
|
|
603
|
+
ownership: 'unowned',
|
|
604
|
+
productProcess: true
|
|
605
|
+
});
|
|
288
606
|
}
|
|
289
607
|
|
|
608
|
+
const resourceRecords = [...resourceRecordsByPid.values()];
|
|
290
609
|
return {
|
|
610
|
+
ownershipModel: MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL,
|
|
291
611
|
sampledAt: new Date().toISOString(),
|
|
292
612
|
totalLiveDeskProcessCount: liveDeskRecords.length,
|
|
293
613
|
captureHelperCount: helpers.length,
|
|
614
|
+
ownedProductProcessCount: resourceRecords.filter(record =>
|
|
615
|
+
record.ownedByDiagnostic === true && record.productProcess === true
|
|
616
|
+
).length,
|
|
294
617
|
unownedLiveDeskPids: liveDeskRecords
|
|
295
618
|
.filter(record => !ownedLiveDeskPids.has(record.pid))
|
|
296
619
|
.map(record => record.pid)
|
|
@@ -322,6 +645,9 @@ export function summarizeMacDiagnosticResourceSamples(
|
|
|
322
645
|
role,
|
|
323
646
|
pid,
|
|
324
647
|
ownedByDiagnostic: record?.ownedByDiagnostic === true,
|
|
648
|
+
ownerRole: String(record?.ownerRole || ''),
|
|
649
|
+
ownership: String(record?.ownership || ''),
|
|
650
|
+
productProcess: record?.productProcess !== false,
|
|
325
651
|
cpuPercentSamples: [],
|
|
326
652
|
rssBytesPeak: 0
|
|
327
653
|
});
|
|
@@ -338,12 +664,18 @@ export function summarizeMacDiagnosticResourceSamples(
|
|
|
338
664
|
role,
|
|
339
665
|
pid,
|
|
340
666
|
ownedByDiagnostic: true,
|
|
667
|
+
ownerRole: String(record?.ownerRole || ''),
|
|
668
|
+
ownership: String(record?.ownership || ''),
|
|
669
|
+
productProcess: record?.productProcess === true,
|
|
341
670
|
cpuPercentSamples: [],
|
|
342
671
|
rssBytesPeak: 0
|
|
343
672
|
};
|
|
344
673
|
grouped.set(key, summary);
|
|
345
674
|
}
|
|
346
675
|
summary.ownedByDiagnostic = summary.ownedByDiagnostic && record.ownedByDiagnostic === true;
|
|
676
|
+
summary.productProcess = summary.productProcess && record.productProcess === true;
|
|
677
|
+
if (summary.ownerRole !== String(record?.ownerRole || '')) summary.ownerRole = 'mixed';
|
|
678
|
+
if (summary.ownership !== String(record?.ownership || '')) summary.ownership = 'mixed';
|
|
347
679
|
summary.cpuPercentSamples.push(Math.max(0, finite(record.cpuPercent)));
|
|
348
680
|
summary.rssBytesPeak = Math.max(summary.rssBytesPeak, Math.max(0, finite(record.rssBytes)));
|
|
349
681
|
}
|
|
@@ -357,6 +689,9 @@ export function summarizeMacDiagnosticResourceSamples(
|
|
|
357
689
|
role: summary.role,
|
|
358
690
|
pid: summary.pid,
|
|
359
691
|
ownedByDiagnostic: summary.ownedByDiagnostic,
|
|
692
|
+
ownerRole: summary.ownerRole,
|
|
693
|
+
ownership: summary.ownership,
|
|
694
|
+
productProcess: summary.productProcess,
|
|
360
695
|
sampleCount: summary.cpuPercentSamples.length,
|
|
361
696
|
cpuPercentSamples,
|
|
362
697
|
cpuPercentP95: Math.round(percentile95(summary.cpuPercentSamples) * 100) / 100,
|
|
@@ -369,6 +704,72 @@ export function summarizeMacDiagnosticResourceSamples(
|
|
|
369
704
|
.map(sample => Math.max(0, Math.round(finite(sample.totalLiveDeskProcessCount))));
|
|
370
705
|
const captureHelperCountSamples = normalizedSamples
|
|
371
706
|
.map(sample => Math.max(0, Math.round(finite(sample.captureHelperCount))));
|
|
707
|
+
const productResourceSamples = normalizedSamples.map(sample => {
|
|
708
|
+
const ownedProcesses = (Array.isArray(sample.processes) ? sample.processes : [])
|
|
709
|
+
.filter(record =>
|
|
710
|
+
record?.ownedByDiagnostic === true
|
|
711
|
+
&& record?.productProcess === true
|
|
712
|
+
);
|
|
713
|
+
return {
|
|
714
|
+
cpuPercent: ownedProcesses.reduce(
|
|
715
|
+
(sum, record) => sum + Math.max(0, finite(record?.cpuPercent)),
|
|
716
|
+
0
|
|
717
|
+
),
|
|
718
|
+
rssBytes: ownedProcesses.reduce(
|
|
719
|
+
(sum, record) => sum + Math.max(0, finite(record?.rssBytes)),
|
|
720
|
+
0
|
|
721
|
+
),
|
|
722
|
+
processCount: ownedProcesses.length,
|
|
723
|
+
childProcessCount: ownedProcesses.filter(record =>
|
|
724
|
+
String(record?.ownership || '') === 'exact-descendant'
|
|
725
|
+
).length
|
|
726
|
+
};
|
|
727
|
+
});
|
|
728
|
+
const ownedCpuPercentSamples = productResourceSamples
|
|
729
|
+
.map(sample => Math.round(sample.cpuPercent * 100) / 100)
|
|
730
|
+
.slice(-120);
|
|
731
|
+
const ownedRssBytesSamples = productResourceSamples
|
|
732
|
+
.map(sample => Math.round(sample.rssBytes))
|
|
733
|
+
.slice(-120);
|
|
734
|
+
const ownedProcessCountSamples = productResourceSamples
|
|
735
|
+
.map(sample => sample.processCount)
|
|
736
|
+
.slice(-120);
|
|
737
|
+
const ownedChildProcessCountSamples = productResourceSamples
|
|
738
|
+
.map(sample => sample.childProcessCount)
|
|
739
|
+
.slice(-120);
|
|
740
|
+
const roles = [...MAC_PRODUCT_RESOURCE_ROLES].map(role => {
|
|
741
|
+
const cpuPercentSamples = [];
|
|
742
|
+
let rssBytesPeak = 0;
|
|
743
|
+
let processCountPeak = 0;
|
|
744
|
+
let sampleCount = 0;
|
|
745
|
+
for (const sample of normalizedSamples) {
|
|
746
|
+
const roleProcesses = (Array.isArray(sample.processes) ? sample.processes : [])
|
|
747
|
+
.filter(record =>
|
|
748
|
+
record?.ownedByDiagnostic === true
|
|
749
|
+
&& String(record?.role || '') === role
|
|
750
|
+
);
|
|
751
|
+
if (roleProcesses.length === 0) continue;
|
|
752
|
+
sampleCount += 1;
|
|
753
|
+
processCountPeak = Math.max(processCountPeak, roleProcesses.length);
|
|
754
|
+
cpuPercentSamples.push(Math.round(roleProcesses.reduce(
|
|
755
|
+
(sum, record) => sum + Math.max(0, finite(record?.cpuPercent)),
|
|
756
|
+
0
|
|
757
|
+
) * 100) / 100);
|
|
758
|
+
rssBytesPeak = Math.max(rssBytesPeak, roleProcesses.reduce(
|
|
759
|
+
(sum, record) => sum + Math.max(0, finite(record?.rssBytes)),
|
|
760
|
+
0
|
|
761
|
+
));
|
|
762
|
+
}
|
|
763
|
+
return {
|
|
764
|
+
role,
|
|
765
|
+
sampleCount,
|
|
766
|
+
processCountPeak,
|
|
767
|
+
cpuPercentSamples: cpuPercentSamples.slice(-120),
|
|
768
|
+
cpuPercentP95: Math.round(percentile95(cpuPercentSamples) * 100) / 100,
|
|
769
|
+
cpuPercentPeak: Math.round(Math.max(0, ...cpuPercentSamples) * 100) / 100,
|
|
770
|
+
rssBytesPeak: Math.round(rssBytesPeak)
|
|
771
|
+
};
|
|
772
|
+
});
|
|
372
773
|
const unownedLiveDeskPids = [...new Set(
|
|
373
774
|
normalizedSamples.flatMap(sample =>
|
|
374
775
|
(Array.isArray(sample.unownedLiveDeskPids) ? sample.unownedLiveDeskPids : [])
|
|
@@ -377,12 +778,28 @@ export function summarizeMacDiagnosticResourceSamples(
|
|
|
377
778
|
)
|
|
378
779
|
)].sort((left, right) => left - right);
|
|
379
780
|
return {
|
|
781
|
+
ownershipModel: normalizedSamples.length > 0
|
|
782
|
+
&& normalizedSamples.every(sample =>
|
|
783
|
+
sample.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
784
|
+
)
|
|
785
|
+
? MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
786
|
+
: '',
|
|
380
787
|
sampleCount: normalizedSamples.length,
|
|
381
788
|
totalLiveDeskProcessCount: totalLiveDeskProcessCountSamples.at(-1) || 0,
|
|
382
789
|
totalLiveDeskProcessCountPeak: Math.max(0, ...totalLiveDeskProcessCountSamples),
|
|
383
790
|
captureHelperCountPeak: Math.max(0, ...captureHelperCountSamples),
|
|
791
|
+
ownedCpuPercentSamples,
|
|
792
|
+
ownedCpuPercentP95: Math.round(percentile95(ownedCpuPercentSamples) * 100) / 100,
|
|
793
|
+
ownedCpuPercentPeak: Math.round(Math.max(0, ...ownedCpuPercentSamples) * 100) / 100,
|
|
794
|
+
ownedRssBytesSamples,
|
|
795
|
+
ownedRssBytesPeak: Math.max(0, ...ownedRssBytesSamples),
|
|
796
|
+
ownedProcessCountSamples,
|
|
797
|
+
ownedProcessCountPeak: Math.max(0, ...ownedProcessCountSamples),
|
|
798
|
+
ownedChildProcessCountSamples,
|
|
799
|
+
ownedChildProcessCountPeak: Math.max(0, ...ownedChildProcessCountSamples),
|
|
384
800
|
unownedLiveDeskPids,
|
|
385
|
-
processes
|
|
801
|
+
processes,
|
|
802
|
+
roles
|
|
386
803
|
};
|
|
387
804
|
}
|
|
388
805
|
|
|
@@ -494,7 +911,19 @@ function check(id, ok, detail) {
|
|
|
494
911
|
export function classifyMacPhysicalGate(snapshot = {}) {
|
|
495
912
|
const schemaVersion = Math.floor(finite(snapshot.schemaVersion));
|
|
496
913
|
const requestedFps = Math.max(1, finite(snapshot.requestedFps, 30));
|
|
497
|
-
const
|
|
914
|
+
const motion = snapshot.motion || {};
|
|
915
|
+
const activeMotionProfileMatches = motion.required === true
|
|
916
|
+
&& motion.kind === 'active'
|
|
917
|
+
&& finite(motion.width) === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.width
|
|
918
|
+
&& finite(motion.height) === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.height
|
|
919
|
+
&& requestedFps === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.fps
|
|
920
|
+
&& finite(motion.minimumCaptureFps) === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumFps
|
|
921
|
+
&& motion.idleCadenceWaiverAllowed === false;
|
|
922
|
+
const activeMotionOperatorConfirmed = motion.operatorConfirmed === true
|
|
923
|
+
&& motion.operatorRequirement === 'continuous-visible-motion-on-each-tested-display';
|
|
924
|
+
const minimumFps = requestedFps === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.fps
|
|
925
|
+
? MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumFps
|
|
926
|
+
: requestedFps * 0.8;
|
|
498
927
|
const helper = snapshot.helper || {};
|
|
499
928
|
const monitor = snapshot.monitor || {};
|
|
500
929
|
const modifier = snapshot.modifier || {};
|
|
@@ -518,6 +947,8 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
518
947
|
&& typeof captureStages[name] === 'object'
|
|
519
948
|
&& captureStages[name].telemetry
|
|
520
949
|
&& typeof captureStages[name].telemetry === 'object'
|
|
950
|
+
&& captureStages[name].motionProof
|
|
951
|
+
&& typeof captureStages[name].motionProof === 'object'
|
|
521
952
|
&& Number.isFinite(Number(captureStages[name].deliveredFps))
|
|
522
953
|
);
|
|
523
954
|
const stageEvaluations = requiredStageNames.map(name => {
|
|
@@ -529,9 +960,74 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
529
960
|
const deliveredFps = Math.max(0, finite(stage.deliveredFps));
|
|
530
961
|
const idleSkipped = Math.max(0, finite(stageTelemetry.idleSkipped));
|
|
531
962
|
const backpressureSkipped = Math.max(0, finite(stageTelemetry.backpressureSkipped));
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
963
|
+
const encodeFramesInFlight = finite(stageTelemetry.encodeFramesInFlight, -1);
|
|
964
|
+
const pendingEncodeFrameCount = finite(stageTelemetry.pendingEncodeFrameCount, -1);
|
|
965
|
+
const encodeTimestampOwnerCount = finite(
|
|
966
|
+
stageTelemetry.encodeTimestampOwnerCount,
|
|
967
|
+
-1
|
|
968
|
+
);
|
|
969
|
+
const encodeTimestampOwnerHighWatermark = finite(
|
|
970
|
+
stageTelemetry.encodeTimestampOwnerHighWatermark,
|
|
971
|
+
-1
|
|
972
|
+
);
|
|
973
|
+
const videoToolboxActiveSessionCount = finite(
|
|
974
|
+
stageTelemetry.videoToolboxActiveSessionCount,
|
|
975
|
+
-1
|
|
976
|
+
);
|
|
977
|
+
const videoToolboxSessionHighWatermark = finite(
|
|
978
|
+
stageTelemetry.videoToolboxSessionHighWatermark,
|
|
979
|
+
-1
|
|
980
|
+
);
|
|
981
|
+
const outputOldestAgeMs = finite(stageTelemetry.outputOldestAgeMs, -1);
|
|
982
|
+
const outputDropped = finite(stageTelemetry.outputDropped, -1);
|
|
983
|
+
const nativeAndPipeResidenceAgeMs = finite(
|
|
984
|
+
stageTelemetry.nativeAndPipeResidenceAgeMs,
|
|
985
|
+
-1
|
|
986
|
+
);
|
|
987
|
+
const handoffDropped = finite(stageTelemetry.handoffDropped, -1);
|
|
988
|
+
const handoffRecoveryRequests = finite(
|
|
989
|
+
stageTelemetry.handoffRecoveryRequests,
|
|
990
|
+
-1
|
|
991
|
+
);
|
|
992
|
+
const handoffOldestAgeMs = finite(stageTelemetry.handoffOldestAgeMs, -1);
|
|
993
|
+
const annexBAllocations = finite(stageTelemetry.annexBAllocations, -1);
|
|
994
|
+
const annexBPayloadCopies = finite(stageTelemetry.annexBPayloadCopies, -1);
|
|
995
|
+
const annexBPayloadCopiedBytes = finite(
|
|
996
|
+
stageTelemetry.annexBPayloadCopiedBytes,
|
|
997
|
+
-1
|
|
998
|
+
);
|
|
999
|
+
const pipePayloadAllocations = finite(stageTelemetry.pipePayloadAllocations, -1);
|
|
1000
|
+
const pipePayloadCopies = finite(stageTelemetry.pipePayloadCopies, -1);
|
|
1001
|
+
const pipePayloadCopiedBytes = finite(stageTelemetry.pipePayloadCopiedBytes, -1);
|
|
1002
|
+
const motionProof = stage.motionProof || {};
|
|
1003
|
+
const motionProven = motionProof.method
|
|
1004
|
+
=== 'decoded-pixels-native-counters-and-bounded-access-unit-hashes'
|
|
1005
|
+
&& motionProof.operatorRequirement === 'continuous-visible-motion-on-each-tested-display'
|
|
1006
|
+
&& motionProof.detected === true
|
|
1007
|
+
&& finite(motionProof.observationMs)
|
|
1008
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumMotionObservationMs
|
|
1009
|
+
&& finite(motionProof.frameCount)
|
|
1010
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumMotionFrameCount
|
|
1011
|
+
&& finite(motionProof.sampledAccessUnitCount)
|
|
1012
|
+
<= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.maximumMotionHashSamples
|
|
1013
|
+
&& finite(motionProof.distinctAccessUnitHashCount)
|
|
1014
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumDistinctAccessUnits
|
|
1015
|
+
&& finite(motionProof.distinctTelemetrySnapshotCount) >= 2
|
|
1016
|
+
&& finite(motionProof.captureSampleDelta)
|
|
1017
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumNativeCounterDelta
|
|
1018
|
+
&& finite(motionProof.compressionOutputDelta)
|
|
1019
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumNativeCounterDelta
|
|
1020
|
+
&& finite(motionProof.stdoutWriteDelta)
|
|
1021
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumNativeCounterDelta
|
|
1022
|
+
&& finite(motionProof.idleSkippedObserved)
|
|
1023
|
+
<= finite(motionProof.maximumAllowedIdleSkipped, -1)
|
|
1024
|
+
&& finite(motionProof.backpressureSkippedObserved) === 0
|
|
1025
|
+
&& finite(motionProof.decodedPixelHashCount)
|
|
1026
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumDistinctDecodedFrames
|
|
1027
|
+
&& finite(motionProof.distinctDecodedPixelHashCount)
|
|
1028
|
+
>= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumDistinctDecodedFrames;
|
|
1029
|
+
// This is the active-motion physical gate. Idle throttling remains a valid
|
|
1030
|
+
// runtime optimization, but it cannot waive any active cadence floor.
|
|
535
1031
|
const idleDominant = captureFps >= minimumFps
|
|
536
1032
|
&& backpressureSkipped === 0
|
|
537
1033
|
&& idleSkipped >= Math.max(10, captureFps * 0.6);
|
|
@@ -544,18 +1040,65 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
544
1040
|
deliveredFps,
|
|
545
1041
|
idleSkipped,
|
|
546
1042
|
backpressureSkipped,
|
|
1043
|
+
encodeFramesInFlight,
|
|
1044
|
+
pendingEncodeFrameCount,
|
|
1045
|
+
encodeTimestampOwnerCount,
|
|
1046
|
+
encodeTimestampOwnerHighWatermark,
|
|
1047
|
+
videoToolboxActiveSessionCount,
|
|
1048
|
+
videoToolboxSessionHighWatermark,
|
|
1049
|
+
outputOldestAgeMs,
|
|
1050
|
+
outputDropped,
|
|
1051
|
+
nativeAndPipeResidenceAgeMs,
|
|
1052
|
+
handoffDropped,
|
|
1053
|
+
handoffRecoveryRequests,
|
|
1054
|
+
handoffOldestAgeMs,
|
|
1055
|
+
annexBAllocations,
|
|
1056
|
+
annexBPayloadCopies,
|
|
1057
|
+
annexBPayloadCopiedBytes,
|
|
1058
|
+
pipePayloadAllocations,
|
|
1059
|
+
pipePayloadCopies,
|
|
1060
|
+
pipePayloadCopiedBytes,
|
|
547
1061
|
idleDominant,
|
|
548
|
-
|
|
1062
|
+
motionProof,
|
|
1063
|
+
motionProven,
|
|
1064
|
+
telemetryCurrent: finite(stageTelemetry.version) >= 5
|
|
549
1065
|
&& Number.isFinite(Number(stageTelemetry.ageMs))
|
|
550
1066
|
&& finite(stageTelemetry.ageMs) <= 3_000,
|
|
551
1067
|
hardwareAccelerated: stageTelemetry.hardwareAccelerated === true,
|
|
1068
|
+
nativeEncodeOwnershipBounded: encodeFramesInFlight >= 0
|
|
1069
|
+
&& encodeFramesInFlight <= 2
|
|
1070
|
+
&& pendingEncodeFrameCount >= 0
|
|
1071
|
+
&& pendingEncodeFrameCount <= 1
|
|
1072
|
+
&& encodeTimestampOwnerCount >= 0
|
|
1073
|
+
&& encodeTimestampOwnerCount <= 2
|
|
1074
|
+
&& encodeTimestampOwnerHighWatermark >= encodeTimestampOwnerCount
|
|
1075
|
+
&& encodeTimestampOwnerHighWatermark <= 2
|
|
1076
|
+
&& videoToolboxActiveSessionCount === 1
|
|
1077
|
+
&& videoToolboxSessionHighWatermark === 1,
|
|
552
1078
|
captureAtTarget: captureFps >= minimumFps,
|
|
553
|
-
compressionKeepsUp:
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
1079
|
+
compressionKeepsUp: compressionFps >= minimumFps,
|
|
1080
|
+
stdoutKeepsUp: stdoutFps >= minimumFps,
|
|
1081
|
+
deliveredAtTarget: deliveredFps >= minimumFps,
|
|
1082
|
+
backpressureFree: backpressureSkipped === 0,
|
|
1083
|
+
currentFrameQueuesBounded:
|
|
1084
|
+
outputOldestAgeMs >= 0
|
|
1085
|
+
&& outputOldestAgeMs <= 120
|
|
1086
|
+
&& outputDropped === 0
|
|
1087
|
+
&& stageTelemetry.outputAwaitingKeyFrame === false
|
|
1088
|
+
&& nativeAndPipeResidenceAgeMs >= 0
|
|
1089
|
+
&& nativeAndPipeResidenceAgeMs <= 250
|
|
1090
|
+
&& handoffDropped === 0
|
|
1091
|
+
&& handoffRecoveryRequests === 0
|
|
1092
|
+
&& handoffOldestAgeMs >= 0
|
|
1093
|
+
&& handoffOldestAgeMs <= 120,
|
|
1094
|
+
payloadCopyAccountingCurrent:
|
|
1095
|
+
stageTelemetry.copyTelemetryAvailable === true
|
|
1096
|
+
&& annexBAllocations > 0
|
|
1097
|
+
&& annexBPayloadCopies >= annexBAllocations
|
|
1098
|
+
&& annexBPayloadCopiedBytes > 0
|
|
1099
|
+
&& pipePayloadAllocations > 0
|
|
1100
|
+
&& pipePayloadCopies >= pipePayloadAllocations
|
|
1101
|
+
&& pipePayloadCopiedBytes > 0
|
|
559
1102
|
};
|
|
560
1103
|
});
|
|
561
1104
|
const stageMetricDetail = metric => stageEvaluations
|
|
@@ -570,44 +1113,198 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
570
1113
|
&& stageEvaluations.every(stage => stage.stdoutKeepsUp);
|
|
571
1114
|
const deliveredAtTarget = stageEvidenceAvailable
|
|
572
1115
|
&& stageEvaluations.every(stage => stage.deliveredAtTarget);
|
|
1116
|
+
const backpressureFree = stageEvidenceAvailable
|
|
1117
|
+
&& stageEvaluations.every(stage => stage.backpressureFree);
|
|
1118
|
+
const currentFrameQueuesBounded = stageEvidenceAvailable
|
|
1119
|
+
&& stageEvaluations.every(stage => stage.currentFrameQueuesBounded);
|
|
1120
|
+
const payloadCopyAccountingCurrent = stageEvidenceAvailable
|
|
1121
|
+
&& stageEvaluations.every(stage => stage.payloadCopyAccountingCurrent);
|
|
1122
|
+
const activeMotionProven = stageEvidenceAvailable
|
|
1123
|
+
&& stageEvaluations.every(stage => stage.motionProven);
|
|
1124
|
+
const nativeEncodeOwnershipBounded = stageEvidenceAvailable
|
|
1125
|
+
&& stageEvaluations.every(stage => stage.nativeEncodeOwnershipBounded);
|
|
573
1126
|
const helperPids = Array.isArray(helper.observedPids)
|
|
574
1127
|
? helper.observedPids.map(Number).filter(pid => Number.isInteger(pid) && pid > 1)
|
|
575
1128
|
: [];
|
|
576
1129
|
const resources = snapshot.resources || {};
|
|
577
1130
|
const baselineResources = resources.baseline || {};
|
|
1131
|
+
const startupPrimeResources = resources.startupPrime || {};
|
|
578
1132
|
const steadyResources = resources.steadyCapture || {};
|
|
579
1133
|
const cleanupResources = resources.afterCleanup || {};
|
|
580
1134
|
const steadyProcesses = Array.isArray(steadyResources.processes)
|
|
581
1135
|
? steadyResources.processes
|
|
582
1136
|
: [];
|
|
583
1137
|
const sampledSteadyProcesses = steadyProcesses
|
|
584
|
-
.filter(processInfo =>
|
|
1138
|
+
.filter(processInfo =>
|
|
1139
|
+
finite(processInfo?.sampleCount) > 0
|
|
1140
|
+
&& processInfo?.productProcess === true
|
|
1141
|
+
);
|
|
585
1142
|
const sampledSteadyRoles = new Set(
|
|
586
1143
|
sampledSteadyProcesses.map(processInfo => String(processInfo?.role || ''))
|
|
587
1144
|
);
|
|
1145
|
+
const expectedRoleOwnership = new Map([
|
|
1146
|
+
['hub-launcher', ['hub', 'exact-root']],
|
|
1147
|
+
['hub-runtime', ['hub', 'exact-descendant']],
|
|
1148
|
+
['client-launcher', ['client', 'exact-root']],
|
|
1149
|
+
['remote-fast', ['client', 'exact-descendant']],
|
|
1150
|
+
['capture-helper', ['client', 'exact-descendant']]
|
|
1151
|
+
]);
|
|
1152
|
+
const resourceOwnershipLabelsCurrent = sampledSteadyProcesses.every(processInfo => {
|
|
1153
|
+
const expected = expectedRoleOwnership.get(String(processInfo?.role || ''));
|
|
1154
|
+
if (!expected) {
|
|
1155
|
+
return ['hub', 'client'].includes(String(processInfo?.ownerRole || ''))
|
|
1156
|
+
&& String(processInfo?.ownership || '') === 'exact-descendant';
|
|
1157
|
+
}
|
|
1158
|
+
return String(processInfo?.ownerRole || '') === expected[0]
|
|
1159
|
+
&& String(processInfo?.ownership || '') === expected[1];
|
|
1160
|
+
});
|
|
588
1161
|
const resourceTelemetryAvailable = finite(baselineResources.sampleCount) > 0
|
|
1162
|
+
&& finite(startupPrimeResources.sampleCount) > 0
|
|
589
1163
|
&& finite(steadyResources.sampleCount) > 0
|
|
590
1164
|
&& finite(cleanupResources.sampleCount) > 0;
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
1165
|
+
const steadyOwnedProcessCounts = Array.isArray(steadyResources.ownedProcessCountSamples)
|
|
1166
|
+
? steadyResources.ownedProcessCountSamples.map(value => Math.max(0, Math.round(finite(value))))
|
|
1167
|
+
: [];
|
|
1168
|
+
const steadyOwnedChildCounts = Array.isArray(steadyResources.ownedChildProcessCountSamples)
|
|
1169
|
+
? steadyResources.ownedChildProcessCountSamples
|
|
1170
|
+
.map(value => Math.max(0, Math.round(finite(value))))
|
|
1171
|
+
: [];
|
|
1172
|
+
const exactSteadyTopologyCurrent =
|
|
1173
|
+
steadyOwnedProcessCounts.length >= MAC_ACTIVE_MOTION_RESOURCE_BUDGET.minimumSteadySamples
|
|
1174
|
+
&& steadyOwnedChildCounts.length === steadyOwnedProcessCounts.length
|
|
1175
|
+
&& steadyOwnedProcessCounts.every(
|
|
1176
|
+
count => count === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedProcessCountPeakMax
|
|
1177
|
+
)
|
|
1178
|
+
&& steadyOwnedChildCounts.every(
|
|
1179
|
+
count => count === MAC_ACTIVE_MOTION_RESOURCE_BUDGET.ownedChildProcessCountPeakMax
|
|
1180
|
+
);
|
|
1181
|
+
const resourceOwnershipCurrent =
|
|
1182
|
+
resources.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
1183
|
+
&& baselineResources.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
1184
|
+
&& startupPrimeResources.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
1185
|
+
&& steadyResources.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
1186
|
+
&& cleanupResources.ownershipModel === MAC_PHYSICAL_RESOURCE_OWNERSHIP_MODEL
|
|
1187
|
+
&& finite(baselineResources.totalLiveDeskProcessCountPeak) === 0
|
|
1188
|
+
&& exactSteadyTopologyCurrent
|
|
1189
|
+
&& [...MAC_PRODUCT_RESOURCE_ROLES].every(role => sampledSteadyRoles.has(role))
|
|
595
1190
|
&& sampledSteadyProcesses.every(processInfo => processInfo?.ownedByDiagnostic === true)
|
|
1191
|
+
&& resourceOwnershipLabelsCurrent
|
|
596
1192
|
&& (!Array.isArray(steadyResources.unownedLiveDeskPids)
|
|
597
1193
|
|| steadyResources.unownedLiveDeskPids.length === 0);
|
|
598
1194
|
const resourceDrained = finite(cleanupResources.totalLiveDeskProcessCount) === 0
|
|
599
1195
|
&& finite(cleanupResources.totalLiveDeskProcessCountPeak) === 0
|
|
1196
|
+
&& finite(cleanupResources.ownedProcessCountPeak) === 0
|
|
1197
|
+
&& finite(cleanupResources.ownedChildProcessCountPeak) === 0
|
|
1198
|
+
&& finite(cleanupResources.ownedRssBytesPeak) === 0
|
|
600
1199
|
&& (!Array.isArray(cleanupResources.processes) || cleanupResources.processes.length === 0)
|
|
601
1200
|
&& (!Array.isArray(cleanupResources.unownedLiveDeskPids)
|
|
602
1201
|
|| cleanupResources.unownedLiveDeskPids.length === 0);
|
|
1202
|
+
const resourceReturnedToBaseline = finite(cleanupResources.ownedProcessCountPeak)
|
|
1203
|
+
<= finite(baselineResources.ownedProcessCountPeak)
|
|
1204
|
+
&& finite(cleanupResources.ownedChildProcessCountPeak)
|
|
1205
|
+
<= finite(baselineResources.ownedChildProcessCountPeak)
|
|
1206
|
+
&& finite(cleanupResources.ownedRssBytesPeak)
|
|
1207
|
+
<= finite(baselineResources.ownedRssBytesPeak);
|
|
603
1208
|
const resourceHelperPeak = Math.max(
|
|
604
1209
|
finite(helper.maxConcurrent),
|
|
605
1210
|
finite(steadyResources.captureHelperCountPeak)
|
|
606
1211
|
);
|
|
1212
|
+
const resourceBudget = MAC_ACTIVE_MOTION_RESOURCE_BUDGET;
|
|
1213
|
+
const startupPrimeBudget = MAC_STARTUP_PRIME_RESOURCE_BUDGET;
|
|
1214
|
+
const startupPrimeObserved = {
|
|
1215
|
+
samples: Math.max(0, Math.round(finite(startupPrimeResources.sampleCount))),
|
|
1216
|
+
durationMs: Math.max(0, finite(startupPrimeResources.durationMs, -1)),
|
|
1217
|
+
ownedCpuPercentP95: Math.max(0, finite(startupPrimeResources.ownedCpuPercentP95)),
|
|
1218
|
+
ownedCpuPercentPeak: Math.max(0, finite(startupPrimeResources.ownedCpuPercentPeak)),
|
|
1219
|
+
ownedRssBytesPeak: Math.max(
|
|
1220
|
+
0,
|
|
1221
|
+
Math.round(finite(startupPrimeResources.ownedRssBytesPeak))
|
|
1222
|
+
),
|
|
1223
|
+
ownedProcessCountPeak: Math.max(
|
|
1224
|
+
0,
|
|
1225
|
+
Math.round(finite(startupPrimeResources.ownedProcessCountPeak))
|
|
1226
|
+
),
|
|
1227
|
+
ownedChildProcessCountPeak: Math.max(
|
|
1228
|
+
0,
|
|
1229
|
+
Math.round(finite(startupPrimeResources.ownedChildProcessCountPeak))
|
|
1230
|
+
),
|
|
1231
|
+
captureHelperCountPeak: Math.max(
|
|
1232
|
+
0,
|
|
1233
|
+
Math.round(finite(startupPrimeResources.captureHelperCountPeak))
|
|
1234
|
+
)
|
|
1235
|
+
};
|
|
1236
|
+
const startupPrimeWithinBudget =
|
|
1237
|
+
startupPrimeObserved.samples >= startupPrimeBudget.minimumSamples
|
|
1238
|
+
&& startupPrimeObserved.durationMs > 0
|
|
1239
|
+
&& startupPrimeObserved.durationMs <= startupPrimeBudget.maximumDurationMs
|
|
1240
|
+
&& startupPrimeObserved.ownedCpuPercentP95
|
|
1241
|
+
<= startupPrimeBudget.ownedCpuPercentP95Max
|
|
1242
|
+
&& startupPrimeObserved.ownedCpuPercentPeak
|
|
1243
|
+
<= startupPrimeBudget.ownedCpuPercentPeakMax
|
|
1244
|
+
&& startupPrimeObserved.ownedRssBytesPeak
|
|
1245
|
+
<= startupPrimeBudget.ownedRssBytesPeakMax
|
|
1246
|
+
&& startupPrimeObserved.ownedProcessCountPeak
|
|
1247
|
+
<= startupPrimeBudget.ownedProcessCountPeakMax
|
|
1248
|
+
&& startupPrimeObserved.ownedChildProcessCountPeak
|
|
1249
|
+
<= startupPrimeBudget.ownedChildProcessCountPeakMax
|
|
1250
|
+
&& startupPrimeObserved.captureHelperCountPeak
|
|
1251
|
+
<= startupPrimeBudget.captureHelperCountPeakMax
|
|
1252
|
+
&& (!Array.isArray(startupPrimeResources.unownedLiveDeskPids)
|
|
1253
|
+
|| startupPrimeResources.unownedLiveDeskPids.length === 0);
|
|
1254
|
+
const resourceRoleObservations = Object.fromEntries(
|
|
1255
|
+
(Array.isArray(steadyResources.roles) ? steadyResources.roles : [])
|
|
1256
|
+
.map(roleInfo => [String(roleInfo?.role || ''), roleInfo])
|
|
1257
|
+
.filter(([role]) => MAC_PRODUCT_RESOURCE_ROLES.has(role))
|
|
1258
|
+
);
|
|
1259
|
+
const resourceRoleChecks = Object.entries(resourceBudget.roleBudgets).map(([role, roleBudget]) => {
|
|
1260
|
+
const observed = resourceRoleObservations[role] || {};
|
|
1261
|
+
return {
|
|
1262
|
+
role,
|
|
1263
|
+
available: finite(observed.sampleCount) >= resourceBudget.minimumSteadySamples,
|
|
1264
|
+
processCountPeak: Math.max(0, Math.round(finite(observed.processCountPeak))),
|
|
1265
|
+
cpuPercentP95: Math.max(0, finite(observed.cpuPercentP95)),
|
|
1266
|
+
cpuPercentPeak: Math.max(0, finite(observed.cpuPercentPeak)),
|
|
1267
|
+
rssBytesPeak: Math.max(0, Math.round(finite(observed.rssBytesPeak))),
|
|
1268
|
+
budget: roleBudget
|
|
1269
|
+
};
|
|
1270
|
+
});
|
|
1271
|
+
const resourceRolesWithinBudget = resourceRoleChecks.every(roleInfo =>
|
|
1272
|
+
roleInfo.available
|
|
1273
|
+
&& roleInfo.processCountPeak <= roleInfo.budget.processCountPeakMax
|
|
1274
|
+
&& roleInfo.cpuPercentP95 <= roleInfo.budget.cpuPercentP95Max
|
|
1275
|
+
&& roleInfo.cpuPercentPeak <= roleInfo.budget.cpuPercentPeakMax
|
|
1276
|
+
&& roleInfo.rssBytesPeak <= roleInfo.budget.rssBytesPeakMax
|
|
1277
|
+
);
|
|
1278
|
+
const resourceBudgetObserved = {
|
|
1279
|
+
steadySamples: Math.max(0, Math.round(finite(steadyResources.sampleCount))),
|
|
1280
|
+
ownedCpuPercentP95: Math.max(0, finite(steadyResources.ownedCpuPercentP95)),
|
|
1281
|
+
ownedCpuPercentPeak: Math.max(0, finite(steadyResources.ownedCpuPercentPeak)),
|
|
1282
|
+
ownedRssBytesPeak: Math.max(0, Math.round(finite(steadyResources.ownedRssBytesPeak))),
|
|
1283
|
+
ownedProcessCountPeak: Math.max(0, Math.round(finite(steadyResources.ownedProcessCountPeak))),
|
|
1284
|
+
ownedChildProcessCountPeak: Math.max(
|
|
1285
|
+
0,
|
|
1286
|
+
Math.round(finite(steadyResources.ownedChildProcessCountPeak))
|
|
1287
|
+
),
|
|
1288
|
+
captureHelperCountPeak: Math.max(0, Math.round(resourceHelperPeak))
|
|
1289
|
+
};
|
|
1290
|
+
const resourceWithinBudget = resourceBudgetObserved.steadySamples
|
|
1291
|
+
>= resourceBudget.minimumSteadySamples
|
|
1292
|
+
&& resourceBudgetObserved.ownedCpuPercentP95 <= resourceBudget.ownedCpuPercentP95Max
|
|
1293
|
+
&& resourceBudgetObserved.ownedCpuPercentPeak <= resourceBudget.ownedCpuPercentPeakMax
|
|
1294
|
+
&& resourceBudgetObserved.ownedRssBytesPeak <= resourceBudget.ownedRssBytesPeakMax
|
|
1295
|
+
&& resourceBudgetObserved.ownedProcessCountPeak <= resourceBudget.ownedProcessCountPeakMax
|
|
1296
|
+
&& resourceBudgetObserved.ownedChildProcessCountPeak
|
|
1297
|
+
<= resourceBudget.ownedChildProcessCountPeakMax
|
|
1298
|
+
&& resourceBudgetObserved.captureHelperCountPeak
|
|
1299
|
+
<= resourceBudget.captureHelperCountPeakMax
|
|
1300
|
+
&& resourceRolesWithinBudget;
|
|
607
1301
|
const highCpuProcesses = steadyProcesses
|
|
608
1302
|
.filter(processInfo =>
|
|
609
|
-
|
|
610
|
-
|
|
1303
|
+
processInfo?.productProcess === true
|
|
1304
|
+
&& (
|
|
1305
|
+
finite(processInfo?.cpuPercentP95) >= 80
|
|
1306
|
+
|| finite(processInfo?.cpuPercentPeak) >= 100
|
|
1307
|
+
)
|
|
611
1308
|
)
|
|
612
1309
|
.map(processInfo => ({
|
|
613
1310
|
role: String(processInfo?.role || ''),
|
|
@@ -657,12 +1354,88 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
657
1354
|
const lifecycleRegistryFresh = Number.isFinite(lifecycleCompletedAtMs)
|
|
658
1355
|
&& Number.isFinite(registrySampledAtMs)
|
|
659
1356
|
&& registrySampledAtMs >= lifecycleCompletedAtMs;
|
|
1357
|
+
const videoToolboxSessionMaxConcurrent = finite(
|
|
1358
|
+
helper.videoToolboxSessionMaxConcurrent,
|
|
1359
|
+
-1
|
|
1360
|
+
);
|
|
1361
|
+
const videoToolboxSessionFinalCount = finite(
|
|
1362
|
+
helper.videoToolboxSessionFinalCount,
|
|
1363
|
+
-1
|
|
1364
|
+
);
|
|
1365
|
+
const nativeTerminalLifecycle = helper.nativeTerminalLifecycle || {};
|
|
1366
|
+
const finalHelperIdentity = lifecycle.finalHelperIdentity || {};
|
|
1367
|
+
const finalHelperStartedAtMs = Date.parse(String(finalHelperIdentity.startedAt || ''));
|
|
1368
|
+
const finalHelperObservedAtMs = Date.parse(String(finalHelperIdentity.observedAt || ''));
|
|
1369
|
+
const finalStopRequestedAtMs = Date.parse(String(lifecycle.finalStopRequestedAt || ''));
|
|
1370
|
+
const finalStopAcknowledgedAtMs = Date.parse(String(lifecycle.finalStopAcknowledgedAt || ''));
|
|
1371
|
+
const terminalObservedAtMs = Date.parse(
|
|
1372
|
+
String(nativeTerminalLifecycle.terminalObservedAt || '')
|
|
1373
|
+
);
|
|
1374
|
+
const nativeTerminalOwnerBound =
|
|
1375
|
+
Number.isInteger(Number(finalHelperIdentity.observationId))
|
|
1376
|
+
&& finite(finalHelperIdentity.observationId) > 0
|
|
1377
|
+
&& Number.isInteger(Number(finalHelperIdentity.processId))
|
|
1378
|
+
&& finite(finalHelperIdentity.processId) > 1
|
|
1379
|
+
&& Number.isInteger(Number(finalHelperIdentity.osProcessId))
|
|
1380
|
+
&& finite(finalHelperIdentity.osProcessId) > 1
|
|
1381
|
+
&& finite(finalHelperIdentity.osProcessId) === finite(finalHelperIdentity.processId)
|
|
1382
|
+
&& helperPids.includes(finite(finalHelperIdentity.osProcessId))
|
|
1383
|
+
&& String(finalHelperIdentity.profileName || '').startsWith('macos-screencapturekit')
|
|
1384
|
+
&& Number.isFinite(finalHelperStartedAtMs)
|
|
1385
|
+
&& Number.isFinite(finalHelperObservedAtMs)
|
|
1386
|
+
&& finalHelperObservedAtMs >= finalHelperStartedAtMs
|
|
1387
|
+
&& String(finalHelperIdentity.streamPurpose || '') === 'wall'
|
|
1388
|
+
&& finite(finalHelperIdentity.captureGeneration)
|
|
1389
|
+
=== finite(lifecycle.restoredWallGeneration)
|
|
1390
|
+
&& String(finalHelperIdentity.streamId || '').length > 0
|
|
1391
|
+
&& String(finalHelperIdentity.streamId || '')
|
|
1392
|
+
=== String(lifecycle.finalStopStreamId || '')
|
|
1393
|
+
&& finite(nativeTerminalLifecycle.observationId)
|
|
1394
|
+
=== finite(finalHelperIdentity.observationId)
|
|
1395
|
+
&& finite(nativeTerminalLifecycle.processId)
|
|
1396
|
+
=== finite(finalHelperIdentity.processId)
|
|
1397
|
+
&& String(nativeTerminalLifecycle.profileName || '')
|
|
1398
|
+
=== String(finalHelperIdentity.profileName || '')
|
|
1399
|
+
&& Date.parse(String(nativeTerminalLifecycle.startedAt || '')) === finalHelperStartedAtMs
|
|
1400
|
+
&& Number.isFinite(finalStopRequestedAtMs)
|
|
1401
|
+
&& Number.isFinite(finalStopAcknowledgedAtMs)
|
|
1402
|
+
&& finalStopRequestedAtMs >= finalHelperObservedAtMs
|
|
1403
|
+
&& finalStopAcknowledgedAtMs >= finalStopRequestedAtMs
|
|
1404
|
+
&& lifecycleCompletedAtMs >= finalStopAcknowledgedAtMs
|
|
1405
|
+
&& Number.isFinite(terminalObservedAtMs)
|
|
1406
|
+
&& terminalObservedAtMs >= finalStopRequestedAtMs
|
|
1407
|
+
&& terminalObservedAtMs <= lifecycleCompletedAtMs
|
|
1408
|
+
&& registrySampledAtMs >= terminalObservedAtMs;
|
|
1409
|
+
const nativeTerminalClean = nativeTerminalLifecycle.terminalTelemetryAvailable === true
|
|
1410
|
+
&& nativeTerminalLifecycle.terminalClean === true
|
|
1411
|
+
&& finite(nativeTerminalLifecycle.terminalTelemetryVersion) >= 5
|
|
1412
|
+
&& finite(nativeTerminalLifecycle.terminalEncodeFramesInFlight, -1) === 0
|
|
1413
|
+
&& finite(nativeTerminalLifecycle.terminalPendingEncodeFrameCount, -1) === 0
|
|
1414
|
+
&& finite(nativeTerminalLifecycle.terminalEncodeTimestampOwnerCount, -1) === 0
|
|
1415
|
+
&& finite(nativeTerminalLifecycle.terminalEncodeTimestampOwnerHighWatermark, -1) >= 1
|
|
1416
|
+
&& finite(nativeTerminalLifecycle.terminalEncodeTimestampOwnerHighWatermark, -1) <= 2
|
|
1417
|
+
&& finite(nativeTerminalLifecycle.terminalVideoToolboxActiveSessionCount, -1) === 0
|
|
1418
|
+
&& finite(nativeTerminalLifecycle.terminalVideoToolboxSessionHighWatermark, -1) === 1
|
|
1419
|
+
&& Number.isFinite(Date.parse(String(nativeTerminalLifecycle.terminalObservedAt || '')));
|
|
660
1420
|
const checks = [
|
|
661
1421
|
check(
|
|
662
1422
|
'report-schema',
|
|
663
|
-
schemaVersion ===
|
|
1423
|
+
schemaVersion === 4,
|
|
664
1424
|
`v${schemaVersion || 'missing'}`
|
|
665
1425
|
),
|
|
1426
|
+
check(
|
|
1427
|
+
'active-motion-profile',
|
|
1428
|
+
activeMotionProfileMatches,
|
|
1429
|
+
`${finite(motion.width)}x${finite(motion.height)}@${requestedFps} `
|
|
1430
|
+
+ `motion=${String(motion.kind || '-')} waiver=${motion.idleCadenceWaiverAllowed === true}`
|
|
1431
|
+
),
|
|
1432
|
+
check(
|
|
1433
|
+
'active-motion-operator',
|
|
1434
|
+
activeMotionOperatorConfirmed,
|
|
1435
|
+
activeMotionOperatorConfirmed
|
|
1436
|
+
? motion.operatorRequirement
|
|
1437
|
+
: 'pass --confirm-active-motion after starting continuous motion on both displays'
|
|
1438
|
+
),
|
|
666
1439
|
check(
|
|
667
1440
|
'diagnostic-run',
|
|
668
1441
|
!runError,
|
|
@@ -712,6 +1485,13 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
712
1485
|
+ `max=${finite(lifecycle.registryMaxConcurrent, -1)} `
|
|
713
1486
|
+ `final=${finite(lifecycle.registryFinalHelperCount, -1)}`
|
|
714
1487
|
),
|
|
1488
|
+
check(
|
|
1489
|
+
'capture-lifecycle-sequential-restarts',
|
|
1490
|
+
finite(lifecycle.registryHelperStartCount, -1) === 4
|
|
1491
|
+
&& finite(lifecycle.registryHelperStopCount, -1) === 4,
|
|
1492
|
+
`starts=${finite(lifecycle.registryHelperStartCount, -1)} `
|
|
1493
|
+
+ `stops=${finite(lifecycle.registryHelperStopCount, -1)} expected=4/4`
|
|
1494
|
+
),
|
|
715
1495
|
check(
|
|
716
1496
|
'capture-lifecycle-stop',
|
|
717
1497
|
lifecycle.controlStopConfirmed === true
|
|
@@ -734,6 +1514,16 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
734
1514
|
stageEvidenceAvailable,
|
|
735
1515
|
stageEvidenceAvailable ? requiredStageNames.join(',') : 'initial and switched stages required'
|
|
736
1516
|
),
|
|
1517
|
+
check(
|
|
1518
|
+
'active-motion-proof',
|
|
1519
|
+
activeMotionProven,
|
|
1520
|
+
stageEvaluations.map(stage =>
|
|
1521
|
+
`${stage.name}=${stage.motionProven ? 'proven' : 'unproven'} `
|
|
1522
|
+
+ `pixels=${finite(stage.motionProof.distinctDecodedPixelHashCount)} `
|
|
1523
|
+
+ `au=${finite(stage.motionProof.distinctAccessUnitHashCount)} `
|
|
1524
|
+
+ `native=${finite(stage.motionProof.captureSampleDelta)}`
|
|
1525
|
+
).join(' ')
|
|
1526
|
+
),
|
|
737
1527
|
check(
|
|
738
1528
|
'native-profile',
|
|
739
1529
|
snapshot.platformProfile === 'macos-screencapturekit-nv12-videotoolbox',
|
|
@@ -760,6 +1550,18 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
760
1550
|
.map(stage => `${stage.name}=${stage.hardwareAccelerated ? 'hardware' : 'not-confirmed'}`)
|
|
761
1551
|
.join(' ')
|
|
762
1552
|
),
|
|
1553
|
+
check(
|
|
1554
|
+
'native-encode-ownership',
|
|
1555
|
+
nativeEncodeOwnershipBounded,
|
|
1556
|
+
stageEvaluations.map(stage =>
|
|
1557
|
+
`${stage.name}=inFlight:${stage.encodeFramesInFlight}`
|
|
1558
|
+
+ `/pending:${stage.pendingEncodeFrameCount}`
|
|
1559
|
+
+ `/timestampOwners:${stage.encodeTimestampOwnerCount}`
|
|
1560
|
+
+ `/timestampOwnerHigh:${stage.encodeTimestampOwnerHighWatermark}`
|
|
1561
|
+
+ `/vt:${stage.videoToolboxActiveSessionCount}`
|
|
1562
|
+
+ `/high:${stage.videoToolboxSessionHighWatermark}`
|
|
1563
|
+
).join(' ')
|
|
1564
|
+
),
|
|
763
1565
|
check(
|
|
764
1566
|
'screencapturekit-fps',
|
|
765
1567
|
captureAtTarget,
|
|
@@ -791,7 +1593,37 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
791
1593
|
'delivered-fps',
|
|
792
1594
|
deliveredAtTarget,
|
|
793
1595
|
`${stageMetricDetail('deliveredFps')} target=${requestedFps}`
|
|
794
|
-
+ `${idleOptimized ? ' idle-
|
|
1596
|
+
+ `${idleOptimized ? ' idle-detected-active-gate' : ''}`
|
|
1597
|
+
),
|
|
1598
|
+
check(
|
|
1599
|
+
'encode-backpressure',
|
|
1600
|
+
backpressureFree,
|
|
1601
|
+
stageEvaluations
|
|
1602
|
+
.map(stage => `${stage.name}=${stage.backpressureSkipped}`)
|
|
1603
|
+
.join(' ')
|
|
1604
|
+
),
|
|
1605
|
+
check(
|
|
1606
|
+
'current-frame-queue-pressure',
|
|
1607
|
+
currentFrameQueuesBounded,
|
|
1608
|
+
stageEvaluations.map(stage =>
|
|
1609
|
+
`${stage.name}=nativeDrop:${stage.outputDropped}`
|
|
1610
|
+
+ `/nativeOldest:${stage.outputOldestAgeMs}`
|
|
1611
|
+
+ `/nativeAwait:${stage.telemetry.outputAwaitingKeyFrame === true ? 1 : 0}`
|
|
1612
|
+
+ `/age:${stage.nativeAndPipeResidenceAgeMs}`
|
|
1613
|
+
+ `/handoffDrop:${stage.handoffDropped}`
|
|
1614
|
+
+ `/recovery:${stage.handoffRecoveryRequests}`
|
|
1615
|
+
+ `/handoffOldest:${stage.handoffOldestAgeMs}`
|
|
1616
|
+
).join(' ')
|
|
1617
|
+
),
|
|
1618
|
+
check(
|
|
1619
|
+
'payload-copy-accounting',
|
|
1620
|
+
payloadCopyAccountingCurrent,
|
|
1621
|
+
stageEvaluations.map(stage =>
|
|
1622
|
+
`${stage.name}=annexB:${stage.annexBAllocations}`
|
|
1623
|
+
+ `/${stage.annexBPayloadCopies}/${stage.annexBPayloadCopiedBytes}`
|
|
1624
|
+
+ ` pipe:${stage.pipePayloadAllocations}`
|
|
1625
|
+
+ `/${stage.pipePayloadCopies}/${stage.pipePayloadCopiedBytes}`
|
|
1626
|
+
).join(' ')
|
|
795
1627
|
),
|
|
796
1628
|
check(
|
|
797
1629
|
'single-helper',
|
|
@@ -799,17 +1631,70 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
799
1631
|
`max=${resourceHelperPeak} pids=${helperPids.join(',') || '-'}`
|
|
800
1632
|
),
|
|
801
1633
|
check('helper-drained', finite(helper.finalCount) === 0, `final=${finite(helper.finalCount)}`),
|
|
1634
|
+
check(
|
|
1635
|
+
'single-videotoolbox-session',
|
|
1636
|
+
videoToolboxSessionMaxConcurrent === 1
|
|
1637
|
+
&& videoToolboxSessionFinalCount === 0,
|
|
1638
|
+
`max=${videoToolboxSessionMaxConcurrent} final=${videoToolboxSessionFinalCount} `
|
|
1639
|
+
+ 'proof=one-session-per-exact-helper'
|
|
1640
|
+
),
|
|
1641
|
+
check(
|
|
1642
|
+
'videotoolbox-terminal-cleanup',
|
|
1643
|
+
nativeTerminalClean,
|
|
1644
|
+
`available=${nativeTerminalLifecycle.terminalTelemetryAvailable === true} `
|
|
1645
|
+
+ `clean=${nativeTerminalLifecycle.terminalClean === true} `
|
|
1646
|
+
+ `v=${finite(nativeTerminalLifecycle.terminalTelemetryVersion)} `
|
|
1647
|
+
+ `inFlight=${finite(nativeTerminalLifecycle.terminalEncodeFramesInFlight, -1)} `
|
|
1648
|
+
+ `pending=${finite(nativeTerminalLifecycle.terminalPendingEncodeFrameCount, -1)} `
|
|
1649
|
+
+ `timestampOwners=${finite(nativeTerminalLifecycle.terminalEncodeTimestampOwnerCount, -1)} `
|
|
1650
|
+
+ `timestampOwnerHigh=${finite(nativeTerminalLifecycle.terminalEncodeTimestampOwnerHighWatermark, -1)} `
|
|
1651
|
+
+ `vt=${finite(nativeTerminalLifecycle.terminalVideoToolboxActiveSessionCount, -1)} `
|
|
1652
|
+
+ `high=${finite(nativeTerminalLifecycle.terminalVideoToolboxSessionHighWatermark, -1)}`
|
|
1653
|
+
),
|
|
1654
|
+
check(
|
|
1655
|
+
'videotoolbox-terminal-owner',
|
|
1656
|
+
nativeTerminalOwnerBound,
|
|
1657
|
+
`observation=${finite(finalHelperIdentity.observationId)}/${finite(nativeTerminalLifecycle.observationId)} `
|
|
1658
|
+
+ `pid=${finite(finalHelperIdentity.processId)}/${finite(nativeTerminalLifecycle.processId)} `
|
|
1659
|
+
+ `os=${finite(finalHelperIdentity.osProcessId)}`
|
|
1660
|
+
+ `/${helperPids.includes(finite(finalHelperIdentity.osProcessId)) ? 'observed' : 'missing'} `
|
|
1661
|
+
+ `profile=${String(finalHelperIdentity.profileName || '-') === String(nativeTerminalLifecycle.profileName || '-') ? 'match' : 'mismatch'} `
|
|
1662
|
+
+ `generation=${finite(finalHelperIdentity.captureGeneration)}/${finite(lifecycle.restoredWallGeneration)} `
|
|
1663
|
+
+ `purpose=${String(finalHelperIdentity.streamPurpose || '-')} `
|
|
1664
|
+
+ `stream=${String(finalHelperIdentity.streamId || '') === String(lifecycle.finalStopStreamId || '') ? 'match' : 'mismatch'} `
|
|
1665
|
+
+ `stop=${String(lifecycle.finalStopRequestedAt || '-')} `
|
|
1666
|
+
+ `terminal=${String(nativeTerminalLifecycle.terminalObservedAt || '-')}`
|
|
1667
|
+
),
|
|
802
1668
|
check(
|
|
803
1669
|
'process-telemetry',
|
|
804
1670
|
resourceTelemetryAvailable,
|
|
805
1671
|
resourceTelemetryAvailable
|
|
806
|
-
? `baseline=${finite(baselineResources.sampleCount)} steady=${finite(steadyResources.sampleCount)} cleanup=${finite(cleanupResources.sampleCount)}`
|
|
807
|
-
: 'baseline, steady-capture, and after-cleanup samples are required'
|
|
1672
|
+
? `baseline=${finite(baselineResources.sampleCount)} prime=${finite(startupPrimeResources.sampleCount)} steady=${finite(steadyResources.sampleCount)} cleanup=${finite(cleanupResources.sampleCount)}`
|
|
1673
|
+
: 'baseline, cold startup-prime, steady-capture, and after-cleanup samples are required'
|
|
1674
|
+
),
|
|
1675
|
+
check(
|
|
1676
|
+
'startup-prime-resource-budget',
|
|
1677
|
+
resourceTelemetryAvailable && startupPrimeWithinBudget,
|
|
1678
|
+
`samples=${startupPrimeObserved.samples}/${startupPrimeBudget.minimumSamples} `
|
|
1679
|
+
+ `duration=${startupPrimeObserved.durationMs}/${startupPrimeBudget.maximumDurationMs}ms `
|
|
1680
|
+
+ `cpu-p95=${startupPrimeObserved.ownedCpuPercentP95}`
|
|
1681
|
+
+ `/${startupPrimeBudget.ownedCpuPercentP95Max}% `
|
|
1682
|
+
+ `cpu-peak=${startupPrimeObserved.ownedCpuPercentPeak}`
|
|
1683
|
+
+ `/${startupPrimeBudget.ownedCpuPercentPeakMax}% `
|
|
1684
|
+
+ `rss=${startupPrimeObserved.ownedRssBytesPeak}`
|
|
1685
|
+
+ `/${startupPrimeBudget.ownedRssBytesPeakMax} `
|
|
1686
|
+
+ `processes=${startupPrimeObserved.ownedProcessCountPeak}`
|
|
1687
|
+
+ `/${startupPrimeBudget.ownedProcessCountPeakMax} `
|
|
1688
|
+
+ `children=${startupPrimeObserved.ownedChildProcessCountPeak}`
|
|
1689
|
+
+ `/${startupPrimeBudget.ownedChildProcessCountPeakMax}`
|
|
808
1690
|
),
|
|
809
1691
|
check(
|
|
810
1692
|
'resource-ownership',
|
|
811
1693
|
resourceTelemetryAvailable && resourceOwnershipCurrent,
|
|
812
|
-
`
|
|
1694
|
+
`model=${String(resources.ownershipModel || '-')} `
|
|
1695
|
+
+ `labels=${resourceOwnershipLabelsCurrent ? 'exact' : 'invalid'} `
|
|
1696
|
+
+ `topology=${exactSteadyTopologyCurrent ? '5/3' : `${steadyOwnedProcessCounts.join(',') || '-'}/${steadyOwnedChildCounts.join(',') || '-'}`} `
|
|
1697
|
+
+ `baseline=${finite(baselineResources.totalLiveDeskProcessCountPeak)} `
|
|
813
1698
|
+ `steady=${finite(steadyResources.totalLiveDeskProcessCountPeak)} `
|
|
814
1699
|
+ `unowned=${Array.isArray(steadyResources.unownedLiveDeskPids) ? steadyResources.unownedLiveDeskPids.join(',') || '-' : '-'}`
|
|
815
1700
|
),
|
|
@@ -819,6 +1704,36 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
819
1704
|
`final=${finite(cleanupResources.totalLiveDeskProcessCount)} `
|
|
820
1705
|
+ `peak=${finite(cleanupResources.totalLiveDeskProcessCountPeak)}`
|
|
821
1706
|
),
|
|
1707
|
+
check(
|
|
1708
|
+
'active-motion-resource-budget',
|
|
1709
|
+
resourceTelemetryAvailable && resourceWithinBudget,
|
|
1710
|
+
`samples=${resourceBudgetObserved.steadySamples}/${resourceBudget.minimumSteadySamples} `
|
|
1711
|
+
+ `cpu-p95=${resourceBudgetObserved.ownedCpuPercentP95}`
|
|
1712
|
+
+ `/${resourceBudget.ownedCpuPercentP95Max}% `
|
|
1713
|
+
+ `cpu-peak=${resourceBudgetObserved.ownedCpuPercentPeak}`
|
|
1714
|
+
+ `/${resourceBudget.ownedCpuPercentPeakMax}% `
|
|
1715
|
+
+ `rss=${resourceBudgetObserved.ownedRssBytesPeak}`
|
|
1716
|
+
+ `/${resourceBudget.ownedRssBytesPeakMax} `
|
|
1717
|
+
+ `processes=${resourceBudgetObserved.ownedProcessCountPeak}`
|
|
1718
|
+
+ `/${resourceBudget.ownedProcessCountPeakMax} `
|
|
1719
|
+
+ `children=${resourceBudgetObserved.ownedChildProcessCountPeak}`
|
|
1720
|
+
+ `/${resourceBudget.ownedChildProcessCountPeakMax} `
|
|
1721
|
+
+ resourceRoleChecks.map(roleInfo =>
|
|
1722
|
+
`${roleInfo.role}:cpu=${roleInfo.cpuPercentP95}/${roleInfo.budget.cpuPercentP95Max}`
|
|
1723
|
+
+ ` rss=${roleInfo.rssBytesPeak}/${roleInfo.budget.rssBytesPeakMax}`
|
|
1724
|
+
+ ` proc=${roleInfo.processCountPeak}/${roleInfo.budget.processCountPeakMax}`
|
|
1725
|
+
).join(' ')
|
|
1726
|
+
),
|
|
1727
|
+
check(
|
|
1728
|
+
'resource-baseline-return',
|
|
1729
|
+
resourceTelemetryAvailable && resourceReturnedToBaseline,
|
|
1730
|
+
`processes=${finite(baselineResources.ownedProcessCountPeak)}`
|
|
1731
|
+
+ `->${finite(cleanupResources.ownedProcessCountPeak)} `
|
|
1732
|
+
+ `children=${finite(baselineResources.ownedChildProcessCountPeak)}`
|
|
1733
|
+
+ `->${finite(cleanupResources.ownedChildProcessCountPeak)} `
|
|
1734
|
+
+ `rss=${finite(baselineResources.ownedRssBytesPeak)}`
|
|
1735
|
+
+ `->${finite(cleanupResources.ownedRssBytesPeak)}`
|
|
1736
|
+
),
|
|
822
1737
|
check('two-monitors', finite(monitor.count) >= 2, `count=${finite(monitor.count)}`),
|
|
823
1738
|
check(
|
|
824
1739
|
'monitor-generation',
|
|
@@ -862,6 +1777,8 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
862
1777
|
const failed = checks.filter(item => !item.ok);
|
|
863
1778
|
const bottleneckByCheck = {
|
|
864
1779
|
'report-schema': 'report-schema',
|
|
1780
|
+
'active-motion-profile': 'active-motion-profile',
|
|
1781
|
+
'active-motion-operator': 'active-motion-operator',
|
|
865
1782
|
'diagnostic-run': 'diagnostic-run',
|
|
866
1783
|
'diagnostic-cleanup': 'diagnostic-cleanup',
|
|
867
1784
|
'capture-lifecycle-order': 'capture-lifecycle-order',
|
|
@@ -869,22 +1786,34 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
869
1786
|
'capture-lifecycle-pause': 'capture-pause-resume',
|
|
870
1787
|
'capture-lifecycle-helper': 'capture-helper-lifecycle',
|
|
871
1788
|
'capture-lifecycle-registry': 'capture-helper-registry',
|
|
1789
|
+
'capture-lifecycle-sequential-restarts': 'capture-helper-restart-storm',
|
|
872
1790
|
'capture-lifecycle-stop': 'capture-stop',
|
|
873
1791
|
'first-frame': 'capture-startup',
|
|
874
1792
|
'monitor-first-frame': 'monitor-restart',
|
|
875
1793
|
'capture-stage-evidence': 'capture-stage-evidence',
|
|
1794
|
+
'active-motion-proof': 'active-motion-not-proven',
|
|
876
1795
|
'native-profile': 'capture-fallback',
|
|
877
1796
|
'telemetry-current': 'native-telemetry-stale',
|
|
878
1797
|
'hardware-videotoolbox': 'videotoolbox-software',
|
|
1798
|
+
'native-encode-ownership': 'videotoolbox-ownership',
|
|
879
1799
|
'screencapturekit-fps': 'screencapturekit',
|
|
880
1800
|
'videotoolbox-fps': 'videotoolbox',
|
|
881
1801
|
'stdout-fps': 'native-stdout',
|
|
882
1802
|
'delivered-fps': 'agent-or-transport',
|
|
1803
|
+
'encode-backpressure': 'videotoolbox-backpressure',
|
|
1804
|
+
'current-frame-queue-pressure': 'current-frame-queue-pressure',
|
|
1805
|
+
'payload-copy-accounting': 'payload-copy-accounting',
|
|
883
1806
|
'single-helper': 'duplicate-helper',
|
|
884
1807
|
'helper-drained': 'stale-helper',
|
|
1808
|
+
'single-videotoolbox-session': 'videotoolbox-ownership',
|
|
1809
|
+
'videotoolbox-terminal-cleanup': 'videotoolbox-terminal-cleanup',
|
|
1810
|
+
'videotoolbox-terminal-owner': 'videotoolbox-terminal-owner',
|
|
885
1811
|
'process-telemetry': 'process-telemetry',
|
|
1812
|
+
'startup-prime-resource-budget': 'startup-prime-resource-budget',
|
|
886
1813
|
'resource-ownership': 'resource-ownership',
|
|
887
1814
|
'resource-drained': 'resource-not-drained',
|
|
1815
|
+
'active-motion-resource-budget': 'resource-budget',
|
|
1816
|
+
'resource-baseline-return': 'resource-not-returned',
|
|
888
1817
|
'two-monitors': 'monitor-topology',
|
|
889
1818
|
'monitor-generation': 'monitor-generation',
|
|
890
1819
|
'monitor-native-identity': 'monitor-binding',
|
|
@@ -899,7 +1828,16 @@ export function classifyMacPhysicalGate(snapshot = {}) {
|
|
|
899
1828
|
processTelemetry: {
|
|
900
1829
|
available: resourceTelemetryAvailable,
|
|
901
1830
|
highLoad: highCpuProcesses.length > 0,
|
|
902
|
-
highLoadProcesses: highCpuProcesses
|
|
1831
|
+
highLoadProcesses: highCpuProcesses,
|
|
1832
|
+
budget: { ...resourceBudget },
|
|
1833
|
+
observed: resourceBudgetObserved,
|
|
1834
|
+
startupPrime: {
|
|
1835
|
+
budget: { ...startupPrimeBudget },
|
|
1836
|
+
observed: startupPrimeObserved,
|
|
1837
|
+
withinBudget: startupPrimeWithinBudget
|
|
1838
|
+
},
|
|
1839
|
+
roles: resourceRoleChecks,
|
|
1840
|
+
returnedToBaseline: resourceReturnedToBaseline
|
|
903
1841
|
},
|
|
904
1842
|
checks
|
|
905
1843
|
};
|