Public
Edited
Mar 10, 2023
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
instanceCosts.view()
Insert cell
bestClusters = ({ minClusterMem = 0, minClusterCpus = 0, minInstanceMem = 0, minInstanceCpus = 0, arch = "x86_64", spot = false, currentRuntime, currentThreads } = {}) => {
let clusters = instanceCosts
.params({
minClusterMem,
minClusterCpus,
minInstanceMem,
minInstanceCpus,
arch,
})
.filter(
(d, $) => $.arch === 'both' ? true : d.arch === $.arch
)
.filter(
(d, $) => (d.memoryGib >= $.minInstanceMem) && (d.vcpus >= $.minInstanceCpus)
)
.impute({
hourlyPriceSpot: Infinity
})
.derive({
count: (d, $) => op.greatest(
op.ceil($.minClusterMem / d.memoryGib),
op.ceil($.minClusterCpus / d.vcpus),
)
})
.derive({
totalMemoryGib: d => d.memoryGib * d.count,
totalVcpus: d => d.vcpus * d.count,
totalHourlyPrice: d => d.hourlyPrice * d.count,
totalHourlyPriceSpot: d => d.hourlyPriceSpot * d.count,
})
.derive({
extraMemGiB: (d, $) => d.totalMemoryGib - $.minClusterMem,
extraCpus: (d, $) => d.totalVcpus - $.minClusterCpus,
})
// For identical configurations, only show the cheapest option
.groupby('totalMemoryGib', 'totalVcpus')
.filter(d => d.totalHourlyPrice === op.min(d.totalHourlyPrice))
.ungroup()
.select(aq.not('hourlyPrice', 'hourlyPriceSpot'))

console.log(currentRuntime);
if (currentRuntime === undefined || currentThreads === undefined) {
clusters = clusters
.orderby((spot ? 'totalHourlyPriceSpot' : 'totalHourlyPrice'), 'extraMemGiB', 'extraCpus')
} else {
// estimate new runtime, assuming linear speedup as CPU count increases (obvs not always true!)
clusters = clusters
.params({currentRuntime, currentThreads, spot})
.derive({
runtime: (d, $) => ($.currentThreads / d.totalVcpus) * $.currentRuntime
})
.derive({
cost: (d, $) => d[$.spot ? 'totalHourlyPriceSpot' : 'totalHourlyPrice'] / (3600 / d.runtime)
})
.orderby('cost', (spot ? 'totalHourlyPriceSpot' : 'totalHourlyPrice'), 'extraMemGiB', 'extraCpus')
}
return clusters
}
Insert cell
bestCluster = (...args) => {
return bestClusters(...args)
.object(0)
}
Insert cell
clusters = bestClusters({
minClusterMem,
minClusterCpus,
minInstanceMem,
minInstanceCpus,
arch,
currentRuntime: currentRuntime === "" ? undefined : parseInt(currentRuntime),
currentThreads: currentThreads === "" ? undefined : parseInt(currentThreads),
})
Insert cell
hourlyCostLookup = {
const names = instanceCosts.column('name');
const prices = instanceCosts.column('hourlyPrice');
const lookup = new Map();
for (let i = 0; i < names.length; i++) {
lookup[names.get(i)] = prices.get(i)
}
return lookup
}
Insert cell
// get the cost for a cluster of a particular instance type
clusterCost = (type, count, seconds) => {
return hourlyCostLookup[type] * count / (3600 / seconds)
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more