Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .pmat-gates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ exclude = [

[tdg]
# CB-200 ratchet: functions below min_grade (pmat comply); the count may only fall.
# 602 measured 2026-09-14 under pmat 3.40.0 (was 609 under 3.39.0, 2026-09-03).
# The tree did not change between those two readings — the instrument did, so this
# is a re-measurement banked at the new floor, not seven functions fixed.
# 602 re-measured 2026-09-15 under pmat 3.40.1 (602 under 3.40.0, 2026-09-14; 609 under
# 3.39.0, 2026-09-03). 3.40.0 -> 3.40.1 read the same tree the same: the instrument moved,
# the count did not. Between those readings #3004 added one B- definition
# (registry/wgpu_probe.rs entry, 603) and merged, because no required job runs
# `pmat comply`; it was split into four graded tables in the pin-bump PR, back to 602.
baseline = 602
# CB-200: 21 functions below A are in non-release crates (test-lib, test-cli, train/cuda)
# These are complex GPU/inference functions where high cyclomatic complexity is inherent
Expand Down
128 changes: 109 additions & 19 deletions crates/aprender-compute/src/registry/wgpu_probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,67 @@ impl BackendFactory for WgpuFactory {
}
}

#[allow(clippy::cast_possible_truncation)]
fn entry(i: usize, info: &wgpu::AdapterInfo, limits: &wgpu::Limits) -> BackendEntry {
let vendor = match info.vendor {
/// PCI vendor id -> vendor name. `"unknown"` for anything not in the table.
fn vendor_name(vendor_id: u32) -> &'static str {
match vendor_id {
0x10de => "NVIDIA",
0x1002 => "AMD",
0x8086 => "Intel",
0x106b => "Apple",
_ => "unknown",
};
let transport = match info.backend {
}
}

/// wgpu backend -> the transport string `apr devices` prints (lane 2).
fn transport_name(backend: wgpu::Backend) -> &'static str {
match backend {
wgpu::Backend::Vulkan => "vulkan",
wgpu::Backend::Metal => "metal",
wgpu::Backend::Dx12 => "dx12",
wgpu::Backend::Gl => "gl",
wgpu::Backend::BrowserWebGpu => "webgpu",
wgpu::Backend::Noop => "noop",
};
let (device_type, status) = match info.device_type {
}
}

/// Device type -> (`device_type` string, status). A software rasteriser is
/// `Unavailable(NoBackend)`: listed, never used as a GPU.
fn classify(device_type: wgpu::DeviceType, name: &str) -> (&'static str, Status) {
match device_type {
wgpu::DeviceType::DiscreteGpu => ("discrete-gpu", Status::Ready),
wgpu::DeviceType::IntegratedGpu => ("integrated-gpu", Status::Ready),
wgpu::DeviceType::VirtualGpu => ("virtual-gpu", Status::Ready),
wgpu::DeviceType::Cpu => (
"software",
Status::Unavailable(Reason::NoBackend {
vendor: format!("software rasteriser ({}) is not a GPU", info.name),
vendor: format!("software rasteriser ({name}) is not a GPU"),
}),
),
wgpu::DeviceType::Other => ("other", Status::Ready),
};
let unified = matches!(info.backend, wgpu::Backend::Metal)
|| matches!(info.device_type, wgpu::DeviceType::IntegratedGpu);
}
}

/// Unified memory: Metal, or any integrated part. wgpu exposes no VRAM figure;
/// `max_buffer_size` is an allocation cap, so it is the working-set limit here
/// and `mem_total` stays unknown.
fn mem_kind(
backend: wgpu::Backend,
device_type: wgpu::DeviceType,
limits: &wgpu::Limits,
) -> MemKind {
let unified = matches!(backend, wgpu::Backend::Metal)
|| matches!(device_type, wgpu::DeviceType::IntegratedGpu);
if unified {
MemKind::Unified { working_set_limit: Some(limits.max_buffer_size) }
} else {
MemKind::Discrete
}
}

#[allow(clippy::cast_possible_truncation)]
fn entry(i: usize, info: &wgpu::AdapterInfo, limits: &wgpu::Limits) -> BackendEntry {
let vendor = vendor_name(info.vendor);
let (device_type, status) = classify(info.device_type, &info.name);
BackendEntry {
kind: BackendKind::Wgpu,
api: Api::Wgpu,
Expand All @@ -72,19 +102,79 @@ fn entry(i: usize, info: &wgpu::AdapterInfo, limits: &wgpu::Limits) -> BackendEn
vendor: vendor.to_string(),
vendor_id: if vendor == "unknown" { None } else { Some(info.vendor) },
device_type: device_type.to_string(),
// wgpu exposes no VRAM figure; `max_buffer_size` is an allocation cap, not
// memory, so it is reported as a capability string and mem_total stays unknown.
mem_total: None,
mem_free: None,
mem_kind: if unified {
MemKind::Unified { working_set_limit: Some(limits.max_buffer_size) }
} else {
MemKind::Discrete
},
mem_kind: mem_kind(info.backend, info.device_type, limits),
compute_class: None,
caps: vec![format!("max_buffer_size={}", limits.max_buffer_size)],
source: Source::CompiledIn,
status,
transport: Some(transport.to_string()),
transport: Some(transport_name(info.backend).to_string()),
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn vendor_table_names_the_four_and_unknown_for_the_rest() {
assert_eq!(vendor_name(0x10de), "NVIDIA");
assert_eq!(vendor_name(0x1002), "AMD");
assert_eq!(vendor_name(0x8086), "Intel");
assert_eq!(vendor_name(0x106b), "Apple");
assert_eq!(vendor_name(0x0000), "unknown");
assert_eq!(vendor_name(0xffff), "unknown");
}

#[test]
fn transport_table_is_total_over_wgpu_backends() {
assert_eq!(transport_name(wgpu::Backend::Vulkan), "vulkan");
assert_eq!(transport_name(wgpu::Backend::Metal), "metal");
assert_eq!(transport_name(wgpu::Backend::Dx12), "dx12");
assert_eq!(transport_name(wgpu::Backend::Gl), "gl");
assert_eq!(transport_name(wgpu::Backend::BrowserWebGpu), "webgpu");
assert_eq!(transport_name(wgpu::Backend::Noop), "noop");
}

#[test]
fn software_rasteriser_is_listed_but_never_ready() {
let (ty, status) = classify(wgpu::DeviceType::Cpu, "llvmpipe");
assert_eq!(ty, "software");
match status {
Status::Unavailable(Reason::NoBackend { vendor }) => {
assert!(vendor.contains("llvmpipe"), "names the adapter: {vendor}");
}
other => panic!("software rasteriser must be Unavailable(NoBackend), got {other:?}"),
}
for (dt, want) in [
(wgpu::DeviceType::DiscreteGpu, "discrete-gpu"),
(wgpu::DeviceType::IntegratedGpu, "integrated-gpu"),
(wgpu::DeviceType::VirtualGpu, "virtual-gpu"),
(wgpu::DeviceType::Other, "other"),
] {
let (ty, status) = classify(dt, "x");
assert_eq!(ty, want);
assert!(matches!(status, Status::Ready), "{want} is Ready");
}
}

#[test]
fn unified_memory_is_metal_or_integrated_and_carries_the_buffer_cap() {
let mut limits = wgpu::Limits::default();
limits.max_buffer_size = 4096;
for (b, dt) in [
(wgpu::Backend::Metal, wgpu::DeviceType::DiscreteGpu),
(wgpu::Backend::Vulkan, wgpu::DeviceType::IntegratedGpu),
] {
match mem_kind(b, dt, &limits) {
MemKind::Unified { working_set_limit } => assert_eq!(working_set_limit, Some(4096)),
other => panic!("{b:?}/{dt:?} must be Unified, got {other:?}"),
}
}
assert!(matches!(
mem_kind(wgpu::Backend::Vulkan, wgpu::DeviceType::DiscreteGpu, &limits),
MemKind::Discrete
));
}
}
17 changes: 17 additions & 0 deletions docs/roadmaps/roadmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17801,3 +17801,20 @@ roadmap:
- kind:code
notes: 'unanchored_but_bindable moves from [U] to 297; contracts_anchored may not
rise while pv census is absent, because pv validate accepts entity: by ignoring it'
- id: PMAT-3300
github_issue: 3300
item_type: task
title: 'tools.toml pmat 3.40.1: the fleet converged 2026-09-14 and every intel-hosted PR is red'
status: planned
priority: medium
assigned_to: null
created: 2026-09-15T07:58:08Z
updated: 2026-09-15T07:58:08Z
spec: null
acceptance_criteria: []
phases: []
subtasks: []
estimated_effort: null
labels:
- kind:code
notes: null
2 changes: 1 addition & 1 deletion scripts/cb200_baseline.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# tool_version=pmat 3.40.0
# tool_version=pmat 3.40.1
602
2 changes: 1 addition & 1 deletion scripts/complexity_baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# (cyclomatic > 30 or cognitive > 25), as "<path>::<function> <cyclomatic> <cognitive>".
# SHRINK-ONLY. Regenerate with: bash scripts/check_complexity_ratchet.sh --update
# Owner: scripts/check_complexity_ratchet.sh (PMAT-746).
# tool_version=pmat 3.40.0
# tool_version=pmat 3.40.1
crates/apr-cli/examples/gpu_chat_inference.rs::run_chat_completion 11 33
crates/apr-cli/src/commands/attn_parity_lint.rs::run 13 26
crates/apr-cli/src/commands/attn_viz_classifier.rs::classify_causal_mask 8 29
Expand Down
6 changes: 3 additions & 3 deletions tools.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# CI. The fleet installer is infra's forjar pin, applied to every clean-room
# runner (paiml/infra, machines/intel/forjar.yaml):
#
# stack-tool-pmat (line 784) version: "3.39.0" # infra ef0ec4c, 2026-09-06
# stack-tool-bashrs (line 811) version: "7.0.4"
# stack-tool-pmat (line 779) version: "3.40.1" # infra ba369f9, 2026-09-14 (#591)
# stack-tool-bashrs version: "7.4.1"
#
# ALWAYS LATEST (operator rule, 2026-09-14): "we always go latest crates.io on
# our stack." This file names that version and check_tool_versions.sh asserts it.
Expand Down Expand Up @@ -53,7 +53,7 @@
# Bump this file in the SAME commit as the infra forjar.yaml version bump.

[pmat]
version = "3.40.0"
version = "3.40.1"

[bashrs]
version = "7.4.1"
Loading