pinokiod 8.0.45 → 8.0.46
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/kernel/gpu/amd_gfx_targets.json +3 -1
- package/kernel/gpu/amd_pci.js +184 -0
- package/kernel/gpu/amd_pci_targets.json +3243 -0
- package/kernel/sysinfo.js +6 -1
- package/kernel/vault/constants.js +2 -1
- package/kernel/vault/hash_worker.js +13 -1
- package/kernel/vault/index.js +71 -20
- package/kernel/vault/sweeper.js +15 -23
- package/package.json +2 -1
- package/script/update-amd-gfx-targets.js +289 -13
- package/server/lib/app_log_report.js +45 -3
- package/server/lib/log_redaction.js +26 -14
- package/server/public/nav.js +1 -1
- package/server/public/style.css +0 -1
- package/server/public/vault.js +24 -28
- package/server/views/vault.ejs +2 -0
- package/test/amd-gfx-generator.test.js +75 -0
- package/test/amd-gpu-target.test.js +108 -10
- package/test/amd-pci-target.test.js +159 -0
- package/test/app-log-report.test.js +67 -0
- package/test/header-collapse.test.js +10 -5
- package/test/sysinfo-gpu-driver.test.js +4 -0
- package/test/vault-engine.test.js +60 -1
- package/test/vault-sweep.test.js +50 -31
- package/test/vault-ui.test.js +97 -14
|
@@ -2,10 +2,12 @@ const fs = require('fs')
|
|
|
2
2
|
const os = require('os')
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const Environment = require('../../kernel/environment')
|
|
5
|
+
const { createCurrentSystemSnapshot } = require('./log_redaction')
|
|
5
6
|
|
|
6
7
|
const DEFAULT_TAIL_LINES = 800
|
|
7
8
|
const MAX_SECTION_CHARS = 120000
|
|
8
9
|
const SENSITIVE_ENV_KEY = /(?:TOKEN|SECRET|PASSWORD|PASSWD|PASSPHRASE|API[_-]?KEY|APIKEY|CREDENTIAL|COOKIE|SESSION|AUTH|PRIVATE[_-]?KEY)/i
|
|
10
|
+
const SENSITIVE_FIELD_KEY = /(?:^|[_-])(?:TOKEN|SECRET|PASSWORD|PASSWD|PASSPHRASE|API[_-]?KEY|APIKEY|CREDENTIAL|COOKIE|SESSION|AUTH|AUTHORIZATION|PRIVATE[_-]?KEY)(?:$|[_-])/i
|
|
9
11
|
|
|
10
12
|
const escapeRegExp = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
11
13
|
|
|
@@ -52,6 +54,13 @@ class AppLogReportService {
|
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
let systemSpec = this.buildSystemSpec()
|
|
58
|
+
if (redact) {
|
|
59
|
+
const redacted = this.redactStructuredValue(systemSpec, { appRoot, workspaceRoot })
|
|
60
|
+
systemSpec = redacted.value
|
|
61
|
+
this.mergeCounts(totals, redacted.counts)
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
const metadata = {
|
|
56
65
|
app_id: appId,
|
|
57
66
|
title: status.title || appId,
|
|
@@ -62,7 +71,7 @@ class AppLogReportService {
|
|
|
62
71
|
arch: os.arch(),
|
|
63
72
|
node: process.version,
|
|
64
73
|
tail_count: tailLines,
|
|
65
|
-
system_spec:
|
|
74
|
+
system_spec: systemSpec,
|
|
66
75
|
redaction_mode: redact ? 'server_deterministic' : 'none',
|
|
67
76
|
latest_session: sessionIndex.latest_session,
|
|
68
77
|
session: selectedSession,
|
|
@@ -305,6 +314,27 @@ class AppLogReportService {
|
|
|
305
314
|
}
|
|
306
315
|
}
|
|
307
316
|
|
|
317
|
+
redactStructuredValue(input, context = {}) {
|
|
318
|
+
const counts = {}
|
|
319
|
+
const json = JSON.stringify(input, (key, value) => {
|
|
320
|
+
const normalizedKey = String(key).replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
321
|
+
if (key && SENSITIVE_FIELD_KEY.test(normalizedKey) && value !== undefined && value !== null && value !== '') {
|
|
322
|
+
counts.env_secrets = (counts.env_secrets || 0) + 1
|
|
323
|
+
return '[REDACTED_SECRET]'
|
|
324
|
+
}
|
|
325
|
+
if (typeof value === 'string') {
|
|
326
|
+
const redacted = this.redactText(value, context)
|
|
327
|
+
this.mergeCounts(counts, redacted.counts)
|
|
328
|
+
return redacted.text
|
|
329
|
+
}
|
|
330
|
+
return value
|
|
331
|
+
})
|
|
332
|
+
return {
|
|
333
|
+
value: JSON.parse(json),
|
|
334
|
+
counts
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
308
338
|
renderMarkdown(metadata, sections, redactions) {
|
|
309
339
|
const lines = [
|
|
310
340
|
'# Issue Report',
|
|
@@ -418,9 +448,11 @@ class AppLogReportService {
|
|
|
418
448
|
buildSystemSpec() {
|
|
419
449
|
const kernel = this.kernel || {}
|
|
420
450
|
const info = kernel.sysinfo && typeof kernel.sysinfo === 'object' ? kernel.sysinfo : {}
|
|
421
|
-
|
|
451
|
+
const version = this.readPinokioVersion()
|
|
452
|
+
const snapshot = createCurrentSystemSnapshot(kernel, version)
|
|
453
|
+
const spec = this.compactObject({
|
|
422
454
|
pinokio: {
|
|
423
|
-
version
|
|
455
|
+
version,
|
|
424
456
|
node: process.version,
|
|
425
457
|
platform: kernel.platform || process.platform,
|
|
426
458
|
arch: kernel.arch || process.arch
|
|
@@ -438,6 +470,16 @@ class AppLogReportService {
|
|
|
438
470
|
gpus: this.sanitizeGpus(info.gpus),
|
|
439
471
|
graphics: this.sanitizeGraphics(info.graphics)
|
|
440
472
|
})
|
|
473
|
+
|
|
474
|
+
return {
|
|
475
|
+
...spec,
|
|
476
|
+
hardware: {
|
|
477
|
+
...spec.hardware,
|
|
478
|
+
gpu_driver: snapshot.gpu_driver ?? null,
|
|
479
|
+
gpu_target: snapshot.gpu_target ?? null
|
|
480
|
+
},
|
|
481
|
+
diagnostics: snapshot
|
|
482
|
+
}
|
|
441
483
|
}
|
|
442
484
|
|
|
443
485
|
sanitizeOsInfo(value) {
|
|
@@ -95,6 +95,28 @@ function createFallbackStateSnapshot(kernel) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function createCurrentSystemSnapshot(kernel, version) {
|
|
99
|
+
kernel = kernel || {}
|
|
100
|
+
return {
|
|
101
|
+
platform: kernel.platform,
|
|
102
|
+
arch: kernel.arch,
|
|
103
|
+
running: kernel.api && kernel.api.running,
|
|
104
|
+
home: kernel.homedir,
|
|
105
|
+
vars: kernel.vars,
|
|
106
|
+
memory: kernel.memory,
|
|
107
|
+
procs: kernel.procs,
|
|
108
|
+
gpu: kernel.gpu,
|
|
109
|
+
gpus: kernel.gpus,
|
|
110
|
+
gpu_model: kernel.gpu_model,
|
|
111
|
+
gpu_driver: kernel.gpu_driver,
|
|
112
|
+
gpu_target: kernel.gpu_target,
|
|
113
|
+
ram: kernel.ram,
|
|
114
|
+
vram: kernel.vram,
|
|
115
|
+
version,
|
|
116
|
+
...kernel.sysinfo
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
98
120
|
function createCurrentLogSnapshot(kernel, version) {
|
|
99
121
|
const liveShells = kernel && kernel.shell && Array.isArray(kernel.shell.shells)
|
|
100
122
|
? kernel.shell.shells
|
|
@@ -118,21 +140,10 @@ function createCurrentLogSnapshot(kernel, version) {
|
|
|
118
140
|
}
|
|
119
141
|
}
|
|
120
142
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
running: kernel.api.running,
|
|
125
|
-
home: kernel.homedir,
|
|
126
|
-
vars: kernel.vars,
|
|
127
|
-
memory: kernel.memory,
|
|
128
|
-
procs: kernel.procs,
|
|
129
|
-
gpu: kernel.gpu,
|
|
130
|
-
gpus: kernel.gpus,
|
|
131
|
-
version,
|
|
132
|
-
...kernel.sysinfo
|
|
143
|
+
return {
|
|
144
|
+
info: createCurrentSystemSnapshot(kernel, version),
|
|
145
|
+
states
|
|
133
146
|
}
|
|
134
|
-
|
|
135
|
-
return { info, states }
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
async function writeCurrentLogSnapshot(kernel, version) {
|
|
@@ -418,6 +429,7 @@ module.exports = {
|
|
|
418
429
|
LOG_REDACTION_FILE_MAX_BYTES,
|
|
419
430
|
isTopLevelRedactableLogPath,
|
|
420
431
|
normalizeTailLineCount,
|
|
432
|
+
createCurrentSystemSnapshot,
|
|
421
433
|
createCurrentLogSnapshot,
|
|
422
434
|
writeCurrentLogSnapshot,
|
|
423
435
|
normalizeLogRedactionOverrides,
|
package/server/public/nav.js
CHANGED
|
@@ -6,7 +6,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
6
6
|
|
|
7
7
|
const newWindowButton = document.querySelector("#new-window");
|
|
8
8
|
const agent = document.body.getAttribute("data-agent");
|
|
9
|
-
if (newWindowButton
|
|
9
|
+
if (newWindowButton) {
|
|
10
10
|
newWindowButton.addEventListener("click", (event) => {
|
|
11
11
|
if (agent === "electron") {
|
|
12
12
|
window.open("/", "_blank", "pinokio");
|
package/server/public/style.css
CHANGED
|
@@ -4536,7 +4536,6 @@ aside .qr {
|
|
|
4536
4536
|
body.main-sidebar-page > header.navheader #inspector,
|
|
4537
4537
|
body.main-sidebar-page > header.navheader #mobile-link-button,
|
|
4538
4538
|
body.main-sidebar-page > header.navheader .urlbar,
|
|
4539
|
-
body.main-sidebar-page > header.navheader #close-window,
|
|
4540
4539
|
body.main-sidebar-page > header.navheader .runner,
|
|
4541
4540
|
body.main-sidebar-page > header.navheader h1 > .path,
|
|
4542
4541
|
body.main-sidebar-page > header.navheader h1 > .nav-button,
|
package/server/public/vault.js
CHANGED
|
@@ -56,15 +56,13 @@ const COPY = {
|
|
|
56
56
|
scan_queued: "Waiting to start scan",
|
|
57
57
|
scan_analyzing: "Analyzing large files",
|
|
58
58
|
scan_finishing: "Finishing scan",
|
|
59
|
-
scan_estimate_help: "Overall progress combines file scanning and large-file analysis",
|
|
60
59
|
scan_counting_help: "The first scan cannot know its total until this pass finishes",
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
scan_hash_progress_help: "File discovery is complete; the remaining large-file count is exact",
|
|
60
|
+
scan_file_progress_help: "Based on the exact current file total",
|
|
61
|
+
scan_hash_progress_help: "Based on the exact large-file count and current-file bytes",
|
|
64
62
|
scan_finishing_help: "File analysis is complete; deduplication records are being verified",
|
|
65
|
-
about_percent: "About {percent} percent.",
|
|
66
63
|
exact_percent: "{percent} percent.",
|
|
67
64
|
scan_checked: "{done} of {total} large files checked",
|
|
65
|
+
scan_file_bytes: "{done} of {total}",
|
|
68
66
|
scan_files_checked: "{done} of {total} files checked",
|
|
69
67
|
scan_folders: "folders checked",
|
|
70
68
|
scan_files: "files checked",
|
|
@@ -903,50 +901,48 @@ const renderOverview = () => {
|
|
|
903
901
|
const verifying = scanPhase === "verifying"
|
|
904
902
|
const hashTotal = scan.hash_total || 0
|
|
905
903
|
const hashDone = Math.min(Math.max(0, hashTotal - (scan.queued || 0)), hashTotal)
|
|
906
|
-
const
|
|
904
|
+
const currentFileSize = Math.max(0, Number(scan.current_file_size) || 0)
|
|
905
|
+
const currentFileBytes = Math.min(currentFileSize, Math.max(0, Number(scan.current_file_bytes) || 0))
|
|
906
|
+
const currentFileRatio = currentFileSize ? currentFileBytes / currentFileSize : 0
|
|
907
|
+
const hashRatio = hashTotal ? Math.min(1, (hashDone + currentFileRatio) / hashTotal) : 1
|
|
907
908
|
const scanSource = scan.scope_id ? sourceById(scan.scope_id) : null
|
|
908
909
|
const scanProgressLabel = scanSource
|
|
909
910
|
? COPY.scan_location.replace("{location}", scanSource.label)
|
|
910
911
|
: COPY.scan_progress
|
|
911
912
|
const phase = queued ? COPY.scan_queued : counting ? COPY.scan_counting : walking ? scanProgressLabel : verifying ? COPY.scan_finishing : COPY.scan_analyzing
|
|
912
|
-
const rawCountWeight = Number.isFinite(scan.estimated_count_weight) ? scan.estimated_count_weight : 0.4
|
|
913
|
-
const countWeight = Math.max(0, Math.min(0.98, rawCountWeight))
|
|
914
|
-
const rawWalkWeight = Number.isFinite(scan.estimated_walk_weight) ? scan.estimated_walk_weight : 0.5
|
|
915
|
-
const walkWeight = Math.max(0, Math.min(0.98 - countWeight, rawWalkWeight))
|
|
916
|
-
const analysisWeight = Math.max(0, 1 - countWeight - walkWeight)
|
|
917
|
-
const countEstimate = Number.isFinite(scan.count_estimate_files) && scan.count_estimate_files > 0
|
|
918
|
-
? scan.count_estimate_files
|
|
919
|
-
: null
|
|
920
|
-
const countRatio = countEstimate === null ? null : Math.min(1, (scan.counted_files || 0) / countEstimate)
|
|
921
913
|
const totalFiles = Number.isFinite(scan.total_files) ? scan.total_files : null
|
|
922
914
|
const details = counting
|
|
923
915
|
? [`${scan.counted_dirs || 0} ${COPY.scan_folders_found}`, `${scan.counted_files || 0} ${COPY.scan_files_found}`]
|
|
924
916
|
: [`${scan.dirs || 0} ${COPY.scan_folders}`, totalFiles === null
|
|
925
917
|
? `${scan.files || 0} ${COPY.scan_files}`
|
|
926
918
|
: COPY.scan_files_checked.replace("{done}", scan.files || 0).replace("{total}", totalFiles), fmt(scan.bytes_total || 0)]
|
|
927
|
-
if (scan.current_file)
|
|
919
|
+
if (scan.current_file) {
|
|
920
|
+
const fileProgress = currentFileSize
|
|
921
|
+
? ` (${COPY.scan_file_bytes.replace("{done}", fmt(currentFileBytes)).replace("{total}", fmt(currentFileSize))})`
|
|
922
|
+
: ""
|
|
923
|
+
details.push(`${COPY.analyzing} ${scan.current_file}${fileProgress}`)
|
|
924
|
+
}
|
|
928
925
|
if (walking && scan.queued > 1) details.push(`${scan.queued} ${COPY.waiting}`)
|
|
929
926
|
if (!walking && hashTotal) {
|
|
930
927
|
details.push(COPY.scan_checked.replace("{done}", hashDone).replace("{total}", hashTotal))
|
|
931
928
|
}
|
|
932
929
|
let percent = ""
|
|
933
930
|
let progress
|
|
934
|
-
if (queued ||
|
|
935
|
-
const
|
|
931
|
+
if (queued || counting || verifying || (walking && totalFiles === null)) {
|
|
932
|
+
const progressHelp = verifying
|
|
933
|
+
? COPY.scan_finishing_help
|
|
934
|
+
: counting ? COPY.scan_counting_help : phase
|
|
935
|
+
const ariaText = `${details.join(" · ")}. ${progressHelp}.`
|
|
936
936
|
progress = { determinate: false, ariaText }
|
|
937
937
|
} else {
|
|
938
|
-
const progressRatio =
|
|
939
|
-
?
|
|
940
|
-
:
|
|
941
|
-
? 0.99
|
|
942
|
-
: walking
|
|
943
|
-
? countWeight + ((totalFiles ? Math.min(1, (scan.files || 0) / totalFiles) : 1) * walkWeight)
|
|
944
|
-
: Math.min(0.98, countWeight + walkWeight + (analysisWeight * hashRatio))
|
|
938
|
+
const progressRatio = walking
|
|
939
|
+
? (totalFiles ? Math.min(1, (scan.files || 0) / totalFiles) : 1)
|
|
940
|
+
: hashRatio
|
|
945
941
|
const boundedProgress = Math.max(0, Math.min(1, progressRatio))
|
|
946
942
|
const progressValue = Math.round(boundedProgress * 1000) / 10
|
|
947
|
-
const progressHelp =
|
|
948
|
-
const progressText = COPY.
|
|
949
|
-
percent =
|
|
943
|
+
const progressHelp = walking ? COPY.scan_file_progress_help : COPY.scan_hash_progress_help
|
|
944
|
+
const progressText = COPY.exact_percent.replace("{percent}", progressValue)
|
|
945
|
+
percent = `${progressValue}%`
|
|
950
946
|
progress = { determinate: true, value: progressValue, ratio: boundedProgress, help: progressHelp, text: progressText }
|
|
951
947
|
}
|
|
952
948
|
if (!scanState.querySelector(".vault-progress-track")) {
|
package/server/views/vault.ejs
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
<%- include('partials/main_sidebar', { selected: 'vault' }) %>
|
|
24
24
|
</main>
|
|
25
25
|
<script src="/Socket.js"></script>
|
|
26
|
+
<script src="/common.js"></script>
|
|
27
|
+
<script src="/nav.js" data-header-collapse-only></script>
|
|
26
28
|
<script src="/storage-size.js"></script>
|
|
27
29
|
<script src="/vault.js"></script>
|
|
28
30
|
</body>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const assert = require('node:assert/strict')
|
|
2
|
+
const test = require('node:test')
|
|
3
|
+
|
|
4
|
+
const generator = require('../script/update-amd-gfx-targets')
|
|
5
|
+
|
|
6
|
+
test('AMD generator joins LLVM aliases, Mesa families, and PCI IDs', () => {
|
|
7
|
+
const llvm = `
|
|
8
|
+
def : ProcessorModel<"gfx803", Model, FeatureISAVersion8_0_3.Features>;
|
|
9
|
+
def : ProcessorModel<"polaris10", Model, FeatureISAVersion8_0_3.Features>;
|
|
10
|
+
`
|
|
11
|
+
const families = `
|
|
12
|
+
const char *ac_get_llvm_processor_name(enum radeon_family family) {
|
|
13
|
+
switch (family) {
|
|
14
|
+
case CHIP_POLARIS10:
|
|
15
|
+
return "polaris10";
|
|
16
|
+
case CHIP_NAVI23:
|
|
17
|
+
return "gfx1032";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const char *ac_get_ip_type_string(void) {}
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
const processors = generator.parseLlvmProcessorTargets(llvm)
|
|
24
|
+
const familyTargets = generator.parseMesaFamilyTargets(families, processors)
|
|
25
|
+
const entries = generator.parseMesaPciTargets(
|
|
26
|
+
'CHIPSET(0x67DF, POLARIS10)\n',
|
|
27
|
+
familyTargets
|
|
28
|
+
)
|
|
29
|
+
generator.parseLinuxPciTargets(
|
|
30
|
+
'{0x1002, 0x73FF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},',
|
|
31
|
+
familyTargets,
|
|
32
|
+
{ DIMGREY_CAVEFISH: 'NAVI23' },
|
|
33
|
+
entries
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
assert.equal(familyTargets.POLARIS10, 'gfx803')
|
|
37
|
+
assert.equal(entries['1002:67df'].target, 'gfx803')
|
|
38
|
+
assert.equal(entries['1002:73ff'].target, 'gfx1032')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('AMD generator derives former Mesa family aliases from pinned comments', () => {
|
|
42
|
+
assert.deepEqual(generator.parseMesaFamilyAliases(`
|
|
43
|
+
CHIP_NAVI21, /* formerly "Sienna Cichlid" */
|
|
44
|
+
CHIP_NAVI23, /* formerly "Dimgrey Cavefish" */
|
|
45
|
+
`), {
|
|
46
|
+
SIENNA_CICHLID: 'NAVI21',
|
|
47
|
+
DIMGREY_CAVEFISH: 'NAVI23'
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('AMD generator rejects conflicting PCI family targets', () => {
|
|
52
|
+
assert.throws(() => generator.parseLinuxPciTargets(
|
|
53
|
+
[
|
|
54
|
+
'{0x1002, 0x73FF, 0, 0, 0, 0, CHIP_NAVI21},',
|
|
55
|
+
'{0x1002, 0x73FF, 0, 0, 0, 0, CHIP_NAVI23},'
|
|
56
|
+
].join('\n'),
|
|
57
|
+
{ NAVI21: 'gfx1030', NAVI23: 'gfx1032' },
|
|
58
|
+
{}
|
|
59
|
+
), /Conflicting targets/)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('AMD generator keeps exact libdrm revisions without promoting model names', () => {
|
|
63
|
+
const pciTargets = {}
|
|
64
|
+
const revisions = generator.parseLibdrmRevisionTargets(
|
|
65
|
+
'744c, c8, AMD Radeon RX 7900 XTX\n',
|
|
66
|
+
{ 'radeon rx 7900 xtx': 'gfx1100' },
|
|
67
|
+
pciTargets
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
assert.deepEqual(revisions['1002:744c:c8'], {
|
|
71
|
+
target: 'gfx1100',
|
|
72
|
+
model: 'AMD Radeon RX 7900 XTX'
|
|
73
|
+
})
|
|
74
|
+
assert.equal(pciTargets['1002:744c'], undefined)
|
|
75
|
+
})
|
|
@@ -6,17 +6,19 @@ const test = require('node:test')
|
|
|
6
6
|
const system = require('systeminformation')
|
|
7
7
|
|
|
8
8
|
const amd = require('../kernel/gpu/amd')
|
|
9
|
+
const amdPci = require('../kernel/gpu/amd_pci')
|
|
9
10
|
const gfxTargets = require('../kernel/gpu/amd_gfx_targets.json')
|
|
11
|
+
const pciTargets = require('../kernel/gpu/amd_pci_targets.json')
|
|
10
12
|
const packageJson = require('../package.json')
|
|
11
13
|
const Sysinfo = require('../kernel/sysinfo')
|
|
12
14
|
|
|
13
15
|
const root = path.join(__dirname, '..')
|
|
14
16
|
|
|
15
17
|
test('AMD gfx generated data is checked in and self describing', () => {
|
|
16
|
-
assert.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
18
|
+
assert.match(gfxTargets.source, new RegExp(gfxTargets.source_revision))
|
|
19
|
+
assert.doesNotMatch(gfxTargets.source, /\/develop\//)
|
|
20
|
+
assert.match(gfxTargets.source_revision, /^[0-9a-f]{40}$/)
|
|
21
|
+
assert.match(gfxTargets.source_sha256, /^[0-9a-f]{64}$/)
|
|
20
22
|
assert.equal(gfxTargets.generated_by, 'script/update-amd-gfx-targets.js')
|
|
21
23
|
|
|
22
24
|
assert.equal(gfxTargets.entries['radeon rx 6800 xt'], 'gfx1030')
|
|
@@ -24,8 +26,32 @@ test('AMD gfx generated data is checked in and self describing', () => {
|
|
|
24
26
|
assert.equal(gfxTargets.entries.mi210, 'gfx90a')
|
|
25
27
|
})
|
|
26
28
|
|
|
29
|
+
test('AMD PCI generated data is pinned, auditable, and covers mobile and RDNA1 GPUs', () => {
|
|
30
|
+
assert.equal(pciTargets.generated_by, 'script/update-amd-gfx-targets.js')
|
|
31
|
+
assert.ok(pciTargets.sources.length >= 6)
|
|
32
|
+
for (const source of pciTargets.sources) {
|
|
33
|
+
assert.match(source.revision, /^[0-9a-f]{40}$/)
|
|
34
|
+
assert.match(source.sha256, /^[0-9a-f]{64}$/)
|
|
35
|
+
assert.match(source.url, new RegExp(source.revision))
|
|
36
|
+
assert.doesNotMatch(source.url, /\/(?:main|master|develop)\//)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
assert.equal(pciTargets.entries['1002:731f'].target, 'gfx1010')
|
|
40
|
+
assert.equal(pciTargets.entries['1002:7340'].target, 'gfx1012')
|
|
41
|
+
assert.equal(pciTargets.entries['1002:73ff'].target, 'gfx1032')
|
|
42
|
+
assert.equal(pciTargets.entries['1002:73ff'].family, 'NAVI23')
|
|
43
|
+
assert.equal(pciTargets.revision_entries['1002:73ff:c3'].model, 'AMD Radeon RX 6600M')
|
|
44
|
+
assert.equal(pciTargets.revision_entries['1002:73ff:c3'].target, 'gfx1032')
|
|
45
|
+
assert.equal(pciTargets.revision_entries['1002:744c:c8'].target, 'gfx1100')
|
|
46
|
+
assert.equal(
|
|
47
|
+
Object.values(pciTargets.entries).some((entry) => entry.family === 'LIBDRM_MODEL_CONSENSUS'),
|
|
48
|
+
false
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
|
|
27
52
|
test('AMD gfx target refresh is an explicit maintainer command', () => {
|
|
28
53
|
assert.equal(packageJson.scripts['update:amd-gfx-targets'], 'node script/update-amd-gfx-targets.js')
|
|
54
|
+
assert.equal(packageJson.scripts['check:amd-gfx-targets'], 'node script/update-amd-gfx-targets.js --check')
|
|
29
55
|
assert.equal(Object.prototype.hasOwnProperty.call(packageJson.scripts, 'update:amd-rocm-targets'), false)
|
|
30
56
|
|
|
31
57
|
for (const script of ['preinstall', 'install', 'postinstall', 'prestart', 'start', 'poststart']) {
|
|
@@ -51,6 +77,13 @@ test('AMD gfx resolver maps common product names to exact gfx targets', () => {
|
|
|
51
77
|
}
|
|
52
78
|
})
|
|
53
79
|
|
|
80
|
+
test('AMD model resolver does not hand-maintain product gaps covered by PCI identity', () => {
|
|
81
|
+
assert.equal(gfxTargets.entries['radeon rx 6600m'], undefined)
|
|
82
|
+
assert.equal(amd.resolve_rocm_gfx_target('AMD Radeon RX 6600'), 'gfx1032')
|
|
83
|
+
assert.equal(amd.resolve_rocm_gfx_target('AMD Radeon RX 6600M'), null)
|
|
84
|
+
assert.equal(amd.resolve_rocm_gfx_target('AMD Radeon(TM) RX 6600M'), null)
|
|
85
|
+
})
|
|
86
|
+
|
|
54
87
|
test('AMD gfx resolver rejects unknown products and preserves raw gfx targets', () => {
|
|
55
88
|
const unknownModels = [
|
|
56
89
|
'AMD Radeon RX 480',
|
|
@@ -88,6 +121,9 @@ test('AMD gpu_target resolution uses CPU brand only for generic Radeon Graphics
|
|
|
88
121
|
})
|
|
89
122
|
|
|
90
123
|
test('Sysinfo exposes AMD gpu_target for resolved discrete GPUs', async (t) => {
|
|
124
|
+
t.mock.method(amdPci, 'resolve_gpu_target', async () => {
|
|
125
|
+
throw new Error('PCI fallback should not run for a resolved model')
|
|
126
|
+
})
|
|
91
127
|
t.mock.method(system, 'graphics', async () => ({
|
|
92
128
|
controllers: [
|
|
93
129
|
{
|
|
@@ -109,7 +145,63 @@ test('Sysinfo exposes AMD gpu_target for resolved discrete GPUs', async (t) => {
|
|
|
109
145
|
assert.equal(sys.info.gpu_target, 'gfx1030')
|
|
110
146
|
})
|
|
111
147
|
|
|
148
|
+
test('Sysinfo exposes AMD gpu_target for a PCI-resolved mobile GPU', async (t) => {
|
|
149
|
+
t.mock.method(amdPci, 'resolve_gpu_target', async (controller) => {
|
|
150
|
+
assert.equal(controller.model, 'AMD Radeon RX 6600M')
|
|
151
|
+
return 'gfx1032'
|
|
152
|
+
})
|
|
153
|
+
t.mock.method(system, 'graphics', async () => ({
|
|
154
|
+
controllers: [
|
|
155
|
+
{
|
|
156
|
+
vendor: 'Advanced Micro Devices, Inc.',
|
|
157
|
+
model: 'AMD Radeon(TM) Graphics',
|
|
158
|
+
vram: 512
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
vendor: 'Advanced Micro Devices, Inc.',
|
|
162
|
+
model: 'AMD Radeon RX 6600M',
|
|
163
|
+
vram: 8192
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
displays: []
|
|
167
|
+
}))
|
|
168
|
+
|
|
169
|
+
const sys = new Sysinfo()
|
|
170
|
+
sys.info = {}
|
|
171
|
+
|
|
172
|
+
await sys.gpus()
|
|
173
|
+
|
|
174
|
+
assert.equal(sys.info.gpu, 'amd')
|
|
175
|
+
assert.equal(sys.info.gpu_model, 'amd radeon rx 6600m')
|
|
176
|
+
assert.equal(sys.info.gpu_target, 'gfx1032')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('Sysinfo uses exact AMD PCI identity after model lookup misses', async (t) => {
|
|
180
|
+
t.mock.method(amdPci, 'resolve_gpu_target', async (controller) => {
|
|
181
|
+
assert.equal(controller.model, 'AMD Radeon RX 5700 XT')
|
|
182
|
+
return 'gfx1010'
|
|
183
|
+
})
|
|
184
|
+
t.mock.method(system, 'graphics', async () => ({
|
|
185
|
+
controllers: [
|
|
186
|
+
{
|
|
187
|
+
vendor: 'AMD',
|
|
188
|
+
model: 'AMD Radeon RX 5700 XT',
|
|
189
|
+
vram: 8192
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
displays: []
|
|
193
|
+
}))
|
|
194
|
+
|
|
195
|
+
const sys = new Sysinfo()
|
|
196
|
+
sys.info = {}
|
|
197
|
+
|
|
198
|
+
await sys.gpus()
|
|
199
|
+
|
|
200
|
+
assert.equal(sys.info.gpu_target, 'gfx1010')
|
|
201
|
+
})
|
|
202
|
+
|
|
112
203
|
test('Sysinfo leaves unresolved AMD gpu_target null', async (t) => {
|
|
204
|
+
t.mock.method(amdPci, 'resolve_gpu_target', async () => null)
|
|
113
205
|
t.mock.method(system, 'graphics', async () => ({
|
|
114
206
|
controllers: [
|
|
115
207
|
{
|
|
@@ -133,6 +225,9 @@ test('Sysinfo leaves unresolved AMD gpu_target null', async (t) => {
|
|
|
133
225
|
|
|
134
226
|
test('Sysinfo exposes AMD gpu_target through generic APU CPU fallback', async (t) => {
|
|
135
227
|
let cpuBrandCalls = 0
|
|
228
|
+
t.mock.method(amdPci, 'resolve_gpu_target', async () => {
|
|
229
|
+
throw new Error('PCI fallback should not run for a resolved APU')
|
|
230
|
+
})
|
|
136
231
|
t.mock.method(system, 'graphics', async () => ({
|
|
137
232
|
controllers: [
|
|
138
233
|
{
|
|
@@ -159,11 +254,14 @@ test('Sysinfo exposes AMD gpu_target through generic APU CPU fallback', async (t
|
|
|
159
254
|
assert.equal(cpuBrandCalls, 1)
|
|
160
255
|
})
|
|
161
256
|
|
|
162
|
-
test('AMD
|
|
163
|
-
const
|
|
257
|
+
test('AMD model fallback stays offline and data-only', () => {
|
|
258
|
+
const modelSource = fs.readFileSync(path.join(root, 'kernel', 'gpu', 'amd.js'), 'utf8')
|
|
259
|
+
const pciSource = fs.readFileSync(path.join(root, 'kernel', 'gpu', 'amd_pci.js'), 'utf8')
|
|
164
260
|
|
|
165
|
-
assert.doesNotMatch(
|
|
166
|
-
assert.doesNotMatch(
|
|
167
|
-
assert.doesNotMatch(
|
|
168
|
-
assert.doesNotMatch(
|
|
261
|
+
assert.doesNotMatch(modelSource, /require\(["'](?:node:)?https?["']\)/)
|
|
262
|
+
assert.doesNotMatch(modelSource, /require\(["'](?:node:)?child_process["']\)/)
|
|
263
|
+
assert.doesNotMatch(modelSource, /\b(fetch|axios|rocminfo|hipInfo|ze_info)\b/)
|
|
264
|
+
assert.doesNotMatch(modelSource, /\b(kfd|topology)\b/i)
|
|
265
|
+
assert.doesNotMatch(pciSource, /require\(["'](?:node:)?https?["']\)/)
|
|
266
|
+
assert.doesNotMatch(pciSource, /\b(fetch|axios|OpenCL|rocminfo|hipInfo)\b/i)
|
|
169
267
|
})
|