GPU costs represent the single largest expense in AI infrastructure, often exceeding 60% of total cloud spend for machine learning teams. A 2025 FinOps Foundation report found that managing AI and ML spending jumped four positions in priority as organizations struggle with unpredictable GPU bills that can swing from $5,000 to $50,000 monthly without warning.
Unlike traditional cloud workloads where cost follows predictable patterns, AI workloads create three unique cost challenges. GPUs accrue charges continuously whether idle or active. Training workloads generate burst spend patterns that scale infrastructure in hours. Token-based inference pricing compounds silently as conversation history multiplies request volume through what engineers call the context window tax.
This guide walks through the exact steps to implement GPU cost monitoring that connects utilization metrics with financial data, identifies waste before it compounds, and gives engineering and finance teams shared visibility into what drives AI spend.
Prerequisites
Before implementing GPU cost monitoring, ensure you have:
- Admin access to your cloud account (AWS, GCP, Azure, or GPU-as-a-Service provider)
- Existing GPU workloads running (training jobs, inference endpoints, or development environments)
- Access to cloud billing data or cost management APIs
- Basic familiarity with Prometheus, OpenTelemetry, or cloud native monitoring tools
- SSH or kubectl access to GPU nodes for agent installation
- Permissions to create dashboards and alerts in your monitoring platform
Step 1: Instrument GPU Nodes with Telemetry Collection
GPU cost visibility starts with telemetry. Without metrics tied to each GPU instance, you cannot connect utilization to spend.
Install NVIDIA’s Data Center GPU Manager (DCGM) exporter on every GPU node. DCGM surfaces metrics at the device level including GPU utilization percentage, memory usage, power draw, temperature, and SM clock rate.
For Kubernetes clusters running GPU workloads, deploy the DCGM exporter as a DaemonSet to ensure every node reports metrics:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: dcgm-exporter
namespace: gpu-monitoring
spec:
selector:
matchLabels:
app: dcgm-exporter
template:
metadata:
labels:
app: dcgm-exporter
spec:
nodeSelector:
nvidia.com/gpu: "true"
containers:
- name: dcgm-exporter
image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.8-3.6.0-ubuntu22.04
ports:
- name: metrics
containerPort: 9400
securityContext:
runAsNonRoot: false
runAsUser: 0
volumeMounts:
- name: pod-resources
mountPath: /var/lib/kubelet/pod-resources
volumes:
- name: pod-resources
hostPath:
path: /var/lib/kubelet/pod-resources
For non-Kubernetes environments, install DCGM exporter directly on each GPU instance and configure it to expose metrics on port 9400. Point your Prometheus server or OpenTelemetry collector at these endpoints to begin ingesting GPU telemetry.
The critical metrics to collect at this stage: DCGM_FI_DEV_GPU_UTIL (GPU utilization percentage), DCGM_FI_DEV_FB_USED (framebuffer memory used), DCGM_FI_DEV_POWER_USAGE (power draw in watts), and DCGM_FI_DEV_GPU_TEMP (temperature).
Once telemetry flows, verify data arrival by querying your monitoring backend. If using Prometheus, run:
curl http://prometheus-server:9090/api/v1/query?query=DCGM_FI_DEV_GPU_UTIL
You should see per-device utilization values. If metrics are missing, check firewall rules, DaemonSet pod status, or DCGM exporter logs.
Step 2: Connect Cloud Cost Data to GPU Resource Tags
GPU utilization metrics alone do not reveal spend. You must join telemetry with cost allocation tags to calculate dollars per workload.
Every cloud provider structures cost data differently. AWS Cost Explorer surfaces costs by instance ID and resource tags. GCP Billing Export writes line items to BigQuery. Azure Cost Management API provides programmatic access to usage and charges.
Start by tagging all GPU instances with workload metadata. Common tags include team, project, environment (staging vs production), model name, and job ID. Consistent tagging enables cost rollup by any dimension you choose.
In AWS, apply tags via the EC2 console or AWS CLI:
aws ec2 create-tags --resources i-1234567890abcdef0 \
--tags Key=team,Value=ml-platform \
Key=project,Value=recommendation-engine \
Key=environment,Value=production
For Kubernetes GPU workloads, tags propagate from pod labels if your cloud provider supports label to tag mapping. GKE automatically syncs specific labels to billing tags. EKS requires the AWS Load Balancer Controller or custom tooling to push pod labels into EC2 tags.
Once tags exist, export cost data into your monitoring or analytics platform. AWS Cost and Usage Reports can be delivered to S3 then ingested into your data warehouse. GCP Billing Export lands in BigQuery by default. Azure Cost Management API supports scheduled exports to Blob Storage.
The goal is a queryable dataset where each GPU instance hour has both utilization metrics and cost figures attached. This join happens in your monitoring platform’s query layer or in a dedicated cost analytics tool.
Example query joining GPU utilization with cost in Prometheus and AWS Cost Explorer data:
sum by (instance_id, team) (
rate(DCGM_FI_DEV_GPU_UTIL[5m])
* on(instance_id) group_left(cost_per_hour) aws_ec2_cost_per_hour
)
This requires ingesting AWS cost data as Prometheus metrics or using a platform that natively joins telemetry and billing.
Step 3: Build Cost Dashboards Showing Utilization and Spend Together
With telemetry and cost data connected, build dashboards that surface waste and cost drivers.
The most valuable dashboard for AI cost monitoring displays three panels side by side: total GPU spend by team or project, average GPU utilization percentage across the fleet, and idle GPU cost (instances with utilization below 10% over the past hour).
In Grafana, create a dashboard with these queries using Prometheus as the data source:
Panel 1: Total GPU cost by team (last 7 days)
sum by (team) (
aws_ec2_cost_per_hour{instance_type=~"p3.*|p4.*|g4dn.*|g5.*"}
) * 24 * 7
Panel 2: Fleet wide GPU utilization percentage (current)
avg(DCGM_FI_DEV_GPU_UTIL)
Panel 3: Idle GPU cost (instances under 10% utilization, last hour)
sum(
aws_ec2_cost_per_hour{instance_type=~"p3.*|p4.*|g4dn.*|g5.*"}
* on(instance_id) group_left
(avg_over_time(DCGM_FI_DEV_GPU_UTIL[1h]) < 10)
)
Add a fourth panel ranking workloads by cost per unit of work. For training jobs, this could be cost per epoch. For inference, cost per million tokens processed. This requires custom labels emitted by your ML framework.
The idle cost panel typically reveals the largest optimization opportunity. Infrastructure monitoring platforms that correlate resource metrics with cost data make it easier to spot these patterns across hosts, containers, and GPU devices.
Datadog’s GPU Monitoring surfaces similar insights but charges $31 per GPU host per month on top of APM and log ingestion fees. For a 50 node GPU cluster, that adds $18,600 annually just for GPU visibility before counting trace or log costs.
CubeAPM provides GPU device monitoring as part of its unified infrastructure monitoring at $0.15/GB ingestion with no per-host fees. A typical GPU cluster ingesting 5TB monthly of metrics, logs, and traces costs $750 with CubeAPM compared to over $4,000 monthly with Datadog once APM and log indexing are included.
Step 4: Set Alerts for Idle GPUs and Cost Anomalies
Dashboards show historical trends. Alerts prevent waste from compounding.
Configure two alert types: immediate alerts for completely idle GPUs, and anomaly alerts for cost spikes that exceed baseline by a defined threshold.
Idle GPU alert example (Prometheus Alertmanager):
groups:
- name: gpu_cost_alerts
interval: 5m
rules:
- alert: IdleGPUOver1Hour
expr: |
avg_over_time(DCGM_FI_DEV_GPU_UTIL[1h]) < 5
for: 1h
labels:
severity: warning
team: "{{ $labels.team }}"
annotations:
summary: "GPU {{ $labels.instance_id }} idle for 1 hour"
description: "Instance {{ $labels.instance_id }} in team {{ $labels.team }} has been under 5% utilization for 1 hour. Current cost: ${{ $value }} per hour."
Route these alerts to Slack channels organized by team so workload owners see waste in real time.
Cost anomaly alert example:
- alert: GPUCostSpike
expr: |
sum by (team) (aws_ec2_cost_per_hour)
>
(avg_over_time(sum by (team) (aws_ec2_cost_per_hour)[7d]) * 1.5)
for: 30m
labels:
severity: critical
annotations:
summary: "GPU cost spike detected for team {{ $labels.team }}"
description: "Team {{ $labels.team }} GPU spend is 50% above 7 day average. Current hourly rate: ${{ $value }}."
This fires when a team’s GPU cost exceeds their weekly average by 50% for more than 30 minutes. It catches auto scaling events that spin up expensive instances and forget to terminate them.
A production team at a logistics company used this exact alert to detect a training job that misconfigured its termination logic. The job completed but left 12 p4d.24xlarge instances ($32.77/hour each) running for 18 hours, costing $7,077 unnecessarily. The alert fired within 45 minutes and the team terminated the instances before a full day elapsed.
Step 5: Identify and Tag Zombie Processes Holding GPU Resources
Zombie processes represent one of the largest sources of wasted GPU spend. These are workloads that reserve GPU capacity but perform no computation, often because an error occurred and the process never exited cleanly.
To identify zombies, query for GPU processes with non-zero memory allocation but zero utilization over a sustained period.
List all processes holding GPU memory using nvidia-smi on each node:
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv,noheader
Cross reference these PIDs with GPU utilization metrics. If a process holds 10GB of GPU memory but DCGM_FI_DEV_GPU_UTIL shows 0% for that device over 15 minutes, it is likely a zombie.
Automate zombie detection with a scheduled script that runs every 10 minutes:
#!/bin/bash
GPU_PROCS=$(nvidia-smi --query-compute-apps=pid,used_memory --format=csv,noheader,nounits)
while IFS=, read -r PID MEM; do
UTIL=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits -i 0)
if [ "$UTIL" -lt 5 ] && [ "$MEM" -gt 1000 ]; then
echo "Zombie detected: PID $PID using ${MEM}MB with ${UTIL}% utilization"
# Optional: kill -9 $PID after validation
fi
done <<< "$GPU_PROCS"
Before automating termination, validate that the process is truly stuck. Check logs, confirm the parent job completed, and verify no active training or inference is occurring.
Datadog flags these as “ineffective pods” in their GPU Monitoring product. One internal case study from Datadog showed they saved tens of thousands monthly by identifying serving pods stuck in initialization that held GPU capacity for weeks.
CubeAPM’s infrastructure monitoring surfaces similar signals by correlating GPU metrics with pod lifecycle events in Kubernetes. When a pod remains in a running state but GPU utilization stays at zero beyond a configured threshold, it appears in the anomaly view with a recommendation to investigate or terminate.
Step 6: Optimize Inference Costs by Monitoring Token Consumption
Inference workloads using large language models generate costs through token based pricing. Most LLM APIs charge per input and output token, but conversation history is re-sent with every request due to the stateless nature of these APIs.
This creates what engineers call the context window tax. A 10 turn conversation with a chatbot can send thousands of tokens repeatedly, multiplying costs far beyond the new prompt alone.
To monitor token costs, instrument your inference layer to log token counts per request. OpenAI, Anthropic, and most LLM providers return token usage in API responses.
Example Python instrumentation:
import openai
import time
def track_llm_cost(prompt, context):
response = openai.ChatCompletion.create(
model="gpt-4",
messages=context + [{"role": "user", "content": prompt}]
)
input_tokens = response['usage']['prompt_tokens']
output_tokens = response['usage']['completion_tokens']
total_tokens = response['usage']['total_tokens']
# Emit metrics to monitoring platform
emit_metric("llm.tokens.input", input_tokens)
emit_metric("llm.tokens.output", output_tokens)
emit_metric("llm.tokens.total", total_tokens)
# Calculate cost (GPT-4 pricing as of 2026)
cost = (input_tokens * 0.00003) + (output_tokens * 0.00006)
emit_metric("llm.cost.usd", cost)
return response
Aggregate these metrics by endpoint, user, or session to identify cost drivers. A single high volume endpoint with verbose system prompts can consume 10x more tokens than necessary.
Create a dashboard showing token cost by endpoint ranked highest to lowest. Add a panel tracking context window size over time. When context grows unbounded, costs spiral.
Example query in Prometheus:
topk(10,
sum by (endpoint) (rate(llm_cost_usd[1h])) * 3600
)
This surfaces the 10 most expensive endpoints per hour.
One recommendation from cost optimization research: implement context pruning strategies that remove older messages from conversation history after a certain turn count. This reduces token re-transmission while preserving recent context.
Step 7: Track Training Job Costs with Per Job Cost Allocation
Training jobs represent burst spend that can cost thousands of dollars per run. Without per job cost tracking, teams cannot evaluate model development ROI or compare training efficiency across experiments.
To allocate costs per training job, tag cloud instances or Kubernetes pods with job metadata at launch time. Include job ID, model name, experiment ID, and dataset version.
In Kubernetes, MLflow or Kubeflow can inject these labels automatically. For standalone EC2 instances, pass tags via user-data scripts.
Once tags exist, query cost data filtered by job ID:
SELECT
job_id,
SUM(cost) as total_cost,
SUM(gpu_hours) as total_gpu_hours,
SUM(cost) / SUM(gpu_hours) as cost_per_gpu_hour
FROM cloud_cost_export
WHERE resource_type = 'GPU'
AND job_id IS NOT NULL
GROUP BY job_id
ORDER BY total_cost DESC
LIMIT 20;
This reveals which experiments consumed the most resources and whether cost per GPU hour varies across jobs (indicating scheduling inefficiencies or instance type mismatches).
Store these results in a model registry alongside accuracy metrics. Teams can then compare cost versus performance across training runs and optimize for cost-accuracy tradeoffs rather than accuracy alone.
A recommendation from organizations practicing MLOps at scale: append cost metrics to experiment tracking dashboards so data scientists see financial impact alongside model metrics during hyperparameter tuning.
Troubleshooting Common Issues
Metrics not appearing after DCGM exporter installation
Check that the DaemonSet pods are running and that the node selector matches your GPU node labels. Run kubectl get pods -n gpu-monitoring and verify pods are in Running state. If pods are pending, check node affinity and toleration settings. Confirm that DCGM exporter can access NVIDIA driver by checking pod logs with kubectl logs -n gpu-monitoring dcgm-exporter-xxxxx.
Cost data not matching cloud provider bills
Cost data ingestion lag can cause temporary mismatches. AWS Cost and Usage Reports have a delay of up to 24 hours. Verify that the cost data export is configured correctly and that timestamps align between telemetry and billing data. Check that your query accounts for partial hours and that instance pricing includes all charges (compute, storage, network).
Idle GPU alerts firing for active workloads
Some workloads have bursty GPU usage patterns where utilization drops to near zero between batches. Adjust the alert threshold or extend the evaluation window from 1 hour to 2 hours to reduce false positives. Consider using avg_over_time with a longer window or querying for sustained periods below threshold rather than any dip.
Token cost metrics showing zero despite active inference
Confirm that your inference code emits metrics after every LLM API call and that the metrics backend is receiving them. Check network connectivity between your inference service and the metrics collector. Verify that the metric name and labels match your query exactly. Test metric emission in a dev environment with verbose logging enabled.
Per job cost allocation not working in Kubernetes
Ensure that your cloud provider supports syncing Kubernetes labels to billing tags. GKE and EKS both support this but require configuration. In AWS, enable cost allocation tags in the Billing console and wait 24 hours for tags to propagate. Verify that labels on pods match the tag keys you defined in your cost export.
Monitoring GPU Costs with CubeAPM
CubeAPM provides unified GPU cost monitoring by connecting infrastructure metrics, APM traces, and cloud billing data in a single platform. Unlike Datadog which charges per GPU host and requires multiple product SKUs for APM, logs, and infrastructure, CubeAPM uses a flat $0.15/GB ingestion model that includes all signal types.
GPU monitoring in CubeAPM works by ingesting DCGM metrics via OpenTelemetry or Prometheus remote write. These metrics are automatically correlated with Kubernetes pod labels, enabling cost rollup by team, namespace, or workload without custom exporters.
The platform surfaces idle GPUs in a dedicated view that ranks instances by wasted cost per hour. Each entry links to the pod or process holding the GPU, the namespace, and the owner tag, giving teams immediate context to act on.
For inference workloads, CubeAPM traces LLM API calls and joins token usage metrics from response headers with cost data. A built-in dashboard shows token cost by endpoint, model, and user with drill down into individual requests to understand why certain calls are expensive.
CubeAPM runs inside your cloud VPC or on premises, so GPU telemetry and cost data never leave your infrastructure. This eliminates egress fees which can reach $0.10/GB when sending metrics to SaaS tools and keeps sensitive training data and model performance metrics within your security boundary.
A 100 node GPU cluster ingesting 10TB monthly of metrics, logs, and traces costs $1,500 with CubeAPM. The same visibility in Datadog costs over $6,000 monthly once GPU monitoring per host fees, APM traces, and log indexing are combined.
Pricing based on publicly available information as of April 2026. Enterprise discounts and custom contracts are not reflected here.
GPU infrastructure cost monitoring requires connecting device-level utilization metrics with cloud billing data, building dashboards that surface waste, and setting alerts that prevent runaway spend. The steps in this guide apply regardless of whether you use AWS, GCP, Azure, or specialized GPU cloud providers.
The most common optimization opportunities are idle GPUs holding capacity after job completion, zombie processes reserving memory with zero utilization, and inference workloads with unbounded context windows driving token costs. Teams that implement per job cost allocation and correlate spend with model performance metrics make better tradeoffs between cost and accuracy during training.
Disclaimer: The information in this article reflects the latest details available at the time of publication and may change as technologies and products evolve. Features, pricing, and plan limits can change over time. Always verify the latest information directly with the vendor before making purchasing or deployment decisions.
Frequently Asked Questions
What is the difference between GPU utilization and GPU cost?
GPU utilization measures the percentage of compute capacity actively processing workloads while GPU cost measures the hourly charge from your cloud provider regardless of utilization. A GPU at 10% utilization still costs the same per hour as one at 100%, which is why idle GPU detection is critical for cost control.
How do I calculate cost per training job?
Tag each GPU instance or pod with a unique job ID at launch time, then query your cloud cost export filtered by that tag. Sum the total cost for all resources that share the job ID over the duration of the training run. Divide by the number of epochs or model accuracy to calculate cost efficiency.
Why do LLM inference costs increase over time?
LLM APIs charge per token and conversation history is re-sent with every request. As conversations grow longer, each new prompt includes all previous messages, multiplying token counts and costs. Implementing context pruning or summarization reduces this compounding effect.
Can I monitor GPU costs without changing my application code?
Yes, most GPU cost monitoring is done at the infrastructure layer using tools like DCGM exporter which collects device metrics without application changes. However, tracking token usage for LLM inference or per job cost allocation for training requires adding instrumentation to log metadata or emit metrics.
What is a zombie GPU process?
A zombie GPU process is a workload that reserves GPU memory but performs no computation, usually because an error occurred and the process never terminated cleanly. These processes hold capacity and accrue cost while doing no useful work, making them a primary source of waste in GPU infrastructure.
How much can I save by optimizing idle GPUs?
Idle GPU savings depend on your current utilization rate. If your fleet runs at 40% average utilization, you are wasting 60% of GPU spend on idle capacity. For a cluster costing $50,000 monthly, eliminating idle time could save $30,000 per month or $360,000 annually.
Do I need separate tools for GPU monitoring and cost management?
No, unified observability platforms like CubeAPM combine infrastructure metrics and cost data in one dashboard. Using separate tools requires joining data manually or exporting metrics between systems, adding operational overhead and delaying cost visibility.





