Nameplate Analytics

GPU cost attribution

Northwind Systems, Inc.

Report date
2026-10-02
Data period
2026-08-01 to 2026-08-30, a 30-day window; monthly figures scale it to a 30.4-day month
Accounts
2 in scope
Findings
9

1 What we are willing to claim

Every finding in this report carries a confidence rating. Only findings the data supports are added to the recoverable total. The rest are printed in full and left out of the number, because a figure that does not survive a skeptical engineer is worth less than no figure at all.

$100k
recoverable per month, proven and likely findings only
$1.20M
recoverable per year at the same run rate
$213k
observed but not claimed, excluded from the figures to the left

Exact totals before rounding: PROVEN $1,976.00 plus LIKELY $98,125.05 is $100,101.05 recoverable per month, the sum of the recoverable figures on the findings below. UNPROVEN is $213,121.10 per month observed and not claimed. Its findings describe some of the same machines, so each machine is counted once, and none of it is in the recoverable total.

$98k$213kProven recoverable $1,976Proven recoverable$1,976 per monthLikely recoverable$98k per monthone stated assumption eachNot claimed$213k per monthexcluded from the total
The hatched segment is money we are not claiming. It is shown at the same scale as the rest so the proportion is visible rather than described.

The proven band is thin, and that is the finding rather than an apology for it. Billing data on its own settles only what it records directly, and that is a short list. Every dollar above the proven line rests on an assumption printed beside the finding it belongs to, in a sentence you can read and refuse, and the figure goes with it if you do. Widening this band takes more measurement, not more confidence.

Total amortized spend across the period was $315k, of which $306k was GPU compute. (Illustrative figures from a synthetic specimen.) Amortized cost is used throughout, not unblended cost: AWS writes an unblended cost of zero on reserved-instance-covered line items, so a ranking by unblended cost makes the most expensive machine in an account disappear.

Dollar figures are at list price, before any negotiated discount the client holds: each usage line is priced from the export's gross cost columns. Pricing basis GROSS_AMORTIZED_LIST.

2 How to read a finding

PROVEN

The evidence covers the whole period, so there is no assumption to accept or reject. Two routes reach it: a commitment reconciled against a closed billing period, and cluster allocation sampled across the period rather than read once.

LIKELY

The billing data proves the cost. The waste follows from one stated assumption, printed with the finding, which you can accept or reject line by line.

UNPROVEN

There is a cost and a suspicion. The data that would settle it does not exist yet. These dollars are listed and then excluded from the recoverable total.

3 Findings

PROVEN

$1,976 per month recoverable across 1 finding, after machines named by more than one finding are counted once.

Commitment purchased and not consumed: $1,216/mo of Reserved Instance capacity and $760/mo of Savings Plan commitment

PROVENvalidation: synthetic fixture

$1,976
observed per month
$1,976
recoverable per month
2
resources
2/5
disruption to change

What to do.Sell unused Standard RIs on the Reserved Instance Marketplace where the term allows, or move workloads onto the committed instance families so the commitment is consumed. Savings Plan commitments cannot be sold; the recovery is to shift eligible usage onto them before the term ends.

resourceaccountcommitmentunused $ / month
arn:aws:ec2:us-east-1:ri/r-abc111111111111RIFee$1,216
arn:aws:savingsplans::sp/sp-xyz111111111111SavingsPlanRecurringFee$760

LIKELY

$98k per month recoverable across 5 findings, after machines named by more than one finding are counted once.

23 of 63 provisioned GPUs had no pod requesting them when the cluster was read, $60,432/mo

$60k
observed per month
$60k
recoverable per month
5
resources
2/5
disruption to change

Assumption.The cluster was read once, at 2026-09-01T00:00:00+00:00, and this figure applies that single reading to the whole billing period. One reading proves what was allocated at that instant and nothing about the hours either side of it. Sample allocation hourly for the period and whatever is observed becomes proven; until then this is an extrapolation and is rated as one.

What to do.Scale the affected node groups down to the number of GPUs actually requested. Where a node group exists for burst capacity, set its floor to zero and let the cluster autoscaler bring it up on a pending pod.

nodeinstance idinstance typeGPUsGPUs requestedGPUs unrequestednode $ / monthunrequested $ / month
ip-10-0-001-10.ec2.internali-000000000000001001p5.48xlarge808$40,157$40,157
ip-10-0-000-10.ec2.internali-000000000000001000p4d.24xlarge808$9,933$9,933
ip-10-0-004-10.ec2.internali-000000000000001004p4d.24xlarge844$16,020$8,010
ip-10-0-003-10.ec2.internali-000000000000001003g5.12xlarge422$2,980$1,490
ip-10-0-002-10.ec2.internali-000000000000001002g6e.xlarge101$842$842

14 production GPU instances run continuously at on-demand rates, $153,949/mo

$154k
observed per month
$24k
recoverable per month
14
resources
3/5
disruption to change

Counted once.Taken on its own this finding identifies $33k per month. The figure above is what survives de-duplication and is what the recoverable total uses. The difference, $8,626 per month, sits on machines already claimed by gpu zero allocation, which are counted first because PROVEN findings go before LIKELY ones and the order of work decides within a rating. A machine is counted once however many findings describe it.

Assumption.The recoverable figure applies the one-year no-upfront Compute Savings Plan rate AWS publishes for each family (g5 21.25%, g6e 24.40%, p3 18.62%, p4d 23.92%, p5 21.25%), which comes to 21.48% across this set, and assumes the capacity is still wanted twelve months from now. The rates were read from the AWS Savings Plans and EC2 price lists for us-east-1, both published 2026-09-10; re-read them for another region, because they differ by region. If the workload is being migrated or retired inside the term, this finding does not apply.

What to do.Size a Compute Savings Plan to the observed floor of GPU usage, not to the peak. Commit to the level that has been running every day of the period and leave the rest on demand.

resourceaccountinstance typeacceleratordays always on$ / month
i-000000000000001001111111111111p5.48xlargeNVIDIA H10030$40,157
i-000000000000001005111111111111p5.48xlargeNVIDIA H10030$40,157
i-000000000000001004111111111111p4d.24xlargeNVIDIA A10030$16,020
i-000000000000001024111111111111p4d.24xlargeNVIDIA A10030$16,020
i-00000000000000101b111111111111p3.8xlargeNVIDIA V10030$8,930
i-00000000000000101d111111111111p3.8xlargeNVIDIA V10030$8,930
i-000000000000001007111111111111g5.12xlargeNVIDIA A10G30$4,138
i-00000000000000101f111111111111g5.12xlargeNVIDIA A10G30$4,138
i-000000000000001023111111111111g5.12xlargeNVIDIA A10G30$4,138
i-000000000000001027111111111111g5.12xlargeNVIDIA A10G30$4,138
i-00000000000000101a111111111111p3.2xlargeNVIDIA V10030$2,233
i-00000000000000101c111111111111p3.2xlargeNVIDIA V10030$2,233
i-00000000000000101e111111111111g6e.xlargeNVIDIA L40S30$1,358
i-000000000000001022111111111111g6e.xlargeNVIDIA L40S30$1,358

9 untagged instances read as non-production and run continuously, $11,916/mo

$12k
observed per month
$8,369
recoverable per month
9
resources
2/5
disruption to change

Assumption.These resources carry no Environment tag. Each is classified from its account, its name, or its instance family, and the signals are listed per resource below. The finding holds if the client confirms the classification; strike any row that is wrong and the total falls by that row's cost. The recovery then carries the same working-week assumption as the tagged finding above. It treats a 50-hour working week as the time these machines are needed, which leaves 118 of the 168 hours in a week recoverable by scheduling, or 70.2% of the line. A different working pattern moves the figure in proportion, so confirm the hours and rescale. A machine genuinely needed around the clock recovers nothing here, whatever its tag says.

What to do.Confirm the classification, tag the resources so this stops being an inference, then schedule them off outside working hours.

resourceaccountinstance typegpudays always on$ / monthwhy it was classified this way
i-00000000000000100e111111111111g4dn.12xlargeyes30$2,854Name tag contains 'dev'
i-000000000000001011111111111111g4dn.12xlargeyes30$2,854Name tag contains 'dev'
i-000000000000001014222222222222g4dn.12xlargeyes30$2,854account name contains 'sandbox'
i-000000000000001010111111111111g5.xlargeyes30$734Name tag contains 'dev'; single-accelerator g5 instance, the shape of a development box
i-000000000000001013222222222222g5.xlargeyes30$734account name contains 'sandbox'; single-accelerator g5 instance, the shape of a development box
i-000000000000001016111111111111g5.xlargeyes30$734Name tag contains 'qa'; single-accelerator g5 instance, the shape of a development box
i-00000000000000100f111111111111g4dn.xlargeyes30$384Name tag contains 'dev'; single-accelerator g4dn instance, the shape of a development box
i-000000000000001012222222222222g4dn.xlargeyes30$384account name contains 'sandbox'; single-accelerator g4dn instance, the shape of a development box
i-000000000000001015111111111111g4dn.xlargeyes30$384Name tag contains 'qa'; single-accelerator g4dn instance, the shape of a development box

10 tagged non-production instances run continuously, $6,495/mo, $4,706/mo of it GPU

$6,495
observed per month
$4,562
recoverable per month
10
resources
2/5
disruption to change

Assumption.The cost is read straight from the bill and the Environment tag is the client's own, so neither is in question. The recovery is. It treats a 50-hour working week as the time these machines are needed, which leaves 118 of the 168 hours in a week recoverable by scheduling, or 70.2% of the line. A different working pattern moves the figure in proportion, so confirm the hours and rescale. A machine genuinely needed around the clock recovers nothing here, whatever its tag says.

What to do.Stop non-production instances outside working hours with an EventBridge schedule or an autoscaler floor of zero. GPU instances should be stopped rather than resized, because the accelerator is the entire cost.

resourceaccountinstance typegpudays always on$ / monthwhy it was classified this way
i-00000000000000100b111111111111g4dn.12xlargeyes30$2,854Environment tag = dev
i-00000000000000100a111111111111g5.xlargeyes30$734Environment tag = dev
i-00000000000000100d111111111111g5.xlargeyes30$734Environment tag = dev
i-000000000000009007111111111111c5.9xlargeno30$692Environment tag = dev
i-00000000000000100c111111111111g4dn.xlargeyes30$384Environment tag = dev
i-000000000000009001111111111111m5.4xlargeno30$347Environment tag = dev
i-000000000000009010111111111111m5.4xlargeno30$347Environment tag = dev
i-00000000000000900d111111111111r5.2xlargeno30$228Environment tag = dev
i-000000000000009004111111111111m6i.xlargeno30$87Environment tag = dev
i-000000000000009013111111111111m6i.xlargeno30$87Environment tag = dev

4 EBS volumes and snapshots billed for the full period with no associated compute, $320/mo

$320
observed per month
$320
recoverable per month
4
resources
1/5
disruption to change

Assumption.A CUR does not carry EBS attachment state, so this is inferred from a volume billing every day of the period while nothing in the account consumed compute hours against it. Confirm with `aws ec2 describe-volumes --filters Name=status,Values=available` before deleting anything. Snapshots that are the only copy of a dataset are not waste regardless of what the billing says.

What to do.Snapshot then delete volumes confirmed as available. For snapshots, apply a lifecycle policy rather than deleting by hand.

resourceaccountusage typeregiondays billed$ / month
arn:aws:ec2:us-east-1:111111111111:volume/vol-00000000000000000111111111111USE1-EBS:VolumeUsage.gp3us-east-130$80
arn:aws:ec2:us-east-1:111111111111:volume/vol-00000000000000001111111111111USE1-EBS:VolumeUsage.gp3us-east-130$80
arn:aws:ec2:us-east-1:111111111111:volume/vol-00000000000000002111111111111USE1-EBS:VolumeUsage.gp3us-east-130$80
arn:aws:ec2:us-east-1:111111111111:volume/vol-00000000000000003111111111111USE1-EBS:VolumeUsage.gp3us-east-130$80

UNPROVEN

$213k per month observed under these findings once each machine is counted once, all of it excluded from the recoverable total.

$22,326/mo on NVIDIA V100 (p3), superseded silicon

$22k
observed per month
$0
claimed as recoverable
4
resources
4/5
disruption to change

What is missing.Whether a newer family is cheaper for these workloads depends on model size, precision, memory footprint and batch size. None of that is in a Cost and Usage Report. Closing this gap needs one benchmark run of the real workload on a current-generation instance, measuring throughput per dollar rather than utilization. That is a day of work per distinct workload and it is the only thing that will settle it.

What to do.Benchmark the largest single workload on a current-generation instance before changing anything. Do not migrate a fleet on the strength of a spec sheet.

resourceaccountinstance typeaccelerator$ / month
i-00000000000000101b111111111111p3.8xlargeNVIDIA V100$8,930
i-00000000000000101d111111111111p3.8xlargeNVIDIA V100$8,930
i-00000000000000101a111111111111p3.2xlargeNVIDIA V100$2,233
i-00000000000000101c111111111111p3.2xlargeNVIDIA V100$2,233

$309,670/mo of GPU spend has no utilization telemetry (100% of GPU spend)

$310k
observed per month
$0
claimed as recoverable
40
resources
1/5
disruption to change

What is missing.No per-GPU utilization data exists for these instances, so no statement can be made about whether the silicon did work. Closing this gap means running the NVIDIA DCGM exporter with profiling metrics enabled and scraping DCGM_FI_PROF_SM_ACTIVE and DCGM_FI_PROF_PIPE_TENSOR_ACTIVE into Prometheus. Note that DCGM_FI_DEV_GPU_UTIL, the metric on most default dashboards, does not close this gap: it reports whether a kernel was resident, not how much of the chip it used. In our own lab measurement on one H100 rented on Lambda, published at nameplateanalytics.com/method, two configurations of one training job read 99.5% and 99.3% GPU utilization while one produced 26.6 times the real tokens per second of the other. That is one GPU and a configuration built for the test, so it shows what the reading misses, not how often. Export the result with its sample count and the span the samples cover; a mean on its own cannot be tied to any part of the billing period.

What to do.Deploy the NVIDIA DCGM exporter, add DCGM_FI_PROF_SM_ACTIVE to its counters file, which the shipped default comments out, and give the container SYS_ADMIN so the profiling fields can be read. Pod and namespace mapping comes from --kubernetes, which the published manifests already set; pod labels need --kubernetes-enable-pod-labels, which they do not. Two weeks of data is enough to size the next engagement.

resourceaccountinstance typeaccelerator$ / month
i-000000000000001001111111111111p5.48xlargeNVIDIA H100$40,157
i-000000000000001005111111111111p5.48xlargeNVIDIA H100$40,157
i-000000000000001025111111111111p5.48xlargeNVIDIA H100$28,913
i-000000000000001009111111111111p5.48xlargeNVIDIA H100$28,913
i-000000000000001021111111111111p5.48xlargeNVIDIA H100$24,897
i-000000000000001024111111111111p4d.24xlargeNVIDIA A100$16,020
i-000000000000001004111111111111p4d.24xlargeNVIDIA A100$16,020
i-000000000000001019111111111111p5.48xlargeNVIDIA H100$15,059
i-000000000000001000111111111111p4d.24xlargeNVIDIA A100$9,933
i-000000000000001008111111111111p4d.24xlargeNVIDIA A100$9,933
i-000000000000001020111111111111p4d.24xlargeNVIDIA A100$9,933
i-00000000000000101d111111111111p3.8xlargeNVIDIA V100$8,930
i-00000000000000101b111111111111p3.8xlargeNVIDIA V100$8,930
i-000000000000001018111111111111p4d.24xlargeNVIDIA A100$4,325
i-000000000000001023111111111111g5.12xlargeNVIDIA A10G$4,138
i-00000000000000101f111111111111g5.12xlargeNVIDIA A10G$4,138
i-000000000000001027111111111111g5.12xlargeNVIDIA A10G$4,138
i-000000000000001007111111111111g5.12xlargeNVIDIA A10G$4,138
i-000000000000001003111111111111g5.12xlargeNVIDIA A10G$2,980
i-000000000000001011111111111111g4dn.12xlargeNVIDIA T4$2,854
i-00000000000000100e111111111111g4dn.12xlargeNVIDIA T4$2,854
i-00000000000000100b111111111111g4dn.12xlargeNVIDIA T4$2,854
i-000000000000001014222222222222g4dn.12xlargeNVIDIA T4$2,854
i-00000000000000101c111111111111p3.2xlargeNVIDIA V100$2,233
i-00000000000000101a111111111111p3.2xlargeNVIDIA V100$2,233

Showing the 25 largest of 40 resources. The full list is in the machine-readable findings file that accompanies this report.

$97,207/mo of GPU capacity is claimed by a pod but has no utilization data

$97k
observed per month
$0
claimed as recoverable
9
resources
1/5
disruption to change

What is missing.A pod holding a GPU proves the accelerator is reserved, not that it is busy. Whether these GPUs are doing work needs DCGM_FI_PROF_SM_ACTIVE, and for tensor workloads DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, scraped per pod. Two things are usually in the way. DCGM_FI_PROF_SM_ACTIVE is commented out of the exporter's default counters file, so it has to be added and the exporter needs SYS_ADMIN to read it. And pod labels are only attached when the exporter runs with --kubernetes-enable-pod-labels, which the published Helm chart leaves off; pod and namespace mapping itself comes from --kubernetes, which the shipped manifests do set.

What to do.Add DCGM_FI_PROF_SM_ACTIVE to the exporter's counters file, give the container SYS_ADMIN, and turn on --kubernetes-enable-pod-labels so the metrics carry the pod they belong to. Scrape for two weeks, then re-run this audit. Nothing should be resized before that data exists.

4 Cluster allocation

How many of the accelerators you are paying for has anything asked for. This needs no new instrumentation: if a node advertises eight GPUs and no pod requests one, utilization is zero by definition.

40 of 63 GPUs requested (63%)23 provisioned and unclaimed
Read from .status.capacity on each node and from the GPU requests of every non-terminated pod. 3 of 12 GPU nodes have no pod requesting an accelerator.

Illustrative figures from a synthetic specimen.

$60k
per month on GPUs nothing has requested
$97k
per month on GPUs a pod is holding
12
nodes matched to a line in the bill

Cost by namespace (illustrative figures from a synthetic specimen)

platform$53kresearch$31kinference$13k
Each node's cost is split by the share of its GPUs a namespace requested. The unrequested share is not charged to anyone, which is the point of the figure above.

5 What this report cannot tell you

Each gap below is a question the billing data cannot answer, the dollars sitting behind it, and the specific measurement that would close it.

Question left openObserved per monthWhat would close it
$309,670/mo of GPU spend has no utilization telemetry (100% of GPU spend)$310kNo per-GPU utilization data exists for these instances, so no statement can be made about whether the silicon did work. Closing this gap means running the NVIDIA DCGM exporter with profiling metrics enabled and scraping DCGM_FI_PROF_SM_ACTIVE and DCGM_FI_PROF_PIPE_TENSOR_ACTIVE into Prometheus. Note that DCGM_FI_DEV_GPU_UTIL, the metric on most default dashboards, does not close this gap: it reports whether a kernel was resident, not how much of the chip it used. In our own lab measurement on one H100 rented on Lambda, published at nameplateanalytics.com/method, two configurations of one training job read 99.5% and 99.3% GPU utilization while one produced 26.6 times the real tokens per second of the other. That is one GPU and a configuration built for the test, so it shows what the reading misses, not how often. Export the result with its sample count and the span the samples cover; a mean on its own cannot be tied to any part of the billing period.
$97,207/mo of GPU capacity is claimed by a pod but has no utilization data$97kA pod holding a GPU proves the accelerator is reserved, not that it is busy. Whether these GPUs are doing work needs DCGM_FI_PROF_SM_ACTIVE, and for tensor workloads DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, scraped per pod. Two things are usually in the way. DCGM_FI_PROF_SM_ACTIVE is commented out of the exporter's default counters file, so it has to be added and the exporter needs SYS_ADMIN to read it. And pod labels are only attached when the exporter runs with --kubernetes-enable-pod-labels, which the published Helm chart leaves off; pod and namespace mapping itself comes from --kubernetes, which the shipped manifests do set.
$22,326/mo on NVIDIA V100 (p3), superseded silicon$22kWhether a newer family is cheaper for these workloads depends on model size, precision, memory footprint and batch size. None of that is in a Cost and Usage Report. Closing this gap needs one benchmark run of the real workload on a current-generation instance, measuring throughput per dollar rather than utilization. That is a day of work per distinct workload and it is the only thing that will settle it.

The rows above overlap: one machine can sit behind more than one open question, so the column does not add up and is not meant to. Counting each machine once, and setting aside what is already claimed elsewhere in this report, $213k per month is observed and not claimed. None of it is in the recoverable figure. Closing these gaps is the work of the next engagement, and the honest reason to do it is that the answer might be that nothing is wrong.

6 Order of work

Ordered by recoverable dollars per unit of disruption, not by dollars alone. The first item is the one that returns the most for the least argument.

gpu zero allocation$60kdisruption 2/5uncommitted steady gpu$24kdisruption 3/5always on nonprod inferred$8,369disruption 2/5always on nonprod tagged$4,562disruption 2/5unused commitment$1,976disruption 2/5orphaned storage$320disruption 1/5
Bar length is recoverable dollars per month. The disruption score at the right is the effort and risk of making the change, from 1 (delete an orphan) to 5 (re-architect a pipeline).
  1. 23 of 63 provisioned GPUs had no pod requesting them when the cluster was read, $60,432/mo

    $60k per month, disruption 2 of 5. Scale the affected node groups down to the number of GPUs actually requested. Where a node group exists for burst capacity, set its floor to zero and let the cluster autoscaler bring it up on a pending pod.

  2. 14 production GPU instances run continuously at on-demand rates, $153,949/mo

    $24k per month, disruption 3 of 5. Size a Compute Savings Plan to the observed floor of GPU usage, not to the peak. Commit to the level that has been running every day of the period and leave the rest on demand.

  3. 9 untagged instances read as non-production and run continuously, $11,916/mo

    $8,369 per month, disruption 2 of 5. Confirm the classification, tag the resources so this stops being an inference, then schedule them off outside working hours.

  4. 10 tagged non-production instances run continuously, $6,495/mo, $4,706/mo of it GPU

    $4,562 per month, disruption 2 of 5. Stop non-production instances outside working hours with an EventBridge schedule or an autoscaler floor of zero. GPU instances should be stopped rather than resized, because the accelerator is the entire cost.

  5. Commitment purchased and not consumed: $1,216/mo of Reserved Instance capacity and $760/mo of Savings Plan commitment

    $1,976 per month, disruption 2 of 5. Sell unused Standard RIs on the Reserved Instance Marketplace where the term allows, or move workloads onto the committed instance families so the commitment is consumed. Savings Plan commitments cannot be sold; the recovery is to shift eligible usage onto them before the term ends.

  6. 4 EBS volumes and snapshots billed for the full period with no associated compute, $320/mo

    $320 per month, disruption 1 of 5. Snapshot then delete volumes confirmed as available. For snapshots, apply a lifecycle policy rather than deleting by hand.

7 Method

Costs are amortized. On-demand line items use unblended cost; reserved-instance-covered usage uses reservation_effective_cost; Savings-Plan-covered usage uses savings_plan_savings_plan_effective_cost; unused commitment is read from the RIFee and SavingsPlanRecurringFee rows. Savings Plan negation rows are excluded so that covered usage is not counted twice.

Commitment rows were read: 8,880 DiscountedUsage, 30 RIFee, 6,990 SavingsPlanCoveredUsage and 30 SavingsPlanRecurringFee rows. Unused commitment across them comes to $1,976 per month. The commitment finding above lists it. These dollars come from a synthetic fixture whose answer is known by construction.

Period figures are scaled to a 30.4-day month. Neither non-production finding is rated PROVEN, including the one that rests on your own Environment tag: the tag and the run hours are read from data you already own, but recovering the money means scheduling the machines off, and that assumes a working week. The assumed hours are printed on both findings. Where a resource is identified as non-production without a tag saying so, the signals used are printed next to it as well.