From bc1d51de9ba2626864ee7e912e55c651a72371b2 Mon Sep 17 00:00:00 2001 From: Nathan ter Bogt Date: Thu, 26 Mar 2026 16:56:23 +1300 Subject: [PATCH 1/4] Converting the API to use floats --- internal/server/mock/metrics/server.go | 12 ++++++------ metrics.proto | 2 +- pb/metrics.pb.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/server/mock/metrics/server.go b/internal/server/mock/metrics/server.go index 4f8dd0e..c0d0db8 100644 --- a/internal/server/mock/metrics/server.go +++ b/internal/server/mock/metrics/server.go @@ -19,19 +19,19 @@ type Server struct { pb.UnimplementedMetricsServer } -func deterministicRange(t time.Time, minVal, maxVal, seconds int64, key string) int64 { +func deterministicRange(t time.Time, minVal, maxVal float32, seconds int64, key string) float32 { h := fnv.New32a() bucketKey := fmt.Sprintf("%d-%s", t.Unix()/seconds, key) _, _ = h.Write([]byte(bucketKey)) - hashVal := int64(h.Sum32()) + hashVal := float32(h.Sum32()) / float32(^uint32(0)) - rangeSize := maxVal - minVal + 1 - return minVal + (hashVal % rangeSize) + rangeSize := maxVal - minVal + return minVal + (hashVal * rangeSize) } -func metricMappings(metricType pb.MetricType) map[string][]int64 { - data := map[pb.MetricType]map[string][]int64{ +func metricMappings(metricType pb.MetricType) map[string][]float32 { + data := map[pb.MetricType]map[string][]float32{ pb.MetricType_CLUSTER: { "requests": {250_000, 4_000_000}, "httpcode_target_200": {500, 1_000}, diff --git a/metrics.proto b/metrics.proto index 1176026..4690bd4 100644 --- a/metrics.proto +++ b/metrics.proto @@ -68,5 +68,5 @@ message AbsoluteRangeResponse { */ message MetricValue { google.protobuf.Timestamp timestamp = 1; // The timestamp of the metric.. - int64 value = 2; // The value of the metric at the given timestamp. + float value = 2; // The value of the metric at the given timestamp. } diff --git a/pb/metrics.pb.go b/pb/metrics.pb.go index 71c3cd3..77ccdad 100644 --- a/pb/metrics.pb.go +++ b/pb/metrics.pb.go @@ -377,7 +377,7 @@ type MetricValue struct { unknownFields protoimpl.UnknownFields Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // The timestamp of the metric.. - Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // The value of the metric at the given timestamp. + Value float32 `protobuf:"fixed32,2,opt,name=value,proto3" json:"value,omitempty"` // The value of the metric at the given timestamp. } func (x *MetricValue) Reset() { @@ -419,7 +419,7 @@ func (x *MetricValue) GetTimestamp() *timestamppb.Timestamp { return nil } -func (x *MetricValue) GetValue() int64 { +func (x *MetricValue) GetValue() float32 { if x != nil { return x.Value } @@ -476,7 +476,7 @@ var file_metrics_proto_rawDesc = []byte{ 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x54, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, From 10606c9ebd10712fefd3bf53890cd4ce0cc6857c Mon Sep 17 00:00:00 2001 From: Nathan ter Bogt Date: Thu, 26 Mar 2026 17:31:44 +1300 Subject: [PATCH 2/4] Convert to 64 bit floats --- internal/server/mock/metrics/server.go | 8 ++++---- metrics.proto | 2 +- pb/metrics.pb.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/server/mock/metrics/server.go b/internal/server/mock/metrics/server.go index c0d0db8..ba8021c 100644 --- a/internal/server/mock/metrics/server.go +++ b/internal/server/mock/metrics/server.go @@ -19,19 +19,19 @@ type Server struct { pb.UnimplementedMetricsServer } -func deterministicRange(t time.Time, minVal, maxVal float32, seconds int64, key string) float32 { +func deterministicRange(t time.Time, minVal, maxVal float64, seconds int64, key string) float64 { h := fnv.New32a() bucketKey := fmt.Sprintf("%d-%s", t.Unix()/seconds, key) _, _ = h.Write([]byte(bucketKey)) - hashVal := float32(h.Sum32()) / float32(^uint32(0)) + hashVal := float64(h.Sum32()) / float64(^uint64(0)) rangeSize := maxVal - minVal return minVal + (hashVal * rangeSize) } -func metricMappings(metricType pb.MetricType) map[string][]float32 { - data := map[pb.MetricType]map[string][]float32{ +func metricMappings(metricType pb.MetricType) map[string][]float64 { + data := map[pb.MetricType]map[string][]float64{ pb.MetricType_CLUSTER: { "requests": {250_000, 4_000_000}, "httpcode_target_200": {500, 1_000}, diff --git a/metrics.proto b/metrics.proto index 4690bd4..aa674ba 100644 --- a/metrics.proto +++ b/metrics.proto @@ -68,5 +68,5 @@ message AbsoluteRangeResponse { */ message MetricValue { google.protobuf.Timestamp timestamp = 1; // The timestamp of the metric.. - float value = 2; // The value of the metric at the given timestamp. + double value = 2; // The value of the metric at the given timestamp. } diff --git a/pb/metrics.pb.go b/pb/metrics.pb.go index 77ccdad..648524e 100644 --- a/pb/metrics.pb.go +++ b/pb/metrics.pb.go @@ -377,7 +377,7 @@ type MetricValue struct { unknownFields protoimpl.UnknownFields Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // The timestamp of the metric.. - Value float32 `protobuf:"fixed32,2,opt,name=value,proto3" json:"value,omitempty"` // The value of the metric at the given timestamp. + Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` // The value of the metric at the given timestamp. } func (x *MetricValue) Reset() { @@ -419,7 +419,7 @@ func (x *MetricValue) GetTimestamp() *timestamppb.Timestamp { return nil } -func (x *MetricValue) GetValue() float32 { +func (x *MetricValue) GetValue() float64 { if x != nil { return x.Value } @@ -476,7 +476,7 @@ var file_metrics_proto_rawDesc = []byte{ 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x54, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, From 4c8efb6a7cadb88248065b79b60d160094e8ee86 Mon Sep 17 00:00:00 2001 From: Nathan ter Bogt Date: Thu, 26 Mar 2026 20:46:41 +1300 Subject: [PATCH 3/4] Fixing the deterministic function --- internal/server/mock/metrics/server.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/server/mock/metrics/server.go b/internal/server/mock/metrics/server.go index ba8021c..d9710b7 100644 --- a/internal/server/mock/metrics/server.go +++ b/internal/server/mock/metrics/server.go @@ -19,12 +19,13 @@ type Server struct { pb.UnimplementedMetricsServer } +// deterministicRange returns a specific value consistently for a point in a time series. func deterministicRange(t time.Time, minVal, maxVal float64, seconds int64, key string) float64 { h := fnv.New32a() bucketKey := fmt.Sprintf("%d-%s", t.Unix()/seconds, key) _, _ = h.Write([]byte(bucketKey)) - hashVal := float64(h.Sum32()) / float64(^uint64(0)) + hashVal := float64(h.Sum32()) / float64(^uint32(0)) rangeSize := maxVal - minVal return minVal + (hashVal * rangeSize) From b4d5d508b5cf5f3a0ea74768459026132e17f367 Mon Sep 17 00:00:00 2001 From: Nathan ter Bogt Date: Fri, 27 Mar 2026 14:40:36 +1300 Subject: [PATCH 4/4] Mock without a multiplier --- internal/server/mock/metrics/server.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/server/mock/metrics/server.go b/internal/server/mock/metrics/server.go index d9710b7..49981d2 100644 --- a/internal/server/mock/metrics/server.go +++ b/internal/server/mock/metrics/server.go @@ -43,7 +43,7 @@ func metricMappings(metricType pb.MetricType) map[string][]float64 { pb.MetricType_ENVIRONMENT: { "requests": {25_000, 200_000}, "cpu": {25, 100}, - "memory": {512, 4096}, + "memory": {512_000, 4_294_967_296}, // 512KB to 4GB "replicas": {2, 8}, "php_active": {4, 48}, "php_idle": {2, 12}, @@ -56,9 +56,9 @@ func metricMappings(metricType pb.MetricType) map[string][]float64 { "httpcode_target_300": {25, 50}, "httpcode_target_400": {10, 25}, "httpcode_target_500": {0, 10}, - "response_times_avg": {100, 250}, - "response_times_p95": {2_000, 5_000}, - "response_times_p99": {10_000, 20_000}, + "response_times_avg": {0.1, 0.25}, + "response_times_p95": {2.0, 5.0}, + "response_times_p99": {10.0, 20.0}, }, } return data[metricType]