| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- import { forEach, get, round } from 'lodash'
- // rangeToCumulative takes an AllocationSetRange (type: array[AllocationSet])
- // and accumulates the values into a single AllocationSet (type: object)
- export function rangeToCumulative(allocationSetRange, aggregateBy) {
- if (allocationSetRange.length === 0) {
- return null
- }
- const result = {}
- forEach(allocationSetRange, (allocSet) => {
- forEach(allocSet, (alloc) => {
- if (result[alloc.name] === undefined) {
- const hrs = get(alloc, 'minutes', 0) / 60.0
- result[alloc.name] = {
- name: alloc.name,
- [aggregateBy]: alloc.name,
- cpuCost: get(alloc, 'cpuCost', 0),
- gpuCost: get(alloc, 'gpuCost', 0),
- ramCost: get(alloc, 'ramCost', 0),
- pvCost: get(alloc, 'pvCost', 0),
- networkCost: get(alloc, 'networkCost', 0),
- sharedCost: get(alloc, 'sharedCost', 0),
- externalCost: get(alloc, 'externalCost', 0),
- totalCost: get(alloc, 'totalCost', 0),
- cpuUseCoreHrs: get(alloc, 'cpuCoreUsageAverage', 0) * hrs,
- cpuReqCoreHrs: get(alloc, 'cpuCoreRequestAverage', 0) * hrs,
- ramUseByteHrs: get(alloc, 'ramByteUsageAverage', 0) * hrs,
- ramReqByteHrs: get(alloc, 'ramByteRequestAverage', 0) * hrs,
- cpuEfficiency: get(alloc, 'cpuEfficiency', 0),
- ramEfficiency: get(alloc, 'ramEfficiency', 0),
- totalEfficiency: get(alloc, 'totalEfficiency', 0),
- }
- } else {
- const hrs = get(alloc, 'minutes', 0) / 60.0
- result[alloc.name].cpuCost += get(alloc, 'cpuCost', 0)
- result[alloc.name].gpuCost += get(alloc, 'gpuCost', 0)
- result[alloc.name].ramCost += get(alloc, 'ramCost', 0)
- result[alloc.name].pvCost += get(alloc, 'pvCost', 0)
- result[alloc.name].networkCost += get(alloc, 'networkCost', 0)
- result[alloc.name].sharedCost += get(alloc, 'sharedCost', 0)
- result[alloc.name].externalCost += get(alloc, 'externalCost', 0)
- result[alloc.name].totalCost += get(alloc, 'totalCost', 0)
- result[alloc.name].cpuUseCoreHrs += get(alloc, 'cpuCoreUsageAverage', 0) * hrs
- result[alloc.name].cpuReqCoreHrs += get(alloc, 'cpuCoreRequestAverage', 0) * hrs
- result[alloc.name].ramUseByteHrs += get(alloc, 'ramByteUsageAverage', 0) * hrs
- result[alloc.name].ramReqByteHrs += get(alloc, 'ramByteRequestAverage', 0) * hrs
- }
- })
- })
- // If the range is of length > 1 (i.e. it is not just a single set) then
- // compute efficiency for each result after accumulating.
- if (allocationSetRange.length > 1) {
- forEach(result, (alloc, name) => {
- // If we can't compute total efficiency, it defaults to 0.0
- let totalEfficiency = 0.0
- // CPU efficiency is defined as (usage/request). If request == 0.0 but
- // usage > 0, then efficiency gets set to 1.0.
- let cpuEfficiency = 0.0
- if (alloc.cpuReqCoreHrs > 0) {
- cpuEfficiency = alloc.cpuUseCoreHrs / alloc.cpuReqCoreHrs
- } else if (alloc.cpuUseCoreHrs > 0) {
- cpuEfficiency = 1.0
- }
- // RAM efficiency is defined as (usage/request). If request == 0.0 but
- // usage > 0, then efficiency gets set to 1.0.
- let ramEfficiency = 0.0
- if (alloc.ramReqByteHrs > 0) {
- ramEfficiency = alloc.ramUseByteHrs / alloc.ramReqByteHrs
- } else if (alloc.ramUseByteHrs > 0) {
- ramEfficiency = 1.0
- }
- // Compute efficiency as the cost-weighted average of CPU and RAM
- // efficiency
- if ((alloc.cpuCost + alloc.ramCost) > 0.0) {
- totalEfficiency = ((alloc.cpuCost*cpuEfficiency)+(alloc.ramCost*ramEfficiency)) / (alloc.cpuCost + alloc.ramCost)
- }
- result[name].cpuEfficiency = cpuEfficiency
- result[name].ramEfficiency = ramEfficiency
- result[name].totalEfficiency = totalEfficiency
- })
- }
- return result
- }
- // cumulativeToTotals adds each entry in the given AllocationSet (type: object)
- // and returns a single Allocation (type: object) representing the totals
- export function cumulativeToTotals(allocationSet) {
- let totals = {
- name: 'Totals',
- cpuCost: 0,
- gpuCost: 0,
- ramCost: 0,
- pvCost: 0,
- networkCost: 0,
- sharedCost: 0,
- externalCost: 0,
- totalCost: 0,
- cpuEfficiency: 0,
- ramEfficiency: 0,
- totalEfficiency: 0,
- }
- // Use these for computing efficiency. As such, idle will not factor into
- // these numbers, including CPU and RAM cost.
- let cpuReqCoreHrs = 0
- let cpuUseCoreHrs = 0
- let ramReqByteHrs = 0
- let ramUseByteHrs = 0
- let cpuCost = 0
- let ramCost = 0
- forEach(allocationSet, (alloc, name) => {
- // Accumulate efficiency-related fields
- if (name !== "__idle__") {
- cpuReqCoreHrs += get(alloc, 'cpuReqCoreHrs', 0.0)
- cpuUseCoreHrs += get(alloc, 'cpuUseCoreHrs', 0.0)
- ramReqByteHrs += get(alloc, 'ramReqByteHrs', 0.0)
- ramUseByteHrs += get(alloc, 'ramUseByteHrs', 0.0)
- cpuCost += get(alloc, 'cpuCost', 0.0)
- ramCost += get(alloc, 'ramCost', 0.0)
- }
- // Sum cumulative fields
- totals.cpuCost += get(alloc, 'cpuCost', 0)
- totals.gpuCost += get(alloc, 'gpuCost', 0)
- totals.ramCost += get(alloc, 'ramCost', 0)
- totals.pvCost += get(alloc, 'pvCost', 0)
- totals.networkCost += get(alloc, 'networkCost', 0)
- totals.sharedCost += get(alloc, 'sharedCost', 0)
- totals.externalCost += get(alloc, 'externalCost', 0)
- totals.totalCost += get(alloc, 'totalCost', 0)
- })
- // Compute efficiency
- if (cpuReqCoreHrs > 0) {
- totals.cpuEfficiency = cpuUseCoreHrs / cpuReqCoreHrs
- } else if (cpuUseCoreHrs > 0) {
- totals.cpuEfficiency = 1.0
- }
- if (ramReqByteHrs > 0) {
- totals.ramEfficiency = ramUseByteHrs / ramReqByteHrs
- } else if (ramUseByteHrs > 0) {
- totals.ramEfficiency = 1.0
- }
- if ((cpuCost + ramCost) > 0) {
- totals.totalEfficiency = ((cpuCost*totals.cpuEfficiency) + (ramCost*totals.ramEfficiency)) / (cpuCost + ramCost)
- }
- totals.cpuReqCoreHrs = cpuReqCoreHrs
- totals.cpuUseCoreHrs = cpuUseCoreHrs
- totals.ramReqByteHrs = ramReqByteHrs
- totals.ramUseByteHrs = ramUseByteHrs
- return totals
- }
- export function toVerboseTimeRange(window) {
- const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
- const start = new Date()
- start.setUTCHours(0, 0, 0, 0)
- const end = new Date()
- end.setUTCHours(0, 0, 0, 0)
- switch (window) {
- case 'today':
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
- case 'yesterday':
- start.setUTCDate(start.getUTCDate()-1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
- case 'week':
- start.setUTCDate(start.getUTCDate()-start.getUTCDay())
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} until now`
- case 'month':
- start.setUTCDate(1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} until now`
- case 'lastweek':
- start.setUTCDate(start.getUTCDate()-(start.getUTCDay()+7))
- end.setUTCDate(end.getUTCDate()-(end.getUTCDay()+1))
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
- case 'lastmonth':
- end.setUTCDate(1)
- end.setUTCDate(end.getUTCDate()-1)
- start.setUTCDate(1)
- start.setUTCDate(start.getUTCDate()-1)
- start.setUTCDate(1)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
- case '6d':
- start.setUTCDate(start.getUTCDate()-6)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
- case '29d':
- start.setUTCDate(start.getUTCDate()-29)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
- case '59d':
- start.setUTCDate(start.getUTCDate()-59)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
- case '89d':
- start.setUTCDate(start.getUTCDate()-89)
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through now`
- }
- const splitDates = window.split(",")
- if (checkCustomWindow(window) && splitDates.length > 1) {
- let s = splitDates[0].split(/\D+/).slice(0, 3)
- let e = splitDates[1].split(/\D+/).slice(0, 3)
- if (s.length === 3 && e.length === 3) {
- start.setUTCFullYear(s[0], s[1]-1, s[2])
- end.setUTCFullYear(e[0], e[1]-1, e[2])
- if (start === end) {
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()}`
- } else {
- return `${start.getUTCDate()} ${months[start.getUTCMonth()]} ${start.getUTCFullYear()} through ${end.getUTCDate()} ${months[end.getUTCMonth()]} ${end.getUTCFullYear()}`
- }
- }
- }
- return null
- }
- export function bytesToString(bytes) {
- const ei = Math.pow(1024, 6)
- if (bytes >= ei) {
- return `${round(bytes/ei, 1)} EiB`
- }
- const pi = Math.pow(1024, 5)
- if (bytes >= pi) {
- return `${round(bytes/pi, 1)} PiB`
- }
- const ti = Math.pow(1024, 4)
- if (bytes >= ti) {
- return `${round(bytes/ti, 1)} TiB`
- }
- const gi = Math.pow(1024, 3)
- if (bytes >= gi) {
- return `${round(bytes/gi, 1)} GiB`
- }
- const mi = Math.pow(1024, 2)
- if (bytes >= mi) {
- return `${round(bytes/mi, 1)} MiB`
- }
- const ki = Math.pow(1024, 1)
- if (bytes >= ki) {
- return `${round(bytes/ki, 1)} KiB`
- }
- return `${round(bytes, 1)} B`
- }
- const currencyLocale = "en-US"
- export function toCurrency(amount, currency, precision) {
- if (typeof amount !== "number") {
- console.warn(`Tried to convert "${amount}" to currency, but it is not a number`)
- return ""
- }
- if (currency === undefined || currency === "") {
- currency = "USD"
- }
- const opts = {
- style: "currency",
- currency: currency,
- }
- if (typeof precision === "number") {
- opts.minimumFractionDigits = precision
- opts.maximumFractionDigits = precision
- }
- return amount.toLocaleString(currencyLocale, opts);
- }
- export function checkCustomWindow(window) {
- // Example ISO interval string: 2020-12-02T00:00:00Z,2020-12-03T23:59:59Z
- const customDateRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/
- return customDateRegex.test(window)
- }
- export default {
- rangeToCumulative,
- cumulativeToTotals,
- toVerboseTimeRange,
- bytesToString,
- toCurrency,
- checkCustomWindow,
- }
|