Engineering4 min read

ByEmmanuel Bakare

Splitting instance prices with linear programming

How CostGraph estimates CPU, memory, and GPU costs from each machine family’s price list while keeping the total unchanged.

Ask about this postClaudeChatGPTPerplexity

A cloud machine has one price, but CostGraph needs separate CPU, memory, and GPU costs. We now estimate those costs from each provider's price list while keeping the total unchanged.

The problem

An AWS r7i.large costs $0.1323 an hour on the EC2 price list. For that you get 2 vCPU and 16 GiB of memory. AWS does not say how much of the $0.1323 is the CPU and how much is the memory, because you cannot buy them on their own.

When CostGraph tells you what a pod costs, or how much a smaller machine would save, it has to price CPU, memory, and GPU separately.

The old way

Google Cloud publishes separate CPU and memory prices and GPU prices. For everyone else, we assumed a vCPU cost 7.5 times as much as a GiB of memory.

Published splits use provider rates. Our estimates used the 7.5 rule, which gave these two AWS machines different CPU costs despite both having 2 vCPU. The totals stayed correct, but the CPU estimates were inconsistent.

Our approach lets the list price decide

Since a provider such as AWS does not directly tell you the price of one vCPU, we use the price differences between machines. If adding 8 GiB of memory adds $0.03, that helps us estimate what memory costs. We compare prices across a family of machines and find the CPU and memory rates that fit them best.

Grouping machines into families

We only compare machines built on the same hardware. AWS's naming guide helps identify them. In c7i, the c means compute optimized, 7 is the generation, and i is Intel. c7i, m7i, and r7i use the same Intel chips with 2, 4, and 8 GiB per vCPU, so we treat them as one family. Graviton-based c7g and AMD-based c7a use different chips, so each gets its own family.

Finding the best fit

The three .large machines in the 7i family all have 2 vCPU. Only their memory and price differ. On a chart of price against memory, a line's starting value estimates the CPU cost. Its slope estimates the cost of each GiB of memory.

No straight line hits all three prices exactly, so we look for the one with the smallest error. The following demo compares three candidate lines.

Trying lines until the error stops shrinking
price per hour$0.00$0.05$0.1004816memory, GiB (every machine has 2 vCPU)2 vCPU = $0.0749$0.0036 per GiB of memoryc7i.largem7i.larger7i.large
  1. try 1through c7i and m7i6.4% off
  2. try 2through m7i and r7i4.7% off
  3. try 3through c7i and r7i2.8% off
the solver stops when it cannot reduce the error

We express this as a linear programming problem. Our solver uses the simplex method, which moves between candidate solutions to find the lowest error. Gradient descent instead takes small steps downhill.

We look for a price per vCPU and a price per GiB. Neither can be below zero. For each machine, we compare the predicted total with its listed price and measure the error as a percentage. This gives cheap and expensive machines equal weight. We choose the pair with the smallest total error.

In the following formula, cc is the price of one vCPU and mm is the price of one GiB.

min⁡c, m ≥ 0 ∑machines i∣ c⋅vCPUi+m⋅GiBi−pricei ∣pricei\min_{c,\ m\ \ge\ 0} \ \sum_{\text{machines } i} \frac{\left|\, c \cdot \text{vCPU}_i + m \cdot \text{GiB}_i - \text{price}_i \,\right|}{\text{price}_i}

For the 7i family, the fitted ratio is 10.44 GiB of memory per vCPU, compared with the old ratio of 7.5. The following demo shows how that changes each machine's split.

Splitting the same price in two
c7i.large
2 vCPU, 4 GiB, $0.0893/h
78.9%
$0.0352 per vCPU-hour, $0.00469 per GiB-hour
m7i.large
2 vCPU, 8 GiB, $0.1008/h
65.2%
$0.0329 per vCPU-hour, $0.00439 per GiB-hour
r7i.large
2 vCPU, 16 GiB, $0.1323/h
48.4%
$0.0320 per vCPU-hour, $0.00427 per GiB-hour
CPUmemorybar length is the price and never changesone vCPU, three different costs

With the new ratio, c7i and r7i now agree on what a vCPU costs.

Adding the GPU

GPUs work the same way. The five smallest AWS g5 sizes, from g5.xlarge to g5.16xlarge, each have one A10G GPU. A g5.16xlarge has 16 times the vCPUs and memory of a g5.xlarge. We keep the CPU to memory ratio we already learned and fit the GPU price against each machine's full price.

It is the same chart as before. On the 7i chart, every machine had 2 vCPU, so the line's starting value was the CPU cost. Here every machine has one GPU, so the line's starting value, where CPU and memory are zero, is the GPU cost.

Each extra 4 vCPU and 16 GiB adds $0.206. Following the line back to zero CPU and memory gives $1.006 - $0.206 = $0.800 an hour per A10G. The line hits all five prices exactly, so their price differences come from CPU and memory.

The bigger sizes check the answer. g5.12xlarge and g5.24xlarge have 4 GPUs, and g5.48xlarge has 8. Price them as $0.800 per GPU plus the same CPU and memory prices, and you get $5.672, $8.144, and $16.288 an hour, exactly what AWS charges.

One A10G, one rate, on every size
1 GPU
g5.xlarge $1.006/h
$0.80
one price
g5.2xlarge $1.212/h
$0.80
one price
g5.4xlarge $1.624/h
$0.80
one price
g5.8xlarge $2.448/h
$0.80
one price
g5.16xlarge $4.096/h
$0.80
one price
4 and 8 GPUs, drawn at a smaller scale
g5.12xlarge $5.672/h
4 x $0.80
one price
g5.24xlarge $8.144/h
4 x $0.80
one price
g5.48xlarge $16.288/h
8 x $0.80
one price
CPUmemoryGPUAWS g5, bar length is the price

How the parts add up

The fits produce two values: the CPU to memory ratio and the price per GPU. Each machine's CPU and memory costs then come from its own listed price:

  1. Subtract the GPU cost from the machine's price. The rest is the cost of its CPU and memory.
  2. Split that cost between CPU and memory using the ratio.

The parts therefore always add up to the listed price. For a g5.xlarge:

When a family's prices follow the line exactly, like g5, every size gets the same CPU and memory prices. When they do not, the GPU price and the ratio stay fixed and each machine's CPU and memory prices absorb its own difference. m7i.large is 2.8% off the 7i line, so its vCPU price is $0.0365 an hour, compared with $0.0375 for c7i.large and r7i.large.

All together

We repeat this process whenever a provider's prices refresh.

One pass every time prices refresh
  1. 01
    group

    Group machines with the same generation and silicon, regardless of memory per vCPU.

    c7i + m7i + r7i -> 7i
  2. 02
    learn CPU and memory costs

    Linear programming finds the vCPU and GiB costs that best explain the family's prices.

    7i → 1 vCPU = 10.44 GiB
    if it cannot be learned
    provider's median ratio, then the ratio Google Cloud publishes
  3. 03
    learn the GPU

    With that ratio held fixed, the same approach finds one rate per GPU model across its family.

    g5 → $0.800 per A10G
    if it cannot be learned
    what is left after CPU and memory
  4. 04
    split each machine

    Each machine is split on its own price, so the parts always add back to it.

    cpu + memory + gpu = price

Sometimes there is nothing to compare. A family with only one size has no steps to learn from. In that case we borrow the usual ratio from the same provider, or from Google Cloud if the provider has none.

Discounts keep the same split. A spot or reserved machine is split the same way as its full-price version, just with every part scaled down.

Across every provider

The same process runs for every provider we support, each time its prices refresh. What comes out depends on how each one sets its prices.

  • Google Cloud publishes CPU, memory, and GPU prices, so we use them directly. They also serve as a reference for checking our estimates and as the final fallback for other providers.
  • For AWS and Azure, we learn a ratio for almost every family. Their ratios are around 10, compared with the old 7.5.
  • Providers with bundled extras or tiered pricing, such as DigitalOcean, use Google Cloud's ratio of 8.79.
  • GPU providers such as RunPod and Vast list a price per GPU-hour, which we use as the GPU cost.
  • For the largest AWS and Azure training machines, GPU, CPU, and memory capacity grow together. That leaves too little variation to isolate a GPU price, so we estimate its share.

Try it on your machines

Connect a cloud account and open a node in CostGraph to see its CPU, memory, and GPU cost breakdown. Get started for free or book a demo with us.

Frequently asked questions

Put your bill to work

Connect a provider, watch your spend attribute itself, ask GraphAI where the money’s going.