Skip to content

Commit

Permalink
feat: add measurement unit converter (#2772)
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanthccv authored Jun 6, 2023
1 parent edf7e98 commit 7086f7e
Show file tree
Hide file tree
Showing 12 changed files with 567 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,4 @@ clear-swarm-data:
test:
go test ./pkg/query-service/app/metrics/...
go test ./pkg/query-service/app/...
go test ./pkg/query-service/converter/...
16 changes: 16 additions & 0 deletions pkg/query-service/converter/bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package converter

// boolConverter is a Converter implementation for bool
type boolConverter struct{}

func NewBoolConverter() Converter {
return &boolConverter{}
}

func (c *boolConverter) Convert(v Value, to Unit) Value {
// There is no conversion to be done for bool
return Value{
F: v.F,
U: to,
}
}
53 changes: 53 additions & 0 deletions pkg/query-service/converter/converter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package converter

// Unit represents a unit of measurement
type Unit string

// Value represents a value with a unit of measurement
type Value struct {
F float64
U Unit
}

// Converter converts values from one unit to another
type Converter interface {
Convert(v Value, to Unit) Value
}

// noneConverter is a converter that does not convert
type noneConverter struct{}

func (c *noneConverter) Convert(v Value, to Unit) Value {
return v
}

// Converters
var (
DurationConverter = NewDurationConverter()
DataConverter = NewDataConverter()
DataRateConverter = NewDataRateConverter()
PercentConverter = NewPercentConverter()
BoolConverter = NewBoolConverter()
ThroughputConverter = NewThroughputConverter()
NoneConverter = &noneConverter{}
)

// FromUnit returns a converter for the given unit
func FromUnit(u Unit) Converter {
switch u {
case "ns", "us", "ms", "s", "m", "h", "d":
return DurationConverter
case "bytes", "decbytes", "bits", "decbits", "kbytes", "decKbytes", "mbytes", "decMbytes", "gbytes", "decGbytes", "tbytes", "decTbytes", "pbytes", "decPbytes":
return DataConverter
case "binBps", "Bps", "binbps", "bps", "KiBs", "Kibits", "KBs", "Kbits", "MiBs", "Mibits", "MBs", "Mbits", "GiBs", "Gibits", "GBs", "Gbits", "TiBs", "Tibits", "TBs", "Tbits", "PiBs", "Pibits", "PBs", "Pbits":
return DataRateConverter
case "percent", "percentunit":
return PercentConverter
case "bool", "bool_yes_no", "bool_true_false", "bool_1_0":
return BoolConverter
case "cps", "ops", "reqps", "rps", "wps", "iops", "cpm", "opm", "rpm", "wpm":
return ThroughputConverter
default:
return NoneConverter
}
}
97 changes: 97 additions & 0 deletions pkg/query-service/converter/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package converter

const (
// base 10 (SI prefixes)
Bit float64 = 1e0
Kilobit = Bit * 1e3
Megabit = Bit * 1e6
Gigabit = Bit * 1e9
Terabit = Bit * 1e12
Petabit = Bit * 1e15
Exabit = Bit * 1e18
Zettabit = Bit * 1e21
Yottabit = Bit * 1e24
Ronnabit = Bit * 1e27
Quettabit = Bit * 1e30

Byte = Bit * 8
Kilobyte = Byte * 1e3
Megabyte = Byte * 1e6
Gigabyte = Byte * 1e9
Terabyte = Byte * 1e12
Petabyte = Byte * 1e15
Exabyte = Byte * 1e18
Zettabyte = Byte * 1e21
Yottabyte = Byte * 1e24
Ronnabyte = Byte * 1e27
Quettabyte = Byte * 1e30

// base 2 (IEC prefixes)
Kibibit = Bit * 1024
Mebibit = Kibibit * 1024
Gibibit = Mebibit * 1024
Tebibit = Gibibit * 1024
Pebibit = Tebibit * 1024
Exbibit = Pebibit * 1024
Zebibit = Exbibit * 1024
Yobibit = Zebibit * 1024

Kibibyte = Byte * 1024
Mebibyte = Kibibyte * 1024
Gibibyte = Mebibyte * 1024
Tebibyte = Gibibyte * 1024
Pebibyte = Tebibyte * 1024
Exbibyte = Pebibyte * 1024
Zebibyte = Exbibyte * 1024
Yobibyte = Zebibyte * 1024
)

// dataConverter is a Converter for data units.
type dataConverter struct {
}

func NewDataConverter() Converter {
return &dataConverter{}
}

func FromDataUnit(u Unit) float64 {
switch u {
case "bytes": // base 2
return Byte
case "decbytes": // base 10
return Byte
case "bits": // base 2
return Bit
case "decbits": // base 10
return Bit
case "kbytes": // base 2
return Kibibyte
case "deckbytes": // base 10
return Kilobyte
case "mbytes": // base 2
return Mebibyte
case "decmbytes": // base 10
return Megabyte
case "gbytes": // base 2
return Gibibyte
case "decgbytes": // base 10
return Gigabyte
case "tbytes": // base 2
return Tebibyte
case "dectbytes": // base 10
return Terabyte
case "pbytes": // base 2
return Pebibyte
case "decpbytes": // base 10
return Petabyte
default:
return 1
}
}

func (c *dataConverter) Convert(v Value, to Unit) Value {
return Value{
F: v.F * FromDataUnit(v.U) / FromDataUnit(to),
U: to,
}
}
114 changes: 114 additions & 0 deletions pkg/query-service/converter/data_rate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package converter

const (
// base 10 (SI prefixes)
BitPerSecond float64 = 1e0
KilobitPerSecond = BitPerSecond * 1e3
MegabitPerSecond = BitPerSecond * 1e6
GigabitPerSecond = BitPerSecond * 1e9
TerabitPerSecond = BitPerSecond * 1e12
PetabitPerSecond = BitPerSecond * 1e15
ExabitPerSecond = BitPerSecond * 1e18
ZettabitPerSecond = BitPerSecond * 1e21
YottabitPerSecond = BitPerSecond * 1e24

BytePerSecond = BitPerSecond * 8
KilobytePerSecond = BytePerSecond * 1e3
MegabytePerSecond = BytePerSecond * 1e6
GigabytePerSecond = BytePerSecond * 1e9
TerabytePerSecond = BytePerSecond * 1e12
PetabytePerSecond = BytePerSecond * 1e15
ExabytePerSecond = BytePerSecond * 1e18
ZettabytePerSecond = BytePerSecond * 1e21
YottabytePerSecond = BytePerSecond * 1e24

// base 2 (IEC prefixes)
KibibitPerSecond = BitPerSecond * 1024
MebibitPerSecond = KibibitPerSecond * 1024
GibibitPerSecond = MebibitPerSecond * 1024
TebibitPerSecond = GibibitPerSecond * 1024
PebibitPerSecond = TebibitPerSecond * 1024
ExbibitPerSecond = PebibitPerSecond * 1024
ZebibitPerSecond = ExbibitPerSecond * 1024
YobibitPerSecond = ZebibitPerSecond * 1024

KibibytePerSecond = BytePerSecond * 1024
MebibytePerSecond = KibibytePerSecond * 1024
GibibytePerSecond = MebibytePerSecond * 1024
TebibytePerSecond = GibibytePerSecond * 1024
PebibytePerSecond = TebibytePerSecond * 1024
ExbibytePerSecond = PebibytePerSecond * 1024
ZebibytePerSecond = ExbibytePerSecond * 1024
YobibytePerSecond = ZebibytePerSecond * 1024
)

// dataRateConverter is a Converter implementation for data rates
type dataRateConverter struct {
}

func NewDataRateConverter() Converter {
return &dataRateConverter{}
}

func FromDataRateUnit(u Unit) float64 {
// See https://github.com/SigNoz/signoz/blob/5a81f5f90b34845f5b4b3bdd46acf29d04bf3987/frontend/src/container/NewWidget/RightContainer/dataFormatCategories.ts#L62-L85
switch u {
case "binBps": // bytes/sec(IEC)
return BytePerSecond
case "Bps": // bytes/sec(SI)
return BytePerSecond
case "binbps": // bits/sec(IEC)
return BitPerSecond
case "bps": // bits/sec(SI)
return BitPerSecond
case "KiBs": // kibibytes/sec
return KibibytePerSecond
case "Kibits": // kibibits/sec
return KibibitPerSecond
case "KBs": // kilobytes/sec
return KilobytePerSecond
case "Kbits": // kilobits/sec
return KilobitPerSecond
case "MiBs": // mebibytes/sec
return MebibytePerSecond
case "Mibits": // mebibits/sec
return MebibitPerSecond
case "MBs": // megabytes/sec
return MegabytePerSecond
case "Mbits": // megabits/sec
return MegabitPerSecond
case "GiBs": // gibibytes/sec
return GibibytePerSecond
case "Gibits": // gibibits/sec
return GibibitPerSecond
case "GBs": // gigabytes/sec
return GigabytePerSecond
case "Gbits": // gigabits/sec
return GigabitPerSecond
case "TiBs": // tebibytes/sec
return TebibytePerSecond
case "Tibits": // tebibits/sec
return TebibitPerSecond
case "TBs": // terabytes/sec
return TerabytePerSecond
case "Tbits": // terabits/sec
return TerabitPerSecond
case "PiBs": // pebibytes/sec
return PebibytePerSecond
case "Pibits": // pebibits/sec
return PebibitPerSecond
case "PBs": // petabytes/sec
return PetabytePerSecond
case "Pbits": // petabits/sec
return PetabitPerSecond
default:
return 1
}
}

func (c *dataRateConverter) Convert(v Value, to Unit) Value {
return Value{
F: v.F * FromDataRateUnit(v.U) / FromDataRateUnit(to),
U: to,
}
}
67 changes: 67 additions & 0 deletions pkg/query-service/converter/data_rate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package converter

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestDataRate(t *testing.T) {
dataRateConverter := NewDataRateConverter()
// names and ids for data rate units
// { name: 'bytes/sec(IEC)', id: 'binBps' },
// { name: 'bytes/sec(SI)', id: 'Bps' },
// { name: 'bits/sec(IEC)', id: 'binbps' },
// { name: 'bits/sec(SI)', id: 'bps' },
// { name: 'kibibytes/sec', id: 'KiBs' },
// { name: 'kibibits/sec', id: 'Kibits' },
// { name: 'kilobytes/sec', id: 'KBs' },
// { name: 'kilobits/sec', id: 'Kbits' },
// { name: 'mebibytes/sec', id: 'MiBs' },
// { name: 'mebibits/sec', id: 'Mibits' },
// { name: 'megabytes/sec', id: 'MBs' },
// { name: 'megabits/sec', id: 'Mbits' },
// { name: 'gibibytes/sec', id: 'GiBs' },
// { name: 'gibibits/sec', id: 'Gibits' },
// { name: 'gigabytes/sec', id: 'GBs' },
// { name: 'gigabits/sec', id: 'Gbits' },
// { name: 'tebibytes/sec', id: 'TiBs' },
// { name: 'tebibits/sec', id: 'Tibits' },
// { name: 'terabytes/sec', id: 'TBs' },
// { name: 'terabits/sec', id: 'Tbits' },
// { name: 'pebibytes/sec', id: 'PiBs' },
// { name: 'pebibits/sec', id: 'Pibits' },
// { name: 'petabytes/sec', id: 'PBs' },
// { name: 'petabits/sec', id: 'Pbits' },

// 8 bits = 1 byte
assert.Equal(t, Value{F: 1, U: "binBps"}, dataRateConverter.Convert(Value{F: 8, U: "binbps"}, "binBps"))
// 1024 bytes = 1 kbytes
assert.Equal(t, Value{F: 1, U: "KiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "binBps"}, "KiBs"))
// 1 byte = 8 bits
assert.Equal(t, Value{F: 8, U: "binbps"}, dataRateConverter.Convert(Value{F: 1, U: "binBps"}, "binbps"))
// 1 mbytes = 1024 kbytes
assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "KiBs"}, "MiBs"))
// 1 kbytes = 1024 bytes
assert.Equal(t, Value{F: 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "KiBs"}, "binBps"))
// 1024 kbytes = 1 mbytes
assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "KiBs"}, "MiBs"))
// 1 mbytes = 1024 * 1024 bytes
assert.Equal(t, Value{F: 1024 * 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "MiBs"}, "binBps"))
// 1024 mbytes = 1 gbytes
assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "MiBs"}, "GiBs"))
// 2048 mbytes = 2 gbytes
assert.Equal(t, Value{F: 2, U: "GiBs"}, dataRateConverter.Convert(Value{F: 2048, U: "MiBs"}, "GiBs"))
// 1 gbytes = 1024 mbytes
assert.Equal(t, Value{F: 1024, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "MiBs"))
// 1 gbytes = 1024 * 1024 kbytes
assert.Equal(t, Value{F: 1024 * 1024, U: "KiBs"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "KiBs"))
// 1 gbytes = 1024 * 1024 * 1024 bytes
assert.Equal(t, Value{F: 1024 * 1024 * 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "binBps"))
// 1024 * 1024 bytes = 1 mbytes
assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024, U: "binBps"}, "MiBs"))
// 1024 * 1024 kbytes = 1 gbytes
assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024, U: "KiBs"}, "GiBs"))
// 1024 * 1024 * 1024 bytes = 1 gbytes
assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024 * 1024, U: "binBps"}, "GiBs"))
}
Loading

0 comments on commit 7086f7e

Please sign in to comment.