gem/scripts/analyze-metal-counter-info.sh
2026-08-30 18:24:55 -06:00

69 lines
2.9 KiB
Bash
Executable file

#!/bin/sh
set -eu
[ "$#" -eq 1 ] || [ "$#" -eq 2 ] || {
echo "usage: $0 COUNTER_INFO_JSON [OUTPUT_JSON]" >&2
exit 2
}
input=$1
output=${2:-}
analyze() {
jq '
([.counter_sets[].counters[]] | unique) as $names |
def named($pattern): any($names[]; test($pattern; "i"));
if .schema_version != 1 or .workload != "metal-counter-info" or
.device.has_unified_memory != true or .device.gpu_families.apple9 != true or
.device.max_threadgroup_memory_bytes < 32768 or
(.sampling_points.stage_boundary | type) != "boolean" or
(.sampling_points.dispatch_boundary | type) != "boolean" or
(.counter_sets | type) != "array" or (.counter_sets | length) == 0 or
any(.counter_sets[]; (.name | type) != "string" or
(.counters | type) != "array" or any(.counters[]; type != "string"))
then error("invalid target Metal counter inventory") else
(named("timestamp")) as $timestamp |
(named("occup|active.*thread|thread.*active")) as $occupancy |
(named("bandwidth|bytes|memory.*read|memory.*write|read.*memory|write.*memory"))
as $bandwidth |
(named("limiter|stall")) as $limiter |
{
schema_version: 1,
scope: "target-metal-counter-capability-analysis",
device: .device,
sampling_points: .sampling_points,
counter_set_count: (.counter_sets | length),
available_counter_names: $names,
capabilities: {
timestamp: $timestamp,
occupancy: $occupancy,
bandwidth: $bandwidth,
limiter_or_stall: $limiter
},
instrumentation: {
stage_timestamps_available:
(.sampling_points.stage_boundary and $timestamp),
dispatch_performance_counters_available:
(.sampling_points.dispatch_boundary and
($occupancy or $bandwidth or $limiter)),
selected: (
if .sampling_points.dispatch_boundary and
($occupancy or $bandwidth or $limiter)
then "public-dispatch-counter-sampling"
elif .sampling_points.stage_boundary and $timestamp
then "stage-timestamps-plus-xcode-gpu-trace"
else "xcode-gpu-trace-only" end),
reason: (
if .sampling_points.dispatch_boundary and
($occupancy or $bandwidth or $limiter)
then "target exposes public dispatch-boundary performance counters"
elif .sampling_points.stage_boundary and $timestamp
then "public API lacks required performance counters; retain exact stage timestamps and use Xcode for occupancy/bandwidth/limiter evidence"
else "public counter sampling lacks both required performance counters and stage timestamps"
end)
}
}
end
' "$input"
}
if [ -n "$output" ]; then analyze > "$output"; else analyze; fi