Skip to content

Instantly share code, notes, and snippets.

@stephenVertex
Created February 16, 2023 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stephenVertex/4f02350032f7bc2ae64fbf20e71ae8f3 to your computer and use it in GitHub Desktop.
Save stephenVertex/4f02350032f7bc2ae64fbf20e71ae8f3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
## Calculate gp2 price, and return max throughput and IOPS
def mkGp2(vol_size_gb):
### See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/general-purpose.html#gp2-performance
d = {}
d['price'] = 0.10 * vol_size_gb
if vol_size_gb < 33.33:
d['iops'] = 100
else:
d['iops'] = min(16000, 3 * vol_size_gb)
## Calculate throughput max, ignoring bursting from 170 to 334.
if vol_size_gb <= 334:
d['throughput_max'] = 128
else:
d['throughput_max'] = 250
return(d)
## Calculate gp3 price, as a function of size, required IOPS
## and required throughput
def mkGp3(vol_size_gb, req_iops, req_throughput):
storage_price = 0.08 * vol_size_gb
prov_iops = min(13000, max(req_iops - 3000, 0))
prov_iops_price = 0.005 * prov_iops
prov_throughput = min(875, max(req_throughput - 125, 0))
prov_throughput_price = 0.040 * prov_throughput
d = {}
d['price'] = storage_price + prov_iops_price + prov_throughput_price
d['iops'] = 3000 + prov_iops
d['throughput_max'] = 125 + prov_throughput
d['price_details'] = {
'storage' : storage_price,
'prov_iops': prov_iops_price,
'prov_throughput' : prov_throughput_price
}
return(d)
def transform_df(df):
"""
Given an input data frame, transport it to have a volume_type column.
This makes it easier to plot.
"""
melted_df = df.melt(id_vars=['size_gb'], value_vars=['price_gp2', 'price_gp3'], var_name='volume_type', value_name='price')
melted_df['volume_type'] = melted_df['volume_type'].apply(lambda x: x.split('_')[-1])
return melted_df
def plot_df(df):
"""
Create a simple line plot of the price vs volume type
"""
sns.lineplot(x="size_gb", y="price", data=df, hue="volume_type")
plt.show()
def plot_df_2y(df_price, df_ratio):
"""
Create a two axis line plot where the left axis has the price comparison and the right
axis has the ratio
"""
fig, ax1 = plt.subplots()
sns.lineplot(x="size_gb", y="price", data=df_price, hue="volume_type", ax=ax1)
ax2 = ax1.twinx()
sns.lineplot(x="size_gb", y="ratio", data=df_ratio, color="yellow", ax=ax2)
plt.show()
## Iterate over sizes from 1GB to 16TB, in 100GB steps
sizes = range(1, 16000, 10)
prices = []
for size_gb in sizes:
gp2 = lib2.mkGp2(size_gb)
gp3 = lib2.mkGp3(size_gb, gp2['iops'], gp2['throughput_max'])
x = { 'size_gb' : size_gb,
'price_gp2' : gp2['price'],
'price_gp3' : gp3['price']
}
prices.append(x)
## Transform and plot data
df1 = pd.DataFrame(prices)
df2 = transform_df(df1)
price_ratio = df1.assign(ratio=df1["price_gp3"]/df1["price_gp2"])[['size_gb', 'ratio']]
price_ratio = price_ratio[price_ratio['size_gb'] > 1]
plot_df_2y(df2, price_ratio)
@stephenVertex
Copy link
Author

The following bit of Python code shows how the pricing simulation works.

Function: mkGp2 - Given a volume size, return a price (according to Feb 2023 us-east-1 pricing), as well as corresponding IOPS and throughput. Note: This does not take into account throughput bursting of gp2.

Function: mkGp3 - Given a volume size, IOPS, and throughput requirement, calculate a price. This function is used for calculating a price for a gp3 instance which is equivalent in performance to a gp2 instance.

Main: The main bit of code loops over volume sizes from 1GiB to 16TiB, in 10 GiB increments. For each volume size, it simulates a gp2 instance. Given the performance of the gp2 instance in terms of IOPS and throughput, it simulates an equivalent gp3 instance.

Plotting: This code uses the seaborn library for data visualization

@cavit99
Copy link

cavit99 commented Jun 19, 2023

lib2 seems a mistake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment