diff --git a/src/promql/src/aggregate.rs b/src/promql/src/aggregate.rs index 115c5ac4030..d164cf3bac5 100644 --- a/src/promql/src/aggregate.rs +++ b/src/promql/src/aggregate.rs @@ -28,6 +28,7 @@ use datafusion::error::{DataFusionError, Result}; use datatypes::series::MetricName; use datatypes::series::samples::{SampleRef, Series, SeriesSchema}; +use crate::go_format::format_float_f; use crate::grid_series::{GridSeriesBuilder, external}; use crate::map::{drop_empty_labels, validate_float_series, validate_scalar}; use crate::range_eval::quantile; @@ -316,7 +317,7 @@ pub fn count_values( Entry::Vacant(entry) => { let mut metric = series.metric.clone(); metric - .set(label, Arc::from(format_value(value))) + .set(label, Arc::from(format_float_f(value))) .map_err(external)?; let metric = grouping.apply(&metric)?; let index = *group_index.entry(label_key(&metric)).or_insert_with(|| { @@ -348,57 +349,6 @@ pub fn count_values( Ok(output) } -/// Go's `strconv.FormatFloat(value, 'f', -1, 64)`: the fewest significant digits that round-trip, -/// in positional notation. When two candidates of that length are equally close, Go takes the -/// even one while Rust's shortest formatting rounds up, so the digits are recomputed with Rust's -/// exact formatting, which rounds half to even. The recomputed digits only count when they still -/// parse back to `value`: just above a power of two the lower neighbour is half as far away, so -/// the even candidate can name that neighbour, and only the other one round-trips. -fn format_value(value: f64) -> String { - match value { - f64::INFINITY => return "+Inf".to_string(), - f64::NEG_INFINITY => return "-Inf".to_string(), - _ if value.is_nan() => return "NaN".to_string(), - _ => {} - } - let shortest = format!("{value:e}"); - let mantissa = shortest.split_once('e').expect("exponent format").0; - let significant = mantissa.chars().filter(char::is_ascii_digit).count(); - let exact = format!("{value:.precision$e}", precision = significant - 1); - let digits = if exact.parse::() == Ok(value) { - &exact - } else { - &shortest - }; - let (mantissa, exponent) = digits.split_once('e').expect("exponent format"); - let exponent: i64 = exponent.parse().expect("integer exponent"); - let (sign, mantissa) = match mantissa.strip_prefix('-') { - Some(unsigned) => ("-", unsigned), - None => ("", mantissa), - }; - let digits: String = mantissa.chars().filter(char::is_ascii_digit).collect(); - // The decimal point goes after `exponent + 1` digits. - let point = exponent + 1; - let mut out = String::from(sign); - if point <= 0 { - out.push_str("0."); - out.extend(std::iter::repeat_n('0', (-point) as usize)); - out.push_str(digits.trim_end_matches('0')); - } else if point as usize >= digits.len() { - out.push_str(&digits); - out.extend(std::iter::repeat_n('0', point as usize - digits.len())); - } else { - let (whole, fraction) = digits.split_at(point as usize); - out.push_str(whole); - let fraction = fraction.trim_end_matches('0'); - if !fraction.is_empty() { - out.push('.'); - out.push_str(fraction); - } - } - out -} - /// Schema validation is repeated because Series exposes its fields publicly. fn validate_input(schema: &SeriesSchema, input: &[Series], grouping: Grouping<'_>) -> Result<()> { if schema.eval_grid.is_none() { diff --git a/src/promql/src/aggregate/tests.rs b/src/promql/src/aggregate/tests.rs index 6b20c4c6bf8..9d71cb0ca48 100644 --- a/src/promql/src/aggregate/tests.rs +++ b/src/promql/src/aggregate/tests.rs @@ -907,7 +907,7 @@ fn value_labels_format_like_go() { for line in include_str!("format_float_cases.txt").lines() { let (bits, expected) = line.split_once(' ').unwrap(); let value = f64::from_bits(u64::from_str_radix(bits, 16).unwrap()); - assert_eq!(format_value(value), expected, "{bits}"); + assert_eq!(crate::go_format::format_float_f(value), expected, "{bits}"); checked += 1; } assert!(checked > 2_400, "{checked}"); @@ -916,7 +916,7 @@ fn value_labels_format_like_go() { (f64::INFINITY, "+Inf"), (f64::NEG_INFINITY, "-Inf"), ] { - assert_eq!(format_value(value), expected); + assert_eq!(crate::go_format::format_float_f(value), expected); } } diff --git a/src/promql/src/go_format.rs b/src/promql/src/go_format.rs new file mode 100644 index 00000000000..bf19922df25 --- /dev/null +++ b/src/promql/src/go_format.rs @@ -0,0 +1,129 @@ +// Copyright 2023 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The shortest float formats of Go's `strconv`, which Prometheus writes label values in. + +#[cfg(test)] +mod tests; + +/// Go's `strconv.FormatFloat(value, 'f', -1, 64)`, the form of `count_values` labels. +pub(crate) fn format_float_f(value: f64) -> String { + match special(value) { + Some(text) => text.to_string(), + None => { + let (negative, digits, point) = shortest(value); + positional(negative, &digits, point) + } + } +} + +/// Prometheus `labels.FormatOpenMetricsFloat`, the form of `histogram_quantiles` labels: Go's +/// shortest `'g'` format, with `.0` appended to an integer and `0`, `1` and `-1` written as +/// `0.0`, `1.0` and `-1.0`. +pub(crate) fn format_open_metrics_float(value: f64) -> String { + if value == 1.0 { + return "1.0".to_string(); + } + if value == 0.0 { + return "0.0".to_string(); + } + if value == -1.0 { + return "-1.0".to_string(); + } + if let Some(text) = special(value) { + return text.to_string(); + } + let (negative, digits, point) = shortest(value); + // The shortest `'g'` format switches to an exponent below 1e-4 and from 1e6 on. + let exponent = point - 1; + let mut text = if !(-4..6).contains(&exponent) { + let mut text = String::from(if negative { "-" } else { "" }); + text.push_str(&digits[..1]); + if digits.len() > 1 { + text.push('.'); + text.push_str(&digits[1..]); + } + text.push_str(&format!( + "e{}{:02}", + if exponent < 0 { '-' } else { '+' }, + exponent.abs() + )); + text + } else { + positional(negative, &digits, point) + }; + if !text.contains(['e', '.']) { + text.push_str(".0"); + } + text +} + +fn special(value: f64) -> Option<&'static str> { + match value { + f64::INFINITY => Some("+Inf"), + f64::NEG_INFINITY => Some("-Inf"), + _ if value.is_nan() => Some("NaN"), + _ => None, + } +} + +/// The fewest significant digits of a finite `value` that round-trip, without trailing zeros, and +/// the position of the decimal point among them: `value = ±0.digits × 10^point`. Zero is `"0"` at +/// point 1. +/// +/// When two candidates of that length are equally close, Go takes the even one while Rust's +/// shortest formatting rounds up, so the digits are recomputed with Rust's exact formatting, +/// which rounds half to even. The recomputed digits only count when they still parse back to +/// `value`: just above a power of two the lower neighbour is half as far away, so the even +/// candidate can name that neighbour, and only the other one round-trips. +fn shortest(value: f64) -> (bool, String, i64) { + let shortest = format!("{value:e}"); + let mantissa = shortest.split_once('e').expect("exponent format").0; + let significant = mantissa.chars().filter(char::is_ascii_digit).count(); + let exact = format!("{value:.precision$e}", precision = significant - 1); + let chosen = if exact.parse::() == Ok(value) { + &exact + } else { + &shortest + }; + let (mantissa, exponent) = chosen.split_once('e').expect("exponent format"); + let exponent: i64 = exponent.parse().expect("integer exponent"); + let (negative, mantissa) = match mantissa.strip_prefix('-') { + Some(unsigned) => (true, unsigned), + None => (false, mantissa), + }; + let digits: String = mantissa.chars().filter(char::is_ascii_digit).collect(); + let trimmed = digits.trim_end_matches('0'); + let digits = if trimmed.is_empty() { "0" } else { trimmed }; + (negative, digits.to_string(), exponent + 1) +} + +/// `±0.digits × 10^point` in positional notation without trailing fractional zeros. +fn positional(negative: bool, digits: &str, point: i64) -> String { + let mut out = String::from(if negative { "-" } else { "" }); + if point <= 0 { + out.push_str("0."); + out.extend(std::iter::repeat_n('0', (-point) as usize)); + out.push_str(digits); + } else if point as usize >= digits.len() { + out.push_str(digits); + out.extend(std::iter::repeat_n('0', point as usize - digits.len())); + } else { + let (whole, fraction) = digits.split_at(point as usize); + out.push_str(whole); + out.push('.'); + out.push_str(fraction); + } + out +} diff --git a/src/promql/src/go_format/open_metrics_cases.txt b/src/promql/src/go_format/open_metrics_cases.txt new file mode 100644 index 00000000000..38bb7526cfe --- /dev/null +++ b/src/promql/src/go_format/open_metrics_cases.txt @@ -0,0 +1,358 @@ +0 0.0 +8000000000000000 0.0 +3ff0000000000000 1.0 +bff0000000000000 -1.0 +3fe0000000000000 0.5 +3feccccccccccccd 0.9 +3fefae147ae147ae 0.99 +3feff7ced916872b 0.999 +3f1a36e2eb1c432d 0.0001 +3ee4f8b588e368f1 1e-05 +3f201f31f46ed246 0.000123 +40f869f000000000 99999.0 +40f86a0000000000 100000.0 +412e847e00000000 999999.0 +412e848000000000 1e+06 +4132d68700000000 1.234567e+06 +444b1ae4d6e2ef50 1e+21 +3e7ad7f29abcaf48 1e-07 +4000000000000000 2.0 +c004000000000000 -2.5 +1 5e-324 +7fefffffffffffff 1.7976931348623157e+308 +7ff8000000000001 NaN +7ff0000000000000 +Inf +fff0000000000000 -Inf +3e0fffffffffffff 9.313225746154784e-10 +3e10000000000000 9.313225746154785e-10 +3e10000000000001 9.313225746154787e-10 +3e1fffffffffffff 1.8626451492309568e-09 +3e20000000000000 1.862645149230957e-09 +3e20000000000001 1.8626451492309574e-09 +3e2fffffffffffff 3.7252902984619136e-09 +3e30000000000000 3.725290298461914e-09 +3e30000000000001 3.725290298461915e-09 +3e3fffffffffffff 7.450580596923827e-09 +3e40000000000000 7.450580596923828e-09 +3e40000000000001 7.45058059692383e-09 +3e4fffffffffffff 1.4901161193847655e-08 +3e50000000000000 1.4901161193847656e-08 +3e50000000000001 1.490116119384766e-08 +3e5fffffffffffff 2.980232238769531e-08 +3e60000000000000 2.9802322387695312e-08 +3e60000000000001 2.980232238769532e-08 +3e6fffffffffffff 5.960464477539062e-08 +3e70000000000000 5.960464477539063e-08 +3e70000000000001 5.960464477539064e-08 +3e7fffffffffffff 1.1920928955078124e-07 +3e80000000000000 1.1920928955078125e-07 +3e80000000000001 1.1920928955078128e-07 +3e8fffffffffffff 2.3841857910156247e-07 +3e90000000000000 2.384185791015625e-07 +3e90000000000001 2.3841857910156255e-07 +3e9fffffffffffff 4.7683715820312495e-07 +3ea0000000000000 4.76837158203125e-07 +3ea0000000000001 4.768371582031251e-07 +3eafffffffffffff 9.536743164062499e-07 +3eb0000000000000 9.5367431640625e-07 +3eb0000000000001 9.536743164062502e-07 +3ebfffffffffffff 1.9073486328124998e-06 +3ec0000000000000 1.9073486328125e-06 +3ec0000000000001 1.9073486328125004e-06 +3ecfffffffffffff 3.8146972656249996e-06 +3ed0000000000000 3.814697265625e-06 +3ed0000000000001 3.814697265625001e-06 +3edfffffffffffff 7.629394531249999e-06 +3ee0000000000000 7.62939453125e-06 +3ee0000000000001 7.629394531250002e-06 +3eefffffffffffff 1.5258789062499998e-05 +3ef0000000000000 1.52587890625e-05 +3ef0000000000001 1.5258789062500003e-05 +3effffffffffffff 3.0517578124999997e-05 +3f00000000000000 3.0517578125e-05 +3f00000000000001 3.051757812500001e-05 +3f0fffffffffffff 6.103515624999999e-05 +3f10000000000000 6.103515625e-05 +3f10000000000001 6.103515625000001e-05 +3f1fffffffffffff 0.00012207031249999999 +3f20000000000000 0.0001220703125 +3f20000000000001 0.00012207031250000003 +3f2fffffffffffff 0.00024414062499999997 +3f30000000000000 0.000244140625 +3f30000000000001 0.00024414062500000005 +3f3fffffffffffff 0.00048828124999999995 +3f40000000000000 0.00048828125 +3f40000000000001 0.0004882812500000001 +3f4fffffffffffff 0.0009765624999999999 +3f50000000000000 0.0009765625 +3f50000000000001 0.0009765625000000002 +3f5fffffffffffff 0.0019531249999999998 +3f60000000000000 0.001953125 +3f60000000000001 0.0019531250000000004 +3f6fffffffffffff 0.0039062499999999996 +3f70000000000000 0.00390625 +3f70000000000001 0.003906250000000001 +3f7fffffffffffff 0.007812499999999999 +3f80000000000000 0.0078125 +3f80000000000001 0.007812500000000002 +3f8fffffffffffff 0.015624999999999998 +3f90000000000000 0.015625 +3f90000000000001 0.015625000000000003 +3f9fffffffffffff 0.031249999999999997 +3fa0000000000000 0.03125 +3fa0000000000001 0.03125000000000001 +3fafffffffffffff 0.06249999999999999 +3fb0000000000000 0.0625 +3fb0000000000001 0.06250000000000001 +3fbfffffffffffff 0.12499999999999999 +3fc0000000000000 0.125 +3fc0000000000001 0.12500000000000003 +3fcfffffffffffff 0.24999999999999997 +3fd0000000000000 0.25 +3fd0000000000001 0.25000000000000006 +3fdfffffffffffff 0.49999999999999994 +3fe0000000000000 0.5 +3fe0000000000001 0.5000000000000001 +3fefffffffffffff 0.9999999999999999 +3ff0000000000000 1.0 +3ff0000000000001 1.0000000000000002 +3fffffffffffffff 1.9999999999999998 +4000000000000000 2.0 +4000000000000001 2.0000000000000004 +400fffffffffffff 3.9999999999999996 +4010000000000000 4.0 +4010000000000001 4.000000000000001 +401fffffffffffff 7.999999999999999 +4020000000000000 8.0 +4020000000000001 8.000000000000002 +402fffffffffffff 15.999999999999998 +4030000000000000 16.0 +4030000000000001 16.000000000000004 +403fffffffffffff 31.999999999999996 +4040000000000000 32.0 +4040000000000001 32.00000000000001 +404fffffffffffff 63.99999999999999 +4050000000000000 64.0 +4050000000000001 64.00000000000001 +405fffffffffffff 127.99999999999999 +4060000000000000 128.0 +4060000000000001 128.00000000000003 +406fffffffffffff 255.99999999999997 +4070000000000000 256.0 +4070000000000001 256.00000000000006 +407fffffffffffff 511.99999999999994 +4080000000000000 512.0 +4080000000000001 512.0000000000001 +408fffffffffffff 1023.9999999999999 +4090000000000000 1024.0 +4090000000000001 1024.0000000000002 +409fffffffffffff 2047.9999999999998 +40a0000000000000 2048.0 +40a0000000000001 2048.0000000000005 +40afffffffffffff 4095.9999999999995 +40b0000000000000 4096.0 +40b0000000000001 4096.000000000001 +40bfffffffffffff 8191.999999999999 +40c0000000000000 8192.0 +40c0000000000001 8192.000000000002 +40cfffffffffffff 16383.999999999998 +40d0000000000000 16384.0 +40d0000000000001 16384.000000000004 +40dfffffffffffff 32767.999999999996 +40e0000000000000 32768.0 +40e0000000000001 32768.00000000001 +40efffffffffffff 65535.99999999999 +40f0000000000000 65536.0 +40f0000000000001 65536.00000000001 +40ffffffffffffff 131071.99999999999 +4100000000000000 131072.0 +4100000000000001 131072.00000000003 +410fffffffffffff 262143.99999999997 +4110000000000000 262144.0 +4110000000000001 262144.00000000006 +411fffffffffffff 524287.99999999994 +4120000000000000 524288.0 +4120000000000001 524288.0000000001 +412fffffffffffff 1.0485759999999999e+06 +4130000000000000 1.048576e+06 +4130000000000001 1.0485760000000002e+06 +413fffffffffffff 2.0971519999999998e+06 +4140000000000000 2.097152e+06 +4140000000000001 2.0971520000000005e+06 +414fffffffffffff 4.1943039999999995e+06 +4150000000000000 4.194304e+06 +4150000000000001 4.194304000000001e+06 +415fffffffffffff 8.388607999999999e+06 +4160000000000000 8.388608e+06 +4160000000000001 8.388608000000002e+06 +416fffffffffffff 1.6777215999999998e+07 +4170000000000000 1.6777216e+07 +4170000000000001 1.6777216000000004e+07 +417fffffffffffff 3.3554431999999996e+07 +4180000000000000 3.3554432e+07 +4180000000000001 3.355443200000001e+07 +418fffffffffffff 6.710886399999999e+07 +4190000000000000 6.7108864e+07 +4190000000000001 6.710886400000001e+07 +419fffffffffffff 1.3421772799999999e+08 +41a0000000000000 1.34217728e+08 +41a0000000000001 1.3421772800000003e+08 +41afffffffffffff 2.6843545599999997e+08 +41b0000000000000 2.68435456e+08 +41b0000000000001 2.6843545600000006e+08 +41bfffffffffffff 5.3687091199999994e+08 +41c0000000000000 5.36870912e+08 +41c0000000000001 5.368709120000001e+08 +41cfffffffffffff 1.0737418239999999e+09 +41d0000000000000 1.073741824e+09 +41d0000000000001 1.0737418240000002e+09 +3e65822107fcfd52 4.0062361426977984e-08 +bfd04dc76695721d -0.2547472478670743 +3dda858149c6e2d1 9.648466959782995e-11 +c276cb397916001e -1.5663811505600073e+12 +40197f48392907a0 6.374298947457561 +40b27cc6f3875d04 4732.777153454026 +be2cffa2ba517936 -3.3758786482808152e-09 +c27621587cb3ad0b -1.5207796437068152e+12 +c06a768b7c4e0b68 -211.70452704661443 +424c3f2525632186 2.426369665982619e+11 +41f2070f169c1121 4.839240041754182e+09 +bd8bd268b68e6a3f -3.162985000843313e-12 +c0b4c47f2cdf5b8a -5316.496778449868 +3ea4502fc5d6d268 6.053813980584764e-07 +c1034c367674cb74 -158086.80783995579 +3f8c8b35bb9457d8 0.013937396800013532 +c00419db794209ff -2.5126256440428274 +c1e4b7a55a25e0cb -2.7806379051836905e+09 +3e72b02936d4ff9b 6.961870520783569e-08 +40d442fd5ad145f4 20747.958668058694 +be4d968d3f71f8cb -1.3778029368671855e-08 +be06e3cafccae224 -6.661813267564451e-10 +c169d9f17d9e8fbc -1.3553547925605647e+07 +420403def63a5b6f 1.0745536199294645e+10 +4221017fbc897d06 3.651979629274419e+10 +c265a315724c7af1 -7.434432395238419e+11 +41ca71f52257bb7d 8.873518766854092e+08 +40bb9ca8be8e9981 7068.659157669522 +be33fac825416fed -4.651866964628022e-09 +41b9f7676678e7aa 4.356442624722849e+08 +3ef7830356aa6b86 2.2422570888562812e-05 +4228f8bd3e99b0a8 5.362618350084503e+10 +403a156ae58348b0 26.083662361671202 +bfa0a1e9406aec9d -0.03248528395985171 +bd9d8e9fa5ead0bd -6.720511814114512e-12 +40408e4b738b6829 33.11167759234406 +41b780ea967cd710 3.943246304876566e+08 +bfb9c16725fd3d7f -0.10060734441252882 +411f01c926fbf29b 508018.2880704791 +bf12787c2bf3394b -7.045991786755916e-05 +c16ed31f1cb9e6c6 -1.616101689769305e+07 +c0e92d0169a39144 -51560.04414537785 +c02b5389421657ff -13.663156571605212 +3f7e91e98b02c917 0.007463371541393002 +4052560383d17909 73.34396453338935 +c1a58fbeaf635d47 -1.8087099969407102e+08 +bfc03382be14186f -0.1265719822042146 +bdb7ae24e9174548 -2.1537062557132775e-11 +41f5855807b73658 5.7769657554507675e+09 +beb2a18da250bf34 -1.1104981549984584e-06 +bedb3641fe3dea79 -6.487833136388005e-06 +c1eb36dbc9b344e9 -3.652640333602162e+09 +40f5cb471941e52a 89268.44366635816 +c080d6326b40eabc -538.7746186324725 +bd82aafe336eacca -2.1222992129454815e-12 +c0ef278a67149b9c -63804.325083068776 +bf1c44bf5a5ffefb -0.0001078359406108085 +bf6d29286f00f02b -0.0035596646994502565 +bdbfafc3545836c4 -2.8818771389702537e-11 +bd7f325712f4128d -1.7733237396191494e-12 +c05e3e3e4a305605 -120.97255186767877 +bfeca80d72521a90 -0.8955142243219871 +3f85f26283efc6c6 0.01071621861590034 +411cfc5dc1540864 474903.4387971221 +bfbb185b70ab53ba -0.1058404111930277 +413fb024878d4063 2.076708529499077e+06 +c274d6353cb62f07 -1.4318905455069392e+12 +40b900fb4ffbf3a9 6400.981689211833 +3fd796b83f190476 0.36857420122038975 +3f89c820f5c353cf 0.012588746547786215 +bf1c9b582d230176 -0.00010912633595961348 +3f0b626c3f1d7427 5.223172037347622e-05 +c1b98e40b01aa47d -4.287530721040724e+08 +bf40e7ac7417bf38 -0.0005158989007991504 +c0fa23eb55ece0ea -107070.70847785813 +c144a3c813d346b5 -2.705296154885138e+06 +420cfdbc6db30e37 1.556450859838194e+10 +bffaedf1a6e222f5 -1.6830917853241634 +bdaa7d712e166bdf -1.2046261072190693e-11 +bd9166a221898f34 -3.956509186266304e-12 +41f29c7719af53ba 4.995903898957941e+09 +c257d70a133c9673 -4.0956803813035077e+11 +3e03f10e0f212551 5.803775500632443e-10 +bdd09a3e6f241c57 -6.039959833086004e-11 +3def70ff3be70cb0 2.2876625416160384e-10 +3e0b4e8e20f31127 7.947341135001321e-10 +c101aa87289cbd2c -144720.89483020583 +c1a30cf840a79c3b -1.5980854432736382e+08 +c1f2cee10365790c -5.048766518342052e+09 +4241f57b0bb131e8 1.542658517463899e+11 +41644786139efcca 1.0632240613157649e+07 +c10c4694a54af747 -231634.5807093924 +3fb93fb09f6c47ac 0.09862808124697037 +410283b654043a66 151670.7910236895 +3f955397b4926431 0.020826692959051655 +c2770eb58f0d2558 -1.584496439506334e+12 +c2574b9d7f803594 -4.0021144320083716e+11 +c1798c4033fe2656 -2.678886724954828e+07 +bdda20af6b41292d -9.505193404385634e-11 +bd9d5ac882093298 -6.6744682973325806e-12 +c10fbff5b2d5a113 -260094.71232152786 +3ea8e96f5b8e56a9 7.42431146882456e-07 +3d98fa6e04f9ce92 5.679394522162092e-12 +bfb82947a67e52b1 -0.09437988104611851 +3f819e7792417fc3 0.008603033209681038 +3ef67230b027b7e0 2.1406226560154065e-05 +410bdd8f44c9ab40 228273.908587778 +bdaddb0efd7a84af -1.3576799338601639e-11 +bfde7f03e3abff4a -0.476502392135434 +be3c374d736e41cc -6.569555391781771e-09 +bd8fd8d37b3ccebc -3.6205821004411243e-12 +bf015dbd315ae6af -3.312333698830599e-05 +bef0a23119ea0f2f -1.58630006077541e-05 +4147e80684a6bfdc 3.1334530363387894e+06 +418ffa8aa44a03a4 6.706414853613976e+07 +41b39bb8b580c8ba 3.2897246950306284e+08 +c13b6a22b648e604 -1.7966427120498428e+06 +c235fcdd893a310f -9.443669023419164e+10 +421ec18437f5198b 3.3023921661274944e+10 +bf8ae37ae39d02db -0.013129196234900877 +bef95e8cca599392 -2.4194083968604218e-05 +3dcad1bdc176163d 4.8784025588835895e-11 +3f1df0dcf9f95ede 0.00011421536191258015 +c1757d0f8a928585 -2.2532344660771865e+07 +c0a5dcfd887953e8 -2798.4951818385052 +c1ad00c4e533e9a3 -2.4329483460139188e+08 +be189b251dba77ae -1.432259747359515e-09 +c0faea4753b428d7 -110244.45793548539 +3f1888203391860a 9.358116666782087e-05 +c07eccfcba9075b0 -492.81170135907723 +c1a9bf542b517f2b -2.1598466165917334e+08 +be6f489bc56ba9c3 -5.827029585742761e-08 +c07aeee5fdde63b1 -430.9311503111922 +bdbff35e51e90a1f -2.905895413133007e-11 +c08585e696d511e1 -688.7375923772889 +3e1584aa5403510d 1.2525254861511635e-09 +425175c897a14c51 2.9996209728519244e+11 +bfefb52e3298237e -0.9908667553109891 +3ece74d4b80f63d4 3.630682329430478e-06 +be56a526ee438107 -2.108991638348143e-08 +3e7365a824bf7034 7.225981696286206e-08 +405b24ce99aa99ff 108.57510987911517 +bd8f8f5522164965 -3.5879444088569995e-12 +c11bb2a14ccdd7af -453800.3250039769 +be24ed37e9a7b972 -2.4361808796334138e-09 +bec4827163240d09 -2.444928008606154e-06 +c1c39851da458093 -6.574990605429863e+08 +3e46091f323f491a 1.0261140888290476e-08 +bdaa570dd2d99eb9 -1.197807008879946e-11 +40f265b33b61e4f4 75355.2019976562 diff --git a/src/promql/src/go_format/tests.rs b/src/promql/src/go_format/tests.rs new file mode 100644 index 00000000000..ef7a02591a4 --- /dev/null +++ b/src/promql/src/go_format/tests.rs @@ -0,0 +1,29 @@ +// Copyright 2023 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::go_format::format_open_metrics_float; + +/// Prometheus `labels.FormatOpenMetricsFloat`; `open_metrics_cases.txt` comes from promql-compat +/// `narthex-golden-formatfloat -openmetrics` as ` `. +#[test] +fn open_metrics_floats_format_like_prometheus() { + let mut checked = 0; + for line in include_str!("open_metrics_cases.txt").lines() { + let (bits, expected) = line.split_once(' ').unwrap(); + let value = f64::from_bits(u64::from_str_radix(bits, 16).unwrap()); + assert_eq!(format_open_metrics_float(value), expected, "{bits}"); + checked += 1; + } + assert!(checked > 300, "{checked}"); +} diff --git a/src/promql/src/histogram_eval.rs b/src/promql/src/histogram_eval.rs index 4b7fdba6c54..4aa577fc54a 100644 --- a/src/promql/src/histogram_eval.rs +++ b/src/promql/src/histogram_eval.rs @@ -40,9 +40,10 @@ use datatypes::series::time::{TimeAxis, union_positions}; pub(crate) use aggregate::sum_or_avg; pub use aggregate::{HistogramAggregate, aggregate_histograms}; +use crate::go_format::format_open_metrics_float; use crate::go_sort; use crate::grid_series::{ - GridSeriesBuilder, LabelSet, METADATA_LABELS, label_set, merge_same_labelset, + GridSeriesBuilder, LabelSet, METADATA_LABELS, external, label_set, merge_same_labelset, }; const BUCKET_LABEL: &str = "le"; @@ -56,6 +57,30 @@ pub enum HistogramFunction { Fraction { lower: f64, upper: f64 }, } +/// `histogram_quantiles(v, label, q...)`: [`evaluate_histograms`] with `Quantile(q)` for each +/// `q`, each result labelled with `label` set to `q` as Prometheus' `FormatOpenMetricsFloat` +/// writes it. Results that then share a label set merge as [`merge_same_labelset`] does, so a +/// repeated `q`, or a `label` that overwrites the label telling two histograms apart, fails at a +/// point both hold. +pub fn histogram_quantiles( + label: &str, + quantiles: &[f64], + schema: &Arc, + series: &[Series], +) -> Result> { + let mut output = Vec::new(); + for &quantile in quantiles { + let value: Arc = Arc::from(format_open_metrics_float(quantile)); + for mut result in + evaluate_histograms(HistogramFunction::Quantile(quantile), schema, series)? + { + result.metric.set(label, value.clone()).map_err(external)?; + output.push(result); + } + } + merge_same_labelset(schema, output) +} + /// Evaluates `function` over the classic and native histograms in `series`. /// /// Float series with the same labels other than `le` form a classic histogram; a float series diff --git a/src/promql/src/histogram_eval/quantiles_cases.txt b/src/promql/src/histogram_eval/quantiles_cases.txt new file mode 100644 index 00000000000..0e9e1501ff8 --- /dev/null +++ b/src/promql/src/histogram_eval/quantiles_cases.txt @@ -0,0 +1,425 @@ +# Generated by promql-compat cmd/narthex-golden-histogram built for amd64 (Prometheus +# v3.15.0 engine, seed 1, 30 cases per function). Each case lists its operation and +# tab-separated arguments, the grid, the input series and either the result series or +# the error. Points are `grid index:hex bits`. +case quantiles quantile 3fd0000000000000 +grid 100000 10000 2 +series __name__=a_bucket|job=x ; 0:4026000000000000 1:4018000000000000 +series __name__=a_bucket|job=x|le=abc ; 0:404f000000000000 1:4057c00000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:403c000000000000 1:403c000000000000 +series __name__=a_bucket|job=y|le=0.1 ; 0:4051500000000000 1:4053b00000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:4058e00000000000 +series __name__=a_bucket|job=y|le=1 ; 0:405d300000000000 1:4069600000000000 +series __name__=a_bucket|job=y|le=5 ; 0:4065580000000000 +series __name__=a_bucket|job=y|le=+Inf ; 0:406c280000000000 1:4074240000000000 +series __name__=b_bucket|job=z|le=0.25 ; 0:404ba00000000000 1:4040200000000000 +series __name__=b_bucket|job=z|le=2.5 ; 0:4060580000000000 1:405a100000000000 +series __name__=b_bucket|job=z|le=inf ; 0:4065680000000000 1:4065180000000000 +result job=x|quantile=0.25 ; 0:7ff8000000000001 1:7ff8000000000001 +result job=y|quantile=0.25 ; 0:3fb4d13c711ede2d 1:3fbcf601dab51b18 +result job=z|quantile=0.25 ; 0:3fc8cbdf90cbdf91 1:3fe1f00000000000 +end +case quantiles quantile bfe0000000000000,3fefae147ae147ae +grid 100000 10000 5 +series __name__=a_bucket|job=x|le=1 ; 0:4024000000000000 1:4035000000000000 2:4000000000000000 3:4028000000000000 4:7ff0000000000000 +series __name__=a_bucket|job=x|le=abc ; 1:4047800000000000 4:7ff0000000000000 +series __name__=a_bucket|job=x|le=1e400 ; 0:0 1:4053800000000000 2:4052800000000000 3:7ff8000000000001 4:7ff0000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:4044800000000000 1:4057800000000000 3:7ff8000000000001 4:7ff0000000000000 +series __name__=a_bucket|job=y ; 0:404a400000000000 1:4041400000000000 2:4017000000000000 3:4058600000000000 4:4050d00000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:405d800000000000 1:404de00000000000 2:405a700000000000 3:405db00000000000 4:405ad00000000000 +series __name__=a_bucket|job=y|le=5 ; 2:4063c80000000000 3:406af00000000000 4:4072440000000000 +series __name__=a_bucket|job=y|le=+Inf ; 0:406fd80000000000 1:4066280000000000 3:406c180000000000 4:4074440000000000 +series __name__=b_bucket|job=y ; 0:404f800000000000 2:4058300000000000 +series __name__=b_bucket|job=y|le=0 ; 0:4061480000000000 1:4064700000000000 2:4066800000000000 3:4058600000000000 4:4051900000000000 +series __name__=b_bucket|job=y|le=1 ; 0:4069300000000000 1:406ee00000000000 2:406a600000000000 3:4066180000000000 4:405a400000000000 +series __name__=b_bucket|job=y|le=+Inf ; 0:406a680000000000 2:4072380000000000 3:406b600000000000 4:4063680000000000 +series __name__=b_bucket|job=z|le=0.25 ; 0:4014000000000000 1:4020000000000000 2:4031000000000000 3:4043800000000000 4:4028000000000000 +series __name__=b_bucket|job=z|le=2.5 ; 0:4048000000000000 1:40200000000001c2 2:4030ffffffff4515 3:4055400000000000 4:4028000000000000 +series __name__=b_bucket|job=z|le=inf ; 1:40200000000001c2 2:4030ffffffff4336 3:405c400000000000 4:4028000000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 0,bfe0000000000000 +grid 100000 10000 3 +series __name__=a_bucket|job=x|le=0.1 ; 0:403e000000000000 1:4028000000000000 2:7ff0000000000000 +series __name__=a_bucket|job=x|le=0.5 ; 0:404c800000000000 1:4041000000000000 2:7ff0000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:4055400000000000 1:4045000000000000 2:7ff0000000000000 +series __name__=a_bucket|job=x|le=5 ; 0:4060000000000000 1:4056000000000000 2:7ff0000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:7ff8000000000001 1:7ff0000000000000 2:7ff0000000000000 +series __name__=b_bucket|job=y|le=0.1 ; 0:4041800000000000 1:4038000000000000 2:4048000000000000 +series __name__=b_bucket|job=y|le=0.5 ; 0:4043000000000000 1:4037fffffffffd5c +series __name__=b_bucket|job=y|le=1 ; 0:4054000000000000 1:4037ffffffffffff +series __name__=b_bucket|job=y|le=5 ; 0:4053ffffffff2419 1:40380000000107e1 2:40553fffffff165b +series __name__=b_bucket|job=y|le=+Inf ; 0:4054000000000000 2:40557fffffff165b +series __name__=b_bucket|job=z|le=1 ; 0:0 1:0 2:0 +series __name__=b_bucket|job=z|le=1.0 ; 0:0 2:0 +series __name__=b_bucket|job=z|le=2 ; 1:1 2:1a56e1fc2f8f359 +series __name__=b_bucket|job=z|le=+Inf ; 0:1 1:1 2:0 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile bfe0000000000000,bfe0000000000000 +grid 100000 10000 6 +series __name__=a_bucket|job=y|le=1 ; 0:402a000000000000 2:4010000000000000 3:4033000000000000 4:401c000000000000 +series __name__=a_bucket|job=y|le=2 ; 0:4035000000000000 1:4040ffffffff4515 2:4010000000000000 3:403d000000000000 4:401c000000000000 5:4056800000000000 +series __name__=a_bucket|job=y|le=5 ; 0:4034ffffffff191a 1:404a7fffffff4515 2:4047000000000000 4:401c000000000000 5:4058400000000000 +series __name__=b_bucket|job=z|le=1 ; 0:4057c00000000000 1:4039800000000000 3:4028800000000000 4:404f600000000000 5:4044600000000000 +series __name__=b_bucket|job=z|le=2 ; 0:4065c00000000000 1:4055d00000000000 2:4060200000000000 3:4057500000000000 4:405f300000000000 5:4059600000000000 +series __name__=b_bucket|job=z|le=5 ; 0:4070e80000000000 1:405a900000000000 2:4069e80000000000 3:4062580000000000 4:4065500000000000 5:4062780000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile 3fd0000000000000,3ff8000000000000,3fe0000000000000 +grid 100000 10000 8 +series __name__=b_bucket|job=z ; 0:4044c00000000000 1:402e000000000000 2:4021000000000000 3:4048e00000000000 4:404ea00000000000 5:4056c00000000000 6:404ce00000000000 7:4047e00000000000 +series __name__=b_bucket|job=z|le=2.5 ; 1:403dc00000000000 2:4049000000000000 3:4050800000000000 4:4055b00000000000 5:4061300000000000 6:4055d00000000000 +series __name__=b_bucket|job=z|le=inf ; 0:4064180000000000 1:4056c00000000000 2:4060400000000000 3:4064100000000000 5:406bf00000000000 6:4057d00000000000 7:4051e00000000000 +result job=z|quantile=0.25 ; 0:7ff8000000000001 1:3ffe969696969696 2:3ffa000000000000 3:3ff851745d1745d1 4:7ff8000000000001 5:3ff04129e4129e41 6:3fe5d574a1601779 7:7ff8000000000001 +result job=z|quantile=0.5 ; 0:7ff8000000000001 1:4004000000000000 2:4004000000000000 3:4004000000000000 4:7ff8000000000001 5:40004129e4129e41 6:3ff5d574a1601779 7:7ff8000000000001 +result job=z|quantile=1.5 ; 0:7ff0000000000000 1:7ff0000000000000 2:7ff0000000000000 3:7ff0000000000000 4:7ff0000000000000 5:7ff0000000000000 6:7ff0000000000000 7:7ff0000000000000 +end +case quantiles quantile 3ff8000000000000,3ff0000000000000 +grid 100000 10000 5 +series __name__=a_bucket|job=x|le=+Inf ; 1:4052600000000000 3:404b000000000000 4:404fe00000000000 +series __name__=a_bucket|job=y|le=+Inf ; 1:0 2:0 3:0 +series __name__=b_bucket|job=z|le=1 ; 0:404e800000000000 1:4052000000000000 2:4029800000000000 3:4054b00000000000 4:4052900000000000 +series __name__=b_bucket|job=z|le=abc ; 2:4056900000000000 3:4062380000000000 4:405f200000000000 +series __name__=b_bucket|job=z|le=1e400 ; 0:4053900000000000 1:4062f00000000000 2:405e800000000000 3:4064380000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:4063080000000000 1:4067680000000000 2:4064480000000000 4:406ee80000000000 +result job=x|quantile=1.0 ; 1:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 +result job=x|quantile=1.5 ; 1:7ff0000000000000 3:7ff0000000000000 4:7ff0000000000000 +result job=y|quantile=1.0 ; 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 +result job=y|quantile=1.5 ; 1:7ff0000000000000 2:7ff0000000000000 3:7ff0000000000000 +result job=z|quantile=1.0 ; 0:3ff0000000000000 1:3ff0000000000000 2:3ff0000000000000 3:7ff8000000000001 4:3ff0000000000000 +result job=z|quantile=1.5 ; 0:7ff0000000000000 1:7ff0000000000000 2:7ff0000000000000 3:7ff0000000000000 4:7ff0000000000000 +end +case quantiles quantile 3ff0000000000000 +grid 100000 10000 2 +series __name__=a_bucket|job=x ; 0:4026000000000000 1:4040800000000000 +series __name__=a_bucket|job=x|le=0.5 ; 0:7ff8000000000001 1:7ff0000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:7ff8000000000001 1:7ff8000000000001 +series __name__=a_bucket|job=x|le=5 ; 0:7ff8000000000001 1:7ff8000000000001 +series __name__=a_bucket|job=x|le=+Inf ; 0:7ff8000000000001 +result job=x|quantile=1.0 ; 0:4014000000000000 1:7ff8000000000001 +end +case quantiles quantile 3feccccccccccccd,3feccccccccccccd,3fe0000000000000 +grid 100000 10000 2 +series __name__=a_bucket|job=x|le=1 ; 0:4024000000000000 1:4010000000000000 +series __name__=a_bucket|job=x|le=2 ; 0:4008000000000000 1:4058800000000000 +series __name__=a_bucket|job=x|le=5 ; +error vector cannot contain metrics with the same labelset +end +case quantiles quantile 3fefae147ae147ae,3fd0000000000000,3ff0000000000000 +grid 100000 10000 7 +series __name__=a_bucket|job=x|le=+Inf ; 1:4047000000000000 2:4010000000000000 3:4024000000000000 4:4022000000000000 5:4047800000000000 6:4033000000000000 +series __name__=b_bucket|job=y|le=1 ; 0:4053000000000000 1:404d000000000000 2:4026000000000000 3:4054800000000000 4:4055400000000000 5:4050000000000000 6:403d000000000000 +series __name__=b_bucket|job=y|le=2 ; 0:4054400000000000 1:4045000000000000 2:402a000000000000 3:4032000000000000 4:403d000000000000 5:4054800000000000 6:4055400000000000 +series __name__=b_bucket|job=y|le=5 ; 0:4057800000000000 1:4056800000000000 2:4038000000000000 3:403a000000000000 4:404f800000000000 5:404a000000000000 6:4055000000000000 +result job=x|quantile=0.25 ; 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=x|quantile=0.99 ; 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=x|quantile=1.0 ; 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=y|quantile=0.25 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=y|quantile=0.99 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=y|quantile=1.0 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +end +case quantiles quantile 0,3ff0000000000000,0 +grid 100000 10000 7 +series __name__=a_bucket|job=x|le=1 ; 0:4045000000000000 1:4034000000000000 2:403a000000000000 3:4056000000000000 5:401c000000000000 +series __name__=a_bucket|job=x|le=1.0 ; 0:4024000000000000 1:4044000000000000 2:4008000000000000 3:4054400000000000 4:4039000000000000 5:4055800000000000 6:4052c00000000000 +series __name__=a_bucket|job=x|le=2 ; 0:404b800000000000 1:4042800000000000 3:4055c00000000000 4:4018000000000000 5:404b800000000000 6:4054c00000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:4045800000000000 1:4054800000000000 2:4050400000000000 3:4043000000000000 4:4050800000000000 +series __name__=a_bucket|job=y|le=0.1 ; 0:4056900000000000 1:403bc00000000000 2:4035800000000000 3:403b400000000000 4:402f000000000000 5:4052600000000000 6:4047600000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:4063f00000000000 1:4045800000000000 2:405a100000000000 3:4057d00000000000 5:4061080000000000 +series __name__=a_bucket|job=y|le=1 ; 0:4069e00000000000 1:405ab00000000000 3:4066400000000000 6:4053200000000000 +series __name__=a_bucket|job=y|le=5 ; 0:4072180000000000 2:406b780000000000 3:406d000000000000 4:4067080000000000 5:4070700000000000 6:405a500000000000 +series __name__=a_bucket|job=y|le=+Inf ; 0:4074b00000000000 1:4067680000000000 2:4073c80000000000 3:4072340000000000 4:4069000000000000 5:4070e80000000000 6:4062c80000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 0 +grid 100000 10000 2 +series __name__=b_bucket|job=z|le=1 ; 0:4055300000000000 1:4036400000000000 +series __name__=b_bucket|job=z|le=2 ; 0:4062280000000000 1:4047800000000000 +series __name__=b_bucket|job=z|le=5 ; 1:404e600000000000 +result job=0.0 ; 0:7ff8000000000001 1:7ff8000000000001 +end +case quantiles quantile 3feccccccccccccd,bfe0000000000000 +grid 100000 10000 6 +series __name__=a_bucket|job=x|le=+Inf ; 0:0 1:0 4:0 5:0 +series __name__=b_bucket|job=z|le=0.25 ; 0:4031000000000000 1:404e000000000000 3:4047800000000000 4:402c000000000000 5:4053400000000000 +series __name__=b_bucket|job=z|le=2.5 ; 0:404a800000000000 1:4058c00000000000 2:4033000000000000 3:4058000000000000 4:4054c00000000000 5:4048000000000000 +series __name__=b_bucket|job=z ; 0:4055000000000000 1:404c000000000000 3:3ff0000000000000 4:4035000000000000 5:4045000000000000 +result job=x|quantile=-0.5 ; 0:fff0000000000000 1:fff0000000000000 4:fff0000000000000 5:fff0000000000000 +result job=x|quantile=0.9 ; 0:7ff8000000000001 1:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 +result job=z|quantile=-0.5 ; 0:fff0000000000000 1:fff0000000000000 2:fff0000000000000 3:fff0000000000000 4:fff0000000000000 5:fff0000000000000 +result job=z|quantile=0.9 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 +end +case quantiles job 3fefae147ae147ae,3fefae147ae147ae +grid 100000 10000 8 +series __name__=a_bucket|job=x ; 0:4050f00000000000 1:4047000000000000 2:4057500000000000 3:404aa00000000000 4:4025000000000000 5:4050c00000000000 6:4055500000000000 7:402b800000000000 +series __name__=a_bucket|job=x|le=1.0 ; 0:4059b00000000000 1:405ac00000000000 3:405e200000000000 4:4056a00000000000 5:4064280000000000 6:4064200000000000 7:4048600000000000 +series __name__=a_bucket|job=x|le=2 ; 0:4061d80000000000 1:405c000000000000 2:4062180000000000 4:4066180000000000 5:406fe00000000000 6:406fa80000000000 7:404b000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:4065380000000000 1:4061800000000000 2:4064080000000000 3:4066180000000000 4:4067080000000000 5:4075340000000000 6:4071f40000000000 7:4051b00000000000 +series __name__=b_bucket|job=y|le=-1 ; 0:3ff0000000000000 1:4010000000000000 2:4010000000000000 4:c014000000000000 5:c014000000000000 6:4028000000000000 7:403d000000000000 +series __name__=b_bucket|job=y|le=0 ; 0:0 1:403d000000000000 2:c014000000000000 3:4055000000000000 4:4032000000000000 5:403e000000000000 6:c014000000000000 7:4043800000000000 +series __name__=b_bucket|job=y|le=1 ; 1:4048000000000000 2:4008000000000000 3:405d400000000000 4:4040800000000000 5:4045000000000000 6:c014000000000000 7:4053c00000000000 +series __name__=b_bucket|job=y|le=+Inf ; 0:c014000000000000 1:4052000000000000 2:7ff0000000000000 3:4060800000000000 4:7ff0000000000000 5:404c000000000000 6:4044800000000000 7:4056000000000000 +series __name__=b_bucket|job=z|le=1 ; 0:4053c00000000000 2:403f400000000000 3:4048a00000000000 4:4008000000000000 5:4052400000000000 6:404ec00000000000 7:4055600000000000 +series __name__=b_bucket|job=z|le=abc ; 0:405be00000000000 1:4059a00000000000 2:4059d00000000000 3:4054c00000000000 4:402d800000000000 5:4055b00000000000 6:4060680000000000 7:4057a00000000000 +series __name__=b_bucket|job=z|le=1e400 ; 0:4063500000000000 1:4065580000000000 2:4061600000000000 3:405ae00000000000 4:4049200000000000 5:4059c00000000000 6:4067900000000000 7:405d900000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:406c480000000000 1:4070800000000000 2:406d200000000000 3:4060400000000000 4:404ba00000000000 6:406a580000000000 7:4062c00000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 7ff8000000000001 +grid 100000 10000 6 +series __name__=a_bucket|job=x|le=0.1 ; 0:4053900000000000 1:402b000000000000 2:4045400000000000 4:4020000000000000 5:4053000000000000 +series __name__=a_bucket|job=x|le=0.5 ; 0:405a400000000000 1:4048e00000000000 2:404aa00000000000 3:405e700000000000 4:4041600000000000 5:405e100000000000 +series __name__=a_bucket|job=x|le=1 ; 0:405d400000000000 1:4053000000000000 2:4054f00000000000 3:4067800000000000 5:405e500000000000 +series __name__=a_bucket|job=x|le=5 ; 0:4069480000000000 1:4058200000000000 2:4064480000000000 3:4068d80000000000 4:4057f00000000000 5:4068c80000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:4070ec0000000000 2:4069000000000000 3:4071b40000000000 5:406a080000000000 +series __name__=b_bucket|job=z|le=0.25 ; 0:4046000000000000 1:403e000000000000 3:403c000000000000 4:403b000000000000 5:4045800000000000 +series __name__=b_bucket|job=z|le=2.5 ; 0:4053400000000000 1:4045000000000000 2:40390000000112e1 3:404e000000000000 4:403b000000000000 5:40457ffffffffda3 +series __name__=b_bucket|job=z|le=inf ; 0:40533fffffff2c58 1:4051000000000000 3:404dfffffffffcb3 5:40457ffffffffda3 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile 3fd0000000000000 +grid 100000 10000 2 +series __name__=a_bucket|job=x|le=-1 ; 0:4048800000000000 +series __name__=a_bucket|job=x|le=0 ; 0:4055800000000000 1:4034000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:4056800000000000 1:0 +series __name__=a_bucket|job=x|le=+Inf ; 0:c014000000000000 1:4036000000000000 +result job=x|quantile=0.25 ; 0:bff0000000000000 1:0 +end +case quantiles job 3fefae147ae147ae,3fd0000000000000 +grid 100000 10000 7 +series __name__=a_bucket|job=x|le=1 ; 0:4026000000000000 1:403a000000000000 5:4043000000000000 6:4000000000000000 +series __name__=a_bucket|job=x|le=2 ; 0:4046800000000000 1:4051800000000000 2:402e000000000000 3:4014000000000000 4:4040000000000000 5:403f000000000000 6:4041000000000000 +series __name__=a_bucket|job=x|le=5 ; 0:4030000000000000 1:4028000000000000 2:4052400000000000 3:4056400000000000 4:4041800000000000 5:4055800000000000 6:4050000000000000 +series __name__=a_bucket|job=y|le=1 ; 1:4041800000000000 2:4056e00000000000 3:4048000000000000 4:4052c00000000000 5:4042a00000000000 6:401d000000000000 +series __name__=a_bucket|job=y|le=2 ; 1:4046800000000000 2:4062180000000000 3:404e400000000000 4:4065800000000000 5:4050e00000000000 6:4056e00000000000 +series __name__=a_bucket|job=y ; 0:405de00000000000 2:4068180000000000 3:4050000000000000 4:4069700000000000 5:4063d00000000000 6:4066980000000000 +series __name__=b_bucket|job=z|le=-1 ; 0:4014000000000000 1:4000000000000000 2:402c000000000000 3:403d000000000000 4:7ff8000000000001 5:3ff0000000000000 6:4043800000000000 +series __name__=b_bucket|job=z|le=0 ; 0:4039000000000000 1:4028000000000000 2:403f000000000000 4:7ff8000000000001 6:c014000000000000 +series __name__=b_bucket|job=z|le=1 ; 0:0 1:7ff0000000000000 2:4041800000000000 3:0 4:7ff8000000000001 5:c014000000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:7ff0000000000000 1:7ff0000000000000 4:7ff8000000000001 5:7ff0000000000000 6:4046000000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile 3feccccccccccccd +grid 100000 10000 2 +series __name__=a_bucket|job=x ; 0:0 +series __name__=a_bucket|job=x|le=0.5 ; 0:0 1:0 +series __name__=a_bucket|job=x|le=1 ; 0:0 1:0 +series __name__=a_bucket|job=x|le=5 ; 1:0 +series __name__=a_bucket|job=x|le=+Inf ; 0:1a56e1fc2f8f359 1:0 +series __name__=a_bucket|job=y|le=+Inf ; 1:4058800000000000 +series __name__=b_bucket|job=z|le=1 ; 0:0 1:0 +series __name__=b_bucket|job=z|le=abc ; 1:0 +series __name__=b_bucket|job=z|le=1e400 ; 0:0 1:1a56e1fc2f8f359 +series __name__=b_bucket|job=z|le=+Inf ; 1:0 +result job=x|quantile=0.9 ; 0:3ff0000000000000 1:7ff8000000000001 +result job=y|quantile=0.9 ; 1:7ff8000000000001 +result job=z|quantile=0.9 ; 0:7ff8000000000001 1:7ff8000000000001 +end +case quantiles quantile 3ff0000000000000 +grid 100000 10000 4 +series __name__=a_bucket|job=x|le=-1 ; 0:4045000000000000 1:4048800000000000 2:4036000000000000 +series __name__=a_bucket|job=x ; 0:4046800000000000 1:4053400000000000 2:4058c00000000000 3:4057800000000000 +series __name__=a_bucket|job=x|le=1 ; 0:4051c00000000000 1:4044000000000000 2:4058c00000000000 3:403e000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:4018000000000000 1:4048000000000000 2:4041800000000000 +series __name__=a_bucket|job=y|le=0.1 ; 0:4022000000000000 2:402e000000000000 3:4042800000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:4024000000000000 2:4043800000000000 3:4042800000000000 +series __name__=a_bucket|job=y|le=1 ; 0:4023ffffffff2419 1:404a000000000000 2:4043800000000000 3:40427fffffff3497 +series __name__=a_bucket|job=y ; 0:4032ffffffff920c 1:404a000000000000 2:404380000000d668 3:40427fffffff3497 +series __name__=a_bucket|job=y|le=+Inf ; 0:4032ffffffff920c 1:404a000000011de0 2:404380000000d443 3:40437fffffff3497 +series __name__=b_bucket|job=z|le=0.1 ; 0:7ff0000000000000 1:c014000000000000 2:4043000000000000 3:4008000000000000 +series __name__=b_bucket|job=z|le=0.5 ; 1:4030000000000000 2:4055800000000000 3:0 +series __name__=b_bucket|job=z|le=1 ; 0:7ff0000000000000 1:4050400000000000 2:0 3:4037000000000000 +series __name__=b_bucket|job=z|le=5 ; 1:405a400000000000 2:403f000000000000 3:404b000000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:7ff8000000000001 1:4060600000000000 2:4041800000000000 3:7ff8000000000001 +result job=x|quantile=1.0 ; 0:3ff0000000000000 1:bff0000000000000 2:3ff0000000000000 3:7ff8000000000001 +result job=y|quantile=1.0 ; 0:3ff0000000000000 1:3ff0000000000000 2:3ff0000000000000 3:3ff0000000000000 +result job=z|quantile=1.0 ; 0:3ff0000000000000 1:4014000000000000 2:3fe0000000000000 3:4014000000000000 +end +case quantiles quantile 3fefae147ae147ae +grid 100000 10000 6 +series __name__=a_bucket|job=y|le=-1 ; 0:4051100000000000 1:4043800000000000 2:4050000000000000 4:4054300000000000 5:4055000000000000 +series __name__=a_bucket|job=y|le=0 ; 1:4047600000000000 2:4059a00000000000 3:405e000000000000 4:4055f00000000000 5:405a200000000000 +series __name__=a_bucket|job=y ; 0:4068e80000000000 1:4060900000000000 2:405fd00000000000 3:4063c00000000000 4:4061000000000000 5:4067b80000000000 +series __name__=b_bucket|job=z|le=-1 ; 0:4055000000000000 2:404a800000000000 3:4052000000000000 4:4024000000000000 5:4051400000000000 +series __name__=b_bucket|job=z|le=0 ; 1:4010000000000000 2:4053000000000000 3:4044800000000000 5:4032000000000000 +series __name__=b_bucket|job=z|le=1 ; 0:4053c00000000000 1:4024000000000000 2:404a000000000000 3:4047000000000000 4:403e000000000000 5:4047000000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:404c000000000000 1:403d000000000000 2:3ff0000000000000 3:4054400000000000 4:404a000000000000 5:4024000000000000 +result job=y|quantile=0.99 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 +result job=z|quantile=0.99 ; 0:bff0000000000000 1:3ff0000000000000 2:bfa0eb1324f3fad0 3:3ff0000000000000 4:3ff0000000000000 5:bff0000000000000 +end +case quantiles quantile 3fefae147ae147ae +grid 100000 10000 6 +series __name__=a_bucket|job=y|le=0.25 ; 0:4057800000000000 2:404f000000000000 3:403e000000000000 4:403d000000000000 5:4056c00000000000 +series __name__=a_bucket|job=y|le=2.5 ; 0:4055400000000000 1:4053400000000000 2:404a800000000000 3:404f000000000000 4:4055400000000000 5:4050c00000000000 +series __name__=a_bucket|job=y|le=inf ; 0:4044800000000000 1:4034000000000000 2:4041000000000000 3:404f000000000000 4:404f000000000000 5:402a000000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:4043800000000000 1:4022000000000000 3:4042800000000000 4:4026000000000000 5:403e000000000000 +result job=y|quantile=0.99 ; 0:3fcfae147ae147ae 1:4003cccccccccccd 2:3fcfae147ae147ae 3:4003a6b851eb851f 4:4003ba0ea0ea0ea1 5:3fcfae147ae147ae +result job=z|quantile=0.99 ; 0:7ff8000000000001 1:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 +end +case quantiles quantile 7ff8000000000001 +grid 100000 10000 7 +series __name__=a_bucket|job=x|le=1 ; 0:0 1:0 2:0 3:0 4:0 5:0 +series __name__=a_bucket|job=x|le=abc ; 0:0 1:0 2:1 3:1 4:0 5:0 +series __name__=a_bucket|job=x|le=1e400 ; 0:1a56e1fc2f8f359 1:0 2:0 3:0 4:1a56e1fc2f8f359 5:1 6:0 +series __name__=a_bucket|job=x ; 0:0 1:1a56e1fc2f8f359 2:0 3:0 4:1a56e1fc2f8f359 5:0 6:0 +series __name__=a_bucket|job=y ; 0:402a000000000000 1:4035000000000000 3:4044000000000000 4:403f000000000000 5:3ff0000000000000 6:4034000000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:404d000000000000 1:4046800000000000 2:4043000000000000 4:4042800000000000 5:4040000000000000 6:403a000000000000 +series __name__=a_bucket|job=y|le=1 ; 0:405a400000000000 1:4049800000000000 3:405e800000000000 4:404e000000000000 5:4042000000000000 6:4045800000000000 +series __name__=a_bucket|job=y|le=5 ; 0:7ff0000000000000 1:404c000000000000 2:0 3:4061000000000000 4:4059000000000000 5:0 6:4056400000000000 +series __name__=a_bucket|job=y|le=+Inf ; 1:4059000000000000 2:4020000000000000 3:4062a00000000000 4:405bc00000000000 5:c014000000000000 6:405e800000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:404b800000000000 2:4052400000000000 4:4044000000000000 5:4047800000000000 6:4050800000000000 +result job=x|quantile=NaN ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 +result job=y|quantile=NaN ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +result job=z|quantile=NaN ; 0:7ff8000000000001 2:7ff8000000000001 4:7ff8000000000001 5:7ff8000000000001 6:7ff8000000000001 +end +case quantiles quantile 3fefae147ae147ae,3fefae147ae147ae,7ff8000000000001 +grid 100000 10000 2 +series __name__=a_bucket|job=x|le=0.25 ; 0:403a000000000000 1:4030000000000000 +series __name__=a_bucket|job=x|le=2.5 ; 0:4039fffffffffd24 +series __name__=a_bucket|job=x|le=inf ; 0:404afffffffffe92 1:404d800000000000 +series __name__=a_bucket|job=y|le=1 ; 0:4046800000000000 +series __name__=a_bucket|job=y|le=1.0 ; 0:7ff0000000000000 1:4018000000000000 +series __name__=a_bucket|job=y|le=2 ; 0:7ff0000000000000 1:4046000000000000 +series __name__=a_bucket|job=y|le=+Inf ; 0:7ff0000000000000 1:404b800000000000 +series __name__=b_bucket|job=z|le=-1 ; 0:404b800000000000 1:4043e00000000000 +series __name__=b_bucket|job=z|le=0 ; 0:405ec00000000000 1:4060900000000000 +series __name__=b_bucket|job=z|le=1 ; 0:4062f80000000000 +series __name__=b_bucket|job=z ; 0:406e400000000000 1:406a380000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile 3ff0000000000000,7ff8000000000001,3ff8000000000000 +grid 100000 10000 1 +series __name__=a_bucket|job=x|le=0.1 ; 0:403d000000000000 +series __name__=a_bucket|job=x|le=0.5 ; 0:403d000000000330 +series __name__=a_bucket|job=x ; +series __name__=a_bucket|job=x|le=5 ; 0:404ffffffffffe13 +series __name__=a_bucket|job=x|le=+Inf ; 0:404ffffffffffe13 +series __name__=a_bucket|job=y|le=1 ; 0:4055000000000000 +series __name__=a_bucket|job=y|le=abc ; 0:404f800000000000 +series __name__=a_bucket|job=y|le=1e400 ; +series __name__=a_bucket|job=y|le=+Inf ; 0:4053000000000000 +series __name__=b_bucket|job=z|le=1 ; 0:404bc00000000000 +series __name__=b_bucket|job=z|le=1.0 ; 0:4058900000000000 +series __name__=b_bucket|job=z|le=2 ; +series __name__=b_bucket|job=z|le=+Inf ; 0:4065480000000000 +result job=x|quantile=1.0 ; 0:4014000000000000 +result job=x|quantile=1.5 ; 0:7ff0000000000000 +result job=x|quantile=NaN ; 0:7ff8000000000001 +result job=y|quantile=1.0 ; 0:3ff0000000000000 +result job=y|quantile=1.5 ; 0:7ff0000000000000 +result job=y|quantile=NaN ; 0:7ff8000000000001 +result job=z|quantile=1.0 ; 0:3ff0000000000000 +result job=z|quantile=1.5 ; 0:7ff0000000000000 +result job=z|quantile=NaN ; 0:7ff8000000000001 +end +case quantiles quantile 3fd0000000000000,bfe0000000000000,3fefae147ae147ae +grid 100000 10000 6 +series __name__=a_bucket|job=x|le=-1 ; 0:4045000000000000 1:4042000000000000 2:4046000000000000 3:403d000000000000 4:3ff0000000000000 +series __name__=a_bucket|job=x ; 1:404e800000000000 3:403d000000000330 5:4038000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:405d400000000000 1:4057c00000000000 2:404fffffffff0e1c 3:403d000000000330 +series __name__=a_bucket|job=x|le=+Inf ; 1:4057c00000010522 2:4057ffffffff870e 3:4041000000000198 4:4030000000000000 5:4048000000000000 +series __name__=a_bucket|job=y|le=1 ; 0:0 1:0 2:0 3:0 4:0 +series __name__=a_bucket|job=y|le=2 ; 0:1 2:1a56e1fc2f8f359 3:1 4:0 5:0 +series __name__=a_bucket|job=y|le=5 ; 0:1a56e1fc2f8f359 1:0 2:0 3:1 4:0 +series __name__=b_bucket|job=y|le=-1 ; 0:402c000000000000 1:4018000000000000 2:4014000000000000 3:4047000000000000 4:4024000000000000 5:4031000000000000 +series __name__=b_bucket|job=y|le=0 ; 0:404a800000000000 2:4040800000000000 4:4031000000000000 5:404c800000000000 +series __name__=b_bucket|job=y|le=1 ; 0:404e800000000000 1:4055000000000000 2:4053400000000000 3:4046fffffffffd78 4:4040800000000000 5:404c800000000322 +series __name__=b_bucket|job=y|le=+Inf ; 1:4054ffffffff191a 2:4053400000000000 3:4057bffffffffebc 4:404080000000b56b 5:404c800000013c7e +series __name__=b_bucket|job=z|le=1 ; 0:4037000000000000 1:4048e00000000000 2:4050800000000000 3:404d400000000000 4:4057800000000000 +series __name__=b_bucket|job=z|le=abc ; 0:405a500000000000 1:405ea00000000000 2:4062a00000000000 4:405f800000000000 +series __name__=b_bucket|job=z|le=1e400 ; 0:405eb00000000000 1:4067b80000000000 2:406d300000000000 3:406ab00000000000 4:4064b80000000000 5:4062800000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:4061000000000000 1:406df00000000000 2:4070100000000000 3:4072040000000000 4:4065280000000000 5:4064880000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 3fe0000000000000,3ff0000000000000,bfe0000000000000 +grid 100000 10000 1 +series __name__=a_bucket|job=x|le=1 ; 0:4012000000000000 +series __name__=a_bucket|job=x ; 0:403d000000000000 +series __name__=a_bucket|job=x|le=5 ; 0:4055f00000000000 +series __name__=b_bucket|job=z|le=1 ; +series __name__=b_bucket|job=z|le=1.0 ; 0:4042000000000000 +series __name__=b_bucket|job=z|le=2 ; 0:404b000000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:404b000000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 3ff8000000000000,0 +grid 100000 10000 3 +series __name__=b_bucket|job=z|le=1 ; 0:4041800000000000 1:4024000000000000 2:4000000000000000 +series __name__=b_bucket|job=z|le=abc ; 0:40417fffffff3f96 1:402e000000000000 2:4000000000000000 +series __name__=b_bucket|job=z|le=1e400 ; 0:40527fffffff9fcb 1:4045000000000000 2:40000000000001c2 +series __name__=b_bucket|job=z|le=+Inf ; 0:405dbfffffff9fcb 1:4044ffffffff191a 2:400000000000b1ae +result job=0.0 ; 0:0 1:0 2:0 +result job=1.5 ; 0:7ff0000000000000 1:7ff0000000000000 2:7ff0000000000000 +end +case quantiles quantile 3ff0000000000000,3fe0000000000000,3fefae147ae147ae +grid 100000 10000 4 +series __name__=a_bucket|job=x|le=0.1 ; 0:c014000000000000 1:4026000000000000 2:4010000000000000 3:0 +series __name__=a_bucket|job=x|le=0.5 ; 0:4000000000000000 2:403e000000000000 3:403a000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:4038000000000000 1:4054000000000000 2:404a000000000000 3:4044800000000000 +series __name__=a_bucket|job=x|le=5 ; 1:4057000000000000 2:404b000000000000 3:4056000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 0:7ff8000000000001 1:4060400000000000 2:4055c00000000000 3:4061000000000000 +series __name__=a_bucket|job=y|le=0.1 ; 0:0 1:0 2:0 3:0 +series __name__=a_bucket|job=y|le=0.5 ; 0:1 1:0 2:0 3:1 +series __name__=a_bucket|job=y|le=1 ; 0:1 1:0 2:0 3:1 +series __name__=a_bucket|job=y|le=5 ; 0:0 2:0 3:1 +series __name__=a_bucket|job=y|le=+Inf ; 0:0 1:0 3:0 +result job=x|quantile=0.5 ; 0:3ff0000000000000 1:3fe9bd37a6f4de9c 2:3fe9d1745d1745d2 3:400a620ae4c415ca +result job=x|quantile=0.99 ; 0:3ff0000000000000 1:4014000000000000 2:4014000000000000 3:4014000000000000 +result job=x|quantile=1.0 ; 0:3ff0000000000000 1:4014000000000000 2:4014000000000000 3:4014000000000000 +result job=y|quantile=0.5 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 +result job=y|quantile=0.99 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 +result job=y|quantile=1.0 ; 0:7ff8000000000001 1:7ff8000000000001 2:7ff8000000000001 3:7ff8000000000001 +end +case quantiles job 3fefae147ae147ae +grid 100000 10000 1 +series __name__=a_bucket|job=x|le=0.25 ; 0:4055e00000000000 +series __name__=a_bucket|job=x|le=2.5 ; 0:4059200000000000 +series __name__=a_bucket|job=x|le=inf ; 0:405b200000000000 +series __name__=a_bucket|job=y|le=1 ; 0:4051300000000000 +series __name__=a_bucket|job=y|le=2 ; 0:4057800000000000 +series __name__=a_bucket|job=y|le=5 ; 0:4058b00000000000 +series __name__=b_bucket|job=z|le=-1 ; 0:4051c00000000000 +series __name__=b_bucket|job=z|le=0 ; 0:4060400000000000 +series __name__=b_bucket|job=z|le=1 ; 0:4065280000000000 +series __name__=b_bucket|job=z|le=+Inf ; 0:4066880000000000 +error vector cannot contain metrics with the same labelset +end +case quantiles job 3fe0000000000000,3fe0000000000000 +grid 100000 10000 5 +series __name__=a_bucket|job=x|le=0.1 ; 0:4008000000000000 3:4022000000000000 4:403a000000000000 +series __name__=a_bucket|job=x|le=0.5 ; 0:4032000000000000 1:4053400000000000 3:40220000000001fa 4:4040000000000000 +series __name__=a_bucket|job=x|le=1 ; 0:40320000000001fa 1:40533fffffff2c58 2:404200000000c5ea 3:404c80000000007e +series __name__=a_bucket|job=x|le=5 ; 0:40320000000003f4 2:4042000000018bd4 4:4054000000000000 +series __name__=a_bucket|job=x|le=+Inf ; 1:40533fffffff2c57 2:40420000000251be 3:404c7ffffffd8dc6 4:4053ffffffff2419 +series __name__=b_bucket|job=y|le=1 ; 0:4050c00000000000 2:4055500000000000 3:4044c00000000000 4:4047000000000000 +series __name__=b_bucket|job=y|le=1.0 ; 0:405b000000000000 1:405f400000000000 2:4066c00000000000 3:4054500000000000 4:404b800000000000 +series __name__=b_bucket|job=y|le=2 ; 0:405e400000000000 1:406a500000000000 2:406b980000000000 4:405d100000000000 +series __name__=b_bucket|job=y|le=+Inf ; 0:4060b80000000000 1:4072180000000000 2:406e400000000000 3:4067500000000000 4:4067580000000000 +series __name__=b_bucket|job=z|le=-1 ; 0:0 1:0 2:0 3:0 4:0 +series __name__=b_bucket|job=z|le=0 ; 0:1 1:0 3:1a56e1fc2f8f359 4:0 +series __name__=b_bucket|job=z ; 0:1 1:0 2:1a56e1fc2f8f359 3:0 4:0 +series __name__=b_bucket|job=z|le=+Inf ; 0:0 1:1 3:0 +error vector cannot contain metrics with the same labelset +end +case quantiles quantile bfe0000000000000,0 +grid 100000 10000 8 +series __name__=a_bucket|job=x|le=1 ; 0:0 1:0 5:0 6:0 +series __name__=a_bucket|job=x ; 0:1a56e1fc2f8f359 1:0 2:0 3:0 4:0 5:0 6:0 7:1 +series __name__=a_bucket|job=x|le=2 ; 0:1 1:1a56e1fc2f8f359 2:0 3:1 4:0 5:0 6:1a56e1fc2f8f359 7:0 +series __name__=a_bucket|job=x|le=+Inf ; 0:0 1:0 2:1 3:0 4:1a56e1fc2f8f359 5:0 6:0 7:0 +series __name__=a_bucket|job=y|le=0.1 ; 0:403b000000000000 1:4040000000000000 2:4018000000000000 3:4008000000000000 4:4042000000000000 5:403c000000000000 6:4045800000000000 7:4032000000000000 +series __name__=a_bucket|job=y|le=0.5 ; 0:4052000000000000 1:404b800000000000 2:4017fffffffffd5c 3:4008000000000000 5:403c000000000000 6:4045800000000000 7:4032000000000000 +series __name__=a_bucket|job=y ; 0:405bc00000000000 1:404b800000012e5e 2:4017fffffffef57a 3:4030000000000000 4:4051400000000000 7:4045000000000000 +series __name__=a_bucket|job=y|le=+Inf ; 0:4061c0000000c32a 1:404e000000012e5e 2:402ffffffffef6cc 3:402ffffffffea028 4:405ac00000000000 5:40587fffffffff3b 6:40458000000004ba +series __name__=b_bucket|job=z ; 0:4000000000000000 1:4043000000000000 2:402a000000000000 3:403c000000000000 4:4043800000000000 5:4043800000000000 6:4020000000000000 7:0 +series __name__=b_bucket|job=z|le=1.0 ; 0:4014000000000000 1:4050400000000000 2:402a000000000000 3:4046000000000000 4:4049800000000000 5:4055c00000000000 6:4039000000000000 7:403c000000000000 +series __name__=b_bucket|job=z|le=2 ; 0:4018000000000000 1:4056400000000000 2:402a0000000002db 3:4046000000000000 4:40497ffffffee7a0 5:405f800000000000 6:4038fffffffeed1f 7:403c0000000133dd +series __name__=b_bucket|job=z|le=+Inf ; 0:4047800000000000 1:405640000000f4a4 2:40418000000000b7 3:404600000000f1e4 4:40497ffffffee7a0 5:405f800000000376 6:4038fffffffeed1f 7:403c000000000000 +result job=x|quantile=-0.5 ; 0:fff0000000000000 1:fff0000000000000 2:fff0000000000000 3:fff0000000000000 4:fff0000000000000 5:fff0000000000000 6:fff0000000000000 7:fff0000000000000 +result job=x|quantile=0.0 ; 0:7ff8000000000001 1:fff8000000000000 2:7ff8000000000001 3:0 4:fff8000000000000 5:7ff8000000000001 6:fff8000000000000 7:7ff8000000000001 +result job=y|quantile=-0.5 ; 0:fff0000000000000 1:fff0000000000000 2:fff0000000000000 3:fff0000000000000 4:fff0000000000000 5:fff0000000000000 6:fff0000000000000 7:fff0000000000000 +result job=y|quantile=0.0 ; 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:7ff8000000000001 +result job=z|quantile=-0.5 ; 0:fff0000000000000 1:fff0000000000000 2:fff0000000000000 3:fff0000000000000 4:fff0000000000000 5:fff0000000000000 6:fff0000000000000 7:fff0000000000000 +result job=z|quantile=0.0 ; 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 +end diff --git a/src/promql/src/histogram_eval/tests.rs b/src/promql/src/histogram_eval/tests.rs index 8b815b0a49d..2452cffe5b7 100644 --- a/src/promql/src/histogram_eval/tests.rs +++ b/src/promql/src/histogram_eval/tests.rs @@ -22,7 +22,7 @@ use datatypes::series::time::{EvalGrid, GridRange, GridSpec, TimeAxis}; use super::float_histogram::{AddOutcome, FloatHistogram}; use super::{ HistogramAggregate, HistogramFunction, NativeHistogramFunction, aggregate_histograms, - evaluate_histograms, map_native_histogram, + evaluate_histograms, histogram_quantiles, map_native_histogram, }; use crate::grid_series::merge_same_labelset; use crate::grid_series::reference::{ @@ -127,6 +127,30 @@ fn classic_histograms_match_prometheus() { assert!(failed > 20, "{failed} failed"); } +/// `histogram_quantiles` over classic histograms, evaluated by the Prometheus v3.15.0 engine with +/// experimental functions enabled (promql-compat `narthex-golden-histogram -quantiles`). +#[test] +fn histogram_quantiles_match_prometheus() { + let cases = golden_cases(include_str!("quantiles_cases.txt")); + assert_eq!(cases.len(), 30); + let mut failed = 0; + for case in &cases { + let schema = schema(case); + let input: Vec<_> = case + .inputs + .iter() + .filter_map(|(labels, points)| mixed_series(&schema, labels, points, &BTreeMap::new())) + .collect(); + let quantiles: Vec = case.spec[2] + .split(',') + .map(|bits| f64::from_bits(u64::from_str_radix(bits, 16).unwrap())) + .collect(); + let actual = histogram_quantiles(&case.spec[1], &quantiles, &schema, &input); + failed += usize::from(assert_outcome(case, actual, &case.outcome)); + } + assert!(failed > 5, "{failed} failed"); +} + #[test] fn native_histograms_match_prometheus() { let cases = golden_cases(include_str!("native_cases.txt")); diff --git a/src/promql/src/lib.rs b/src/promql/src/lib.rs index c9ee89ff62c..433717d5502 100644 --- a/src/promql/src/lib.rs +++ b/src/promql/src/lib.rs @@ -17,6 +17,7 @@ pub mod error; pub mod evaluated; pub mod extension_plan; pub mod functions; +mod go_format; mod go_sort; #[cfg(test)] mod golden;