Skip to content

Commit a58ca7b

Browse files
committed
extract cycleCount logic, test it, use default arg for yAxisTickFormatter
1 parent aa1eb9c commit a58ca7b

File tree

3 files changed

+59
-29
lines changed

3 files changed

+59
-29
lines changed

app/components/TimeSeriesChart.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export default function TimeSeriesChart({
130130
startTime,
131131
endTime,
132132
unit,
133-
yAxisTickFormatter,
133+
yAxisTickFormatter = (val) => val.toLocaleString(),
134134
}: TimeSeriesChartProps) {
135135
// We use the largest data point +20% for the graph scale. !rawData doesn't
136136
// mean it's empty (it will never be empty because we fill in artificial 0s at
@@ -184,7 +184,7 @@ export default function TimeSeriesChart({
184184
orientation="right"
185185
tick={textMonoMd}
186186
tickMargin={8}
187-
tickFormatter={yAxisTickFormatter || ((val: number) => val.toLocaleString())}
187+
tickFormatter={yAxisTickFormatter}
188188
padding={{ top: 32 }}
189189
{...yTicks}
190190
/>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright Oxide Computer Company
7+
*/
8+
import { expect, test } from 'vitest'
9+
10+
import { getCycleCount } from './MetricsTab'
11+
12+
test('getCycleCount', () => {
13+
expect(getCycleCount(5, 1000)).toEqual(0)
14+
expect(getCycleCount(1000, 1000)).toEqual(0)
15+
expect(getCycleCount(1001, 1000)).toEqual(1)
16+
expect(getCycleCount(10 ** 6, 1000)).toEqual(1)
17+
expect(getCycleCount(10 ** 6 + 1, 1000)).toEqual(2)
18+
expect(getCycleCount(10 ** 9, 1000)).toEqual(2)
19+
expect(getCycleCount(10 ** 9 + 1, 1000)).toEqual(3)
20+
21+
expect(getCycleCount(5, 1024)).toEqual(0)
22+
expect(getCycleCount(1024, 1024)).toEqual(0)
23+
expect(getCycleCount(1025, 1024)).toEqual(1)
24+
expect(getCycleCount(2 ** 20, 1024)).toEqual(1)
25+
expect(getCycleCount(2 ** 20 + 1, 1024)).toEqual(2)
26+
expect(getCycleCount(2 ** 30, 1024)).toEqual(2)
27+
expect(getCycleCount(2 ** 30 + 1, 1024)).toEqual(3)
28+
})

app/pages/project/instances/instance/tabs/MetricsTab.tsx

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ import { getInstanceSelector, useInstanceSelector } from 'app/hooks'
2222

2323
const TimeSeriesChart = React.lazy(() => import('app/components/TimeSeriesChart'))
2424

25+
export function getCycleCount(num: number, base: number) {
26+
let cycleCount = 0
27+
let transformedValue = num
28+
while (transformedValue > base) {
29+
transformedValue = transformedValue / base
30+
cycleCount++
31+
}
32+
return cycleCount
33+
}
34+
2535
type DiskMetricParams = {
2636
title: string
2737
unit: 'Bytes' | 'Count'
@@ -56,36 +66,28 @@ function DiskMetric({
5666

5767
const isBytesChart = unit === 'Bytes'
5868

59-
let unitForSet = ''
60-
let cycleCount = 0
61-
let label
62-
const divisorBase = isBytesChart ? 1024 : 1000
63-
if (metrics?.items?.length) {
64-
// Because we're using cumulative metrics, we can use the last (and therefore largest)
65-
// value in the set to determine the unit and the divisor for the set.
66-
const largestValue =
67-
(metrics?.items?.[metrics.items.length - 1].datum.datum as Cumulativeint64).value || 0
68-
69-
// We'll need to divide each number in the set by a consistent multiple of 1024 (for Bytes) or 1000 (for Counts)
70-
// Figure out what that multiple is:
71-
let transformedValue = largestValue
72-
while (transformedValue > divisorBase) {
73-
transformedValue = transformedValue / divisorBase
74-
cycleCount++
75-
}
69+
const largestValue = useMemo(() => {
70+
if (!metrics || metrics.items.length === 0) return 0
71+
return Math.max(...metrics.items.map((m) => (m.datum.datum as Cumulativeint64).value))
72+
}, [metrics])
7673

77-
// Now that we know how many cycles of "divide by 1024 || 1000" to run through
78-
// (via cylceCount), we can determine the proper unit for the set
79-
if (isBytesChart) {
80-
const byteUnits = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB']
81-
unitForSet = byteUnits[cycleCount]
82-
label = `(${unitForSet})`
83-
} else {
84-
label = '(COUNT)'
85-
}
74+
// We'll need to divide each number in the set by a consistent exponent
75+
// of 1024 (for Bytes) or 1000 (for Counts)
76+
const base = isBytesChart ? 1024 : 1000
77+
// Figure out what that exponent is:
78+
const cycleCount = getCycleCount(largestValue, base)
79+
80+
// Now that we know how many cycles of "divide by 1024 || 1000" to run through
81+
// (via cycleCount), we can determine the proper unit for the set
82+
let unitForSet = ''
83+
let label = '(COUNT)'
84+
if (isBytesChart) {
85+
const byteUnits = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB']
86+
unitForSet = byteUnits[cycleCount]
87+
label = `(${unitForSet})`
8688
}
8789

88-
const divisor = divisorBase ** cycleCount
90+
const divisor = base ** cycleCount
8991

9092
const data = useMemo(
9193
() =>

0 commit comments

Comments
 (0)