From 73aa2a72318801b4f06be3a71ce367a10ffef343 Mon Sep 17 00:00:00 2001 From: Zeying Zhu <50204836+zzylol@users.noreply.github.com> Date: Sun, 4 Oct 2026 15:24:00 +0000 Subject: [PATCH 1/4] Connect KLL demo estimates to Prometheus and Grafana --- README.md | 5 +- asap-precompute-rs/Cargo.lock | 1 + asap-precompute-rs/Cargo.toml | 3 + asap-precompute-rs/src/bin/asap_otap_demo.rs | 15 ++ .../src/bin/demo/prometheus_export.rs | 163 ++++++++++++++++++ demos/kll-grafana/compose.yaml | 25 +++ demos/kll-grafana/grafana/dashboards/kll.json | 81 +++++++++ .../grafana/provisioning/dashboards/asap.yaml | 7 + .../provisioning/datasources/prometheus.yaml | 9 + demos/kll-grafana/prometheus.yml | 4 + demos/kll-grafana/verify.py | 53 ++++++ docs/demo-guide.md | 58 +++++++ 12 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 asap-precompute-rs/src/bin/demo/prometheus_export.rs create mode 100644 demos/kll-grafana/compose.yaml create mode 100644 demos/kll-grafana/grafana/dashboards/kll.json create mode 100644 demos/kll-grafana/grafana/provisioning/dashboards/asap.yaml create mode 100644 demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml create mode 100644 demos/kll-grafana/prometheus.yml create mode 100644 demos/kll-grafana/verify.py diff --git a/README.md b/README.md index 2713b32..900c5e2 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,10 @@ All of this sits on the host-neutral runtime in the same crate ## Build & test For a presentation-ready walkthrough of the real YAML pipeline integration, -see the [live OTAP pipeline demo guide](./docs/demo-guide.md). +see the [live OTAP pipeline demo guide](./docs/demo-guide.md). The guide also +includes a [Prometheus + Grafana setup](./docs/demo-guide.md#write-kll-estimates-to-prometheus-and-view-them-in-grafana) +that writes the KLL p50/p99 estimates to Prometheus and displays them in a +provisioned Grafana dashboard. ```sh cd asap-precompute-rs diff --git a/asap-precompute-rs/Cargo.lock b/asap-precompute-rs/Cargo.lock index 089542e..aec0f19 100644 --- a/asap-precompute-rs/Cargo.lock +++ b/asap-precompute-rs/Cargo.lock @@ -372,6 +372,7 @@ dependencies = [ "otel-arrow-dfe-telemetry", "proptest", "prost 0.13.5", + "prost 0.14.4", "serde", "serde_json", "thiserror 1.0.69", diff --git a/asap-precompute-rs/Cargo.toml b/asap-precompute-rs/Cargo.toml index ea28761..71e7512 100644 --- a/asap-precompute-rs/Cargo.toml +++ b/asap-precompute-rs/Cargo.toml @@ -10,6 +10,8 @@ license = "MIT" asap_sketchlib = { git = "https://github.com/ProjectASAP/asap_sketchlib", rev = "010457de46ba9ec5574a53476bbe8b4bdb02b965" } serde = { version = "1", features = ["derive"] } prost = "0.13" +# OTAP's generated protobuf types implement the 0.14 Message trait. +prost-otap = { package = "prost", version = "0.14", optional = true } thiserror = "1" # Apache Arrow is only pulled in by the OTAP codec. Consumers on the @@ -73,6 +75,7 @@ otap = ["dep:arrow-array", "dep:arrow-schema"] # folded into `otap`. otap-engine = [ "otap", + "dep:prost-otap", "dep:otel-arrow-dfe-engine", "dep:otel-arrow-dfe-otap", "dep:otel-arrow-dfe-config", diff --git a/asap-precompute-rs/src/bin/asap_otap_demo.rs b/asap-precompute-rs/src/bin/asap_otap_demo.rs index f996c8d..fed0671 100644 --- a/asap-precompute-rs/src/bin/asap_otap_demo.rs +++ b/asap-precompute-rs/src/bin/asap_otap_demo.rs @@ -1,6 +1,9 @@ //! Multi-process OTAP sketch create -> merge -> estimate demonstration. //! Each ASAP processor runs in its own OS process and OTAP RuntimePipeline. +#[path = "demo/prometheus_export.rs"] +mod prometheus_export; + use asap_precompute_rs::envelope::{Encoding, SketchEnvelope, SketchType}; use asap_precompute_rs::observation::KeyValue; use asap_precompute_rs::otap::codec::{decode_pdata_to_observations, encode_envelopes_to_pdata}; @@ -756,6 +759,7 @@ struct DemoManifest { } struct ParentOptions { + prometheus_otlp_endpoint: Option, output_dir: Option, result_manifest: Option, points_per_source: u64, @@ -766,6 +770,7 @@ struct ParentOptions { fn parent_options(args: &[std::ffi::OsString]) -> Result { let mut options = ParentOptions { + prometheus_otlp_endpoint: None, output_dir: None, result_manifest: None, points_per_source: 100, @@ -780,6 +785,9 @@ fn parent_options(args: &[std::ffi::OsString]) -> Result .get(index + 1) .ok_or_else(|| format!("missing value for {flag}"))?; match flag.as_ref() { + "--prometheus-otlp-endpoint" => { + options.prometheus_otlp_endpoint = Some(value.to_string_lossy().into_owned()); + } "--output-dir" => options.output_dir = Some(PathBuf::from(value)), "--result-manifest" => options.result_manifest = Some(PathBuf::from(value)), "--points-per-source" => { @@ -812,6 +820,9 @@ fn parent_options(args: &[std::ffi::OsString]) -> Result } index += 2; } + if options.prometheus_otlp_endpoint.is_some() && options.scenario != "kll" { + return Err("--prometheus-otlp-endpoint requires --scenario kll".into()); + } Ok(options) } @@ -954,6 +965,10 @@ fn run_parent(options: ParentOptions) -> Result<(), String> { } } let validation_elapsed_nanoseconds = validation_start.elapsed().as_nanos(); + if let Some(endpoint) = options.prometheus_otlp_endpoint { + prometheus_export::export(&out, &endpoint)?; + println!("KLL estimates exported to Prometheus"); + } if let Some(path) = options.result_manifest { let manifest = DemoManifest { parent_pid: std::process::id(), diff --git a/asap-precompute-rs/src/bin/demo/prometheus_export.rs b/asap-precompute-rs/src/bin/demo/prometheus_export.rs new file mode 100644 index 0000000..eaf64a7 --- /dev/null +++ b/asap-precompute-rs/src/bin/demo/prometheus_export.rs @@ -0,0 +1,163 @@ +//! Optional demo-only OTLP/HTTP export. Curl supplies HTTP/TLS without adding +//! an HTTP client dependency to the collector runtime. +use otel_arrow_dfe_pdata::proto::opentelemetry::collector::metrics::v1::{ + ExportMetricsServiceRequest, ExportMetricsServiceResponse, +}; +use otel_arrow_dfe_pdata::proto::opentelemetry::metrics::v1::metric::Data; +use prost_otap::Message; +use std::io::Write; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::time::{SystemTime, UNIX_EPOCH}; + +fn timestamp_gauges(bytes: &[u8], now: u64) -> Result, String> { + let mut request = ExportMetricsServiceRequest::decode(bytes).map_err(|e| e.to_string())?; + let mut points = 0; + for resource in &mut request.resource_metrics { + for scope in &mut resource.scope_metrics { + let scope_attributes = scope + .scope + .as_ref() + .map(|s| s.attributes.as_slice()) + .unwrap_or_default(); + for metric in &mut scope.metrics { + let Some(Data::Gauge(gauge)) = &mut metric.data else { + return Err("Prometheus demo export expects only estimated gauges".into()); + }; + for point in &mut gauge.data_points { + // The OTAP codec stores series labels on the scope. Prometheus + // identifies series by point attributes, so materialize them here. + for attribute in scope_attributes { + if !point.attributes.iter().any(|a| a.key == attribute.key) { + point.attributes.push(attribute.clone()); + } + } + // Synthetic windows stay in the trace files. Export is a current + // snapshot of the completed estimate, not historical telemetry. + point.start_time_unix_nano = 0; + point.time_unix_nano = now; + points += 1; + } + } + } + } + if points == 0 { + return Err("no estimated gauge points to export".into()); + } + Ok(request.encode_to_vec()) +} + +pub fn export(path: &Path, endpoint: &str) -> Result<(), String> { + if !(endpoint.starts_with("http://") || endpoint.starts_with("https://")) { + return Err("Prometheus OTLP endpoint must be an http:// or https:// URL".into()); + } + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|e| e.to_string())? + .as_nanos() as u64; + let body = timestamp_gauges(&std::fs::read(path).map_err(|e| e.to_string())?, now)?; + let mut child = Command::new("curl") + .args([ + "--silent", + "--show-error", + "--fail-with-body", + "--max-time", + "30", + "--header", + "Content-Type: application/x-protobuf", + "--header", + "Accept: application/x-protobuf", + "--data-binary", + "@-", + "--url", + endpoint, + ]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| format!("start curl for Prometheus OTLP export: {e}"))?; + let write_result = child.stdin.take().expect("piped stdin").write_all(&body); + let output = child.wait_with_output().map_err(|e| e.to_string())?; + if !output.status.success() { + return Err(format!( + "Prometheus OTLP export failed: {} {}", + String::from_utf8_lossy(&output.stderr), + String::from_utf8_lossy(&output.stdout) + )); + } + write_result.map_err(|e| format!("write OTLP request: {e}"))?; + let response = ExportMetricsServiceResponse::decode(output.stdout.as_slice()) + .map_err(|e| format!("invalid Prometheus OTLP response: {e}"))?; + if let Some(partial) = response.partial_success { + if partial.rejected_data_points != 0 || !partial.error_message.is_empty() { + return Err(format!( + "Prometheus OTLP partial success: {} rejected: {}", + partial.rejected_data_points, partial.error_message + )); + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use otel_arrow_dfe_pdata::proto::opentelemetry::common::v1::{ + any_value::Value, AnyValue, InstrumentationScope, KeyValue, + }; + use otel_arrow_dfe_pdata::proto::opentelemetry::metrics::v1::{ + Gauge, Metric, NumberDataPoint, ResourceMetrics, ScopeMetrics, + }; + + #[test] + fn export_uses_current_timestamp_and_preserves_estimate() { + let request = ExportMetricsServiceRequest { + resource_metrics: vec![ResourceMetrics { + scope_metrics: vec![ScopeMetrics { + scope: Some(InstrumentationScope { attributes: vec![KeyValue { key: "quantile".into(), value: Some(AnyValue { value: Some(Value::StringValue("0.99".into())) }) }], ..Default::default() }), + metrics: vec![Metric { + name: "request.duration.estimate".into(), + data: Some(Data::Gauge(Gauge { data_points: vec![NumberDataPoint { + time_unix_nano: 2_000_000_000, + value: Some(otel_arrow_dfe_pdata::proto::opentelemetry::metrics::v1::number_data_point::Value::AsDouble(198.0)), + ..Default::default() + }] })), + ..Default::default() + }], + ..Default::default() + }], + ..Default::default() + }], + }; + let updated = ExportMetricsServiceRequest::decode( + timestamp_gauges(&request.encode_to_vec(), 123456) + .unwrap() + .as_slice(), + ) + .unwrap(); + let metric = &updated.resource_metrics[0].scope_metrics[0].metrics[0]; + assert_eq!(metric.name, "request.duration.estimate"); + let Some(Data::Gauge(gauge)) = &metric.data else { + panic!("expected gauge") + }; + assert_eq!(gauge.data_points[0].time_unix_nano, 123456); + let Some(Data::Gauge(original)) = + &request.resource_metrics[0].scope_metrics[0].metrics[0].data + else { + panic!("expected gauge") + }; + assert_eq!(gauge.data_points[0].value, original.data_points[0].value); + assert_eq!( + gauge.data_points[0].attributes, + request.resource_metrics[0].scope_metrics[0] + .scope + .as_ref() + .unwrap() + .attributes + ); + assert!( + timestamp_gauges(&ExportMetricsServiceRequest::default().encode_to_vec(), 1).is_err() + ); + } +} diff --git a/demos/kll-grafana/compose.yaml b/demos/kll-grafana/compose.yaml new file mode 100644 index 0000000..87353e5 --- /dev/null +++ b/demos/kll-grafana/compose.yaml @@ -0,0 +1,25 @@ +services: + prometheus: + image: prom/prometheus:v3.5.0 + command: + - --config.file=/etc/prometheus/prometheus.yml + - --web.enable-otlp-receiver + ports: + - "127.0.0.1:${PROMETHEUS_PORT:-9090}:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus-data:/prometheus + grafana: + image: grafana/grafana:12.1.0 + ports: + - "127.0.0.1:${GRAFANA_PORT:-3000}:3000" + environment: + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer + volumes: + - ./grafana/provisioning:/etc/grafana/provisioning:ro + - ./grafana/dashboards:/var/lib/grafana/dashboards:ro + - grafana-data:/var/lib/grafana +volumes: + prometheus-data: + grafana-data: diff --git a/demos/kll-grafana/grafana/dashboards/kll.json b/demos/kll-grafana/grafana/dashboards/kll.json new file mode 100644 index 0000000..a78a6da --- /dev/null +++ b/demos/kll-grafana/grafana/dashboards/kll.json @@ -0,0 +1,81 @@ +{ + "uid": "asap-kll", + "title": "ASAP KLL estimates", + "schemaVersion": 39, + "version": 1, + "refresh": "5s", + "time": { + "from": "now-15m", + "to": "now" + }, + "panels": [ + { + "id": 1, + "type": "stat", + "title": "Latest KLL estimates", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "targets": [ + { + "refId": "A", + "expr": "request_duration_estimate{quantile=~\"0.5|0.99\"}", + "legendFormat": "quantile {{quantile}}", + "instant": true + } + ], + "fieldConfig": { + "defaults": { + "decimals": 3 + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } + } + }, + { + "id": 2, + "type": "timeseries", + "title": "KLL estimates over time", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "targets": [ + { + "refId": "A", + "expr": "request_duration_estimate{quantile=~\"0.5|0.99\"}", + "legendFormat": "quantile {{quantile}}", + "instant": false + } + ], + "fieldConfig": { + "defaults": { + "decimals": 3 + }, + "overrides": [] + }, + "options": {} + } + ] +} diff --git a/demos/kll-grafana/grafana/provisioning/dashboards/asap.yaml b/demos/kll-grafana/grafana/provisioning/dashboards/asap.yaml new file mode 100644 index 0000000..2dd466d --- /dev/null +++ b/demos/kll-grafana/grafana/provisioning/dashboards/asap.yaml @@ -0,0 +1,7 @@ +apiVersion: 1 +providers: + - name: ASAP demo + folder: ASAP + type: file + options: + path: /var/lib/grafana/dashboards diff --git a/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml b/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml new file mode 100644 index 0000000..e23f52d --- /dev/null +++ b/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml @@ -0,0 +1,9 @@ +apiVersion: 1 +datasources: + - name: Prometheus + uid: asap-prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: false diff --git a/demos/kll-grafana/prometheus.yml b/demos/kll-grafana/prometheus.yml new file mode 100644 index 0000000..d8b4a57 --- /dev/null +++ b/demos/kll-grafana/prometheus.yml @@ -0,0 +1,4 @@ +global: + scrape_interval: 15s +# Estimated gauges arrive through the OTLP HTTP receiver; no scrape target needed. +scrape_configs: [] diff --git a/demos/kll-grafana/verify.py b/demos/kll-grafana/verify.py new file mode 100644 index 0000000..fead757 --- /dev/null +++ b/demos/kll-grafana/verify.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""Run the real demo and verify its estimates through Prometheus and Grafana.""" +import argparse +import json +import re +import subprocess +import time +import urllib.parse +import urllib.request + + +def get(base, path): + with urllib.request.urlopen(base.rstrip('/') + path, timeout=10) as response: + return json.load(response) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('binary', help='path to the built asap-otap-demo binary') + parser.add_argument('--prometheus', default='http://localhost:9090') + parser.add_argument('--grafana', default='http://localhost:3000') + args = parser.parse_args() + output = subprocess.check_output([ + args.binary, '--prometheus-otlp-endpoint', + args.prometheus.rstrip('/') + '/api/v1/otlp/v1/metrics', + ], text=True) + print(output, end='') + expected = {q: float(v) for q, v in re.findall( + r'result metric=request.duration.estimate quantile=(\S+) value=(\S+)', output)} + assert set(expected) == {'0.5', '0.99'}, expected + query = '/api/v1/query?' + urllib.parse.urlencode({'query': 'request_duration_estimate{quantile=~"0.5|0.99"}'}) + for base, path in [ + (args.prometheus, query), + (args.grafana, '/api/datasources/proxy/uid/asap-prometheus' + query), + ]: + for attempt in range(30): + response = get(base, path) + assert response['status'] == 'success', response + actual = {row['metric']['quantile']: float(row['value'][1]) + for row in response['data']['result']} + if set(actual) == set(expected): + break + time.sleep(1) + assert set(actual) == set(expected), actual + for quantile, value in expected.items(): + assert abs(actual[quantile] - value) <= 0.001, (actual, expected) + dashboard = get(args.grafana, '/api/dashboards/uid/asap-kll')['dashboard'] + assert dashboard['panels'][0]['targets'][0]['expr'].startswith('request_duration_estimate') + print('Verified p50/p99 in Prometheus, Grafana datasource queries, and provisioned dashboard.') + + +if __name__ == '__main__': + main() diff --git a/docs/demo-guide.md b/docs/demo-guide.md index 5985e4f..b6eeeeb 100644 --- a/docs/demo-guide.md +++ b/docs/demo-guide.md @@ -68,3 +68,61 @@ cargo test --features otap-engine --test otap_pipeline_e2e The runnable binary additionally asserts that the final output contains p50 and p99 after the four child processes finish successfully. + +## Write KLL estimates to Prometheus and view them in Grafana + +The optional export sends the validated estimator output as OTLP/HTTP protobuf +straight to Prometheus. Prometheus stores the gauges and Grafana queries them. +It requires `curl` (7.76 or newer) on the machine running the demo, plus Docker +Compose for the bundled backend. No additional collector is required. + +From the repository root: + +```sh +docker compose -f demos/kll-grafana/compose.yaml up -d +cd asap-precompute-rs +cargo run --bin asap-otap-demo --features otap-engine -- \ + --prometheus-otlp-endpoint http://localhost:9090/api/v1/otlp/v1/metrics +``` + +Open [the KLL dashboard](http://localhost:3000/d/asap-kll) (anonymous viewer +access is enabled for this local demo). The dashboard provisions its Prometheus +datasource automatically and displays p50/p99 using: + +```promql +request_duration_estimate{quantile=~"0.5|0.99"} +``` + +The [Prometheus OTLP receiver](https://prometheus.io/docs/guides/opentelemetry/) +is enabled with `--web.enable-otlp-receiver`. Its default translation converts +`request.duration.estimate` to `request_duration_estimate` and retains the +`quantile` label. [Grafana provisioning](https://grafana.com/docs/grafana/latest/administration/provisioning/) +connects that datasource to the dashboard. + +This is a finite demo: one run writes one sample per quantile. Repeat the +command to add samples to the time series. Instant queries show the latest +sample for Prometheus's default five-minute lookback; the history panel shows +previous samples within the selected time range. Values use the demo input's +units (the sequential input is synthetic). The outbound copy uses the current +wall-clock timestamp, so the synthetic 1970-era window remains available in +`out.otlp` and debug traces while the dashboard shows the completed estimate +now. Original gauge values, resource attributes, and point labels are preserved. +Series labels stored on OTAP scopes (including `quantile`) are also copied to +gauge point attributes, which Prometheus uses to identify separate series. +Only the `kll` scenario supports this option. HTTP errors, invalid OTLP +responses, and partial rejection fail the command; no automatic retry can +silently duplicate a partially accepted write. + +To check the entire path after building the binary, run from the repository root: + +```sh +python3 demos/kll-grafana/verify.py asap-precompute-rs/target/debug/asap-otap-demo +``` + +The check compares the printed estimates with Prometheus results and Grafana's +queries through its configured datasource, and verifies the dashboard exists. +Set `PROMETHEUS_PORT` and `GRAFANA_PORT` when starting Compose if the default +ports are occupied, and supply matching `--prometheus` / `--grafana` URLs to +the check. Services bind to localhost and data persists in Compose volumes. +Stop them with `docker compose -f demos/kll-grafana/compose.yaml down`; add `-v` +when you want to remove the demo's stored data. From 46b22109aa33af0dc191a40f0f835818ee341b61 Mon Sep 17 00:00:00 2001 From: Zeying Zhu <50204836+zzylol@users.noreply.github.com> Date: Sun, 4 Oct 2026 16:18:49 +0000 Subject: [PATCH 2/4] Document KLL demo before and after with captured examples --- docs/demo-guide.md | 20 ++++++++++++++++++++ docs/images/kll-after-grafana.png | Bin 0 -> 32040 bytes docs/images/kll-before-console.png | Bin 0 -> 61666 bytes 3 files changed, 20 insertions(+) create mode 100644 docs/images/kll-after-grafana.png create mode 100644 docs/images/kll-before-console.png diff --git a/docs/demo-guide.md b/docs/demo-guide.md index b6eeeeb..9d387c3 100644 --- a/docs/demo-guide.md +++ b/docs/demo-guide.md @@ -126,3 +126,23 @@ ports are occupied, and supply matching `--prometheus` / `--grafana` URLs to the check. Services bind to localhost and data persists in Compose volumes. Stop them with `docker compose -f demos/kll-grafana/compose.yaml down`; add `-v` when you want to remove the demo's stored data. + +## Before and after example + +Without the export option, the demo prints estimates and retains local OTLP +files and debug traces. It does not write samples to Prometheus: + +![Console output without Prometheus export](./images/kll-before-console.png) + +This image renders captured console output from a real run; process launch +lines and trace directory paths are omitted for readability. + +With `--prometheus-otlp-endpoint`, the same estimated values are stored as +separate quantile series and appear in the provisioned Grafana dashboard: + +![Grafana dashboard after exporting KLL estimates](./images/kll-after-grafana.png) + +The screenshot is from the running Grafana demo. This run produced p50 = 100 +and p99 = 198 for the synthetic sequential input. Prometheus and Grafana +queries returned those same values. The history panel uses Prometheus range +queries; displayed steps can repeat the latest sample between demo runs. diff --git a/docs/images/kll-after-grafana.png b/docs/images/kll-after-grafana.png new file mode 100644 index 0000000000000000000000000000000000000000..9394e907ce8f3e9bddcb73933b6df259f4b7bd12 GIT binary patch literal 32040 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 literal 0 HcmV?d00001 diff --git a/docs/images/kll-before-console.png b/docs/images/kll-before-console.png new file mode 100644 index 0000000000000000000000000000000000000000..c379be8c69cf1eb8df3b0ead4c9cbe59e543636f GIT binary patch literal 61666 zcmeEuRajJQ-!F=Qk^<7DbR#XT(lK-O}CN-7&<_F?;zu?|Xem z`(PjLeeHF0Uu&2(%pL#u#RMtJOJblBqaq+6U`R`eDI*{tWgs9R?!9~t+{q^z$w5GP zjUX-dN!2ywXc>$Qsu74qa6S%{#68IPWg(3jLqO{^RoFe>O(5 zmE1O`fo7ZT1uqo1*%}Ea561_ujW1_sOtUr* zVCXyKzaM{781gC%XIi~ToXxAn9kiUnrrUVcd2}l$zBgIC*qm%=LE*(9y+zw^zvHy_NU4`(+fGwybyz{14*I-P$@WuD_w- zI=ZTG`@7No?vLA$vr4QMLWBrqRVQW_0~2VP-tOq*_kT{>e!m1=HWCsN7P)XD$7BAF zE`{L^i2!7|21|VXmbcqsYmjTfU{DnjEgu^OC&(j_5w^Qa)R%lV4tb zI=-2&Vm<_t25skQ6sdt>1@CHkW@74aCpXR5T@Pk{AXTYbweoCF#euL6z zCs0yo)qTCMCG!yLb!ho~vh1_9eD7kb?KWGac6c6p=wma-k)bdeMy7qZzyG7<=fnQ4 ze+8St*YwJoii3&5l34!+GcpWrZtiYkRHDSheapmfUtjg#^D&WW?I0~}zk|nb)=Tem zSG245wN0L!-6Gv>2m;(rOI2XwGd^@u{;EpTsZ5S4=ianQbJm#ptt@Igh^Xk}x+ro&B2h9S(a!F+qb2D8ltwM?ynFF)S+#+PpPAMjE8{?!tIck{DGal?6>~T4Rug-0*CY${umDuI@oc5QzM}8OT zmV*#u%rn6QaV&!7@S9=_IepS@OOfF;?UIFj5J*;vJvLazmbHDnUdd0q?MYQZBk=xZ zD(YmhUb4DQ?eR*hwLwtTF%a`6Rz)tW2P87(#3LYvJHv_N`7XRCEdC#zuIx<;pc7p| z=VaZYOZEecgL-9YtO9}-AK93gs(R!x=ISoVj_}!%cpduU^Dk_4>*Q2KMPZuxsTbg*4 zYW=-r6B#t(d#aN$pPc1}@~QFHDhsu94{AZyM>ZvMb*g6gj~u&?_t&$YcI?|@ZT8{) zxV=Ajx~HbpNO+uV=Cf|u+E|+Q583!DG{D!UzjkL;AGp|UU(3XmES87f^7ai5j;07_ z+Cxut6WO`O@(EaSBsn#LTlU|Zw>C98*U*2@Eh_40%`N)UnJ%SA z^La3oNl(*j`1A2iYPsEfz4H3Sg~8yr1yvvTW&TDy&TBNz$zc+WphUOJgK2a5^gg7( z?(v}eol7QhL`2Ngc7;SPv$1b0L)VnY9k9bmQLd&>bd%%b6%-=gCQmeP#1&un)%;O` z_*H(eIPvMN!^wf7EJAH&b9bQ_Owsw46kvuD-LB zkQ5yJ%jZ6E(9U7-JrMDBR^Qv6*FSlA#A%w*6Y5u6*T>aL*7Fk=; z*?f=tS{6&{nv`%-euvGt)FZAoR&9BW&5f!t zGz_8;L^pz8vR-(Zs1Es~X&|1ggolP2|ClXSNaiR7av_)8ak@MP8C1kou2V8BEr;Nq zL3orYw)UfPM0U1HJXx#j?E;WT=333@sYI1fxz{-H#MD4Ef*c29>zmWt+bFQZ{vJKm zj{B>Vr$s1}%)`&F=W@wE7prJi9@L0sc$Vw;>n!@MWM#otjON*UcbJfB)vsmxoD=qt z0U}W1`y{fFfq|9A$I&W+(ka#7;~k4&*w6NA%9y-c!-F4@#`%?#W7@N&C0&^2X03}Y z*JF!y(#!mH_H$#A40ZEhpKJnwq22!9$jI(39uUL8sw(gfys_&Vl9Amq3`O(F%aWxM z5=v@p^{I);#zIQ$$oel@5jW$|Lt$V za?|$CxUN7^_8!OqPnvZsO!tFc=X(4#(ed%-fj-)&_sbqwmT$SakJq!`QXzVgkbJ_` zYT{w3cU5M@I9RMo#g4ERuH&)ArdE$qQO+B>+25F_vbnHd>>B(}g`E^@m*IZ+IAh*^wipti;w>OTCA#__#g^rud4w7iVP+ftD(C;FJ_T z$uXX5V@f>jpOUzp4RJ{)qG~@LSj=t<-yh9`OX-&BMnCV>ICX31`6~X97LSbkfvt<^ ze0bFFcjU;=Ye~POVub48Hs+nk3BL}3h1~GIA}G5le@8*p%;xutE_Y*RLR0d3QZy0* z6{{C&cp`KDi5%P^0% zzw-HFB)gi|SM1CQuf}$&EtgZsT%%7RJx8}TtTyXVCI;U2fXC2O;=Mf! zf`;yZb&a>VLaKw!?>!wJixi)}K5S{(JniL``AAvJHTXO!tE!s3NG`?rr}I4Z5s$M| zdN)-h@qOUCm(CCfR390aPI9f^5@zlv4V0YeE6Rw4Mi}A}?pg7#;Zzgrq~bv~VqGtx zA@pZOt}~UfhruxQkGI%7eNNSN*%E?~t!-;wvHXSuaP$J>yrC>w)kYOacJQS;@lY${ z7Iu-TX2M+j*Q0NcW&S3}@5AvDV^DXc%~o(!{PliP%$l9_;`}F2~deftd(o@u0 zM(pu&_F(IBGHcr7B7CMhAIods`Q{I%o$tZ)psP-FH4+E2pl|Y*ql9;0pA<7|<8DvH z+0s=LG;+5`{wK(q5JXc_=XF`!6$3j`ytr%?{gwFRa?WmXpO)vHDUdHrBcd z5vaI)PUimTC96>S6Hg~{L;|6F$@TW&Qk^A<(>Ls$)z#sopZ*l%p@)D2w7qkC|FHV! z?3sbH&&>|l{^xY@APLa{P+H@|f8IRTCEurfr&ZhMN4K>#pve#vFh(O>8E9%~=q^qe z2=hiAHSjQe8axpi&vRp4@H-NnorlzD+meh#=z2_+UW^OFYq-SF2=-7HhTdEUx zu4?3|i2QwkPJk4~tohIdq3ri9Com8?pwZm=P+9%H&9z}K^{Xdpj%uKl8@>c36BGC( zD*ehh~Edzm@3)X$5cMtJuJ<^rTXZ3i+zAX?eh?dP2fb1Ru za}tsKRE=&g%$r-O9M#5UO+pk$>S1EK`*Yt(#h{J66VYY%npZ8r{}ra&Q|A#P9HwQlcR@gj8&5OAs`Fj9+~Jm` zt!zTg>Yyl zL9nXq1Y)bD;wAnW%zF8?+|rUL1QsP?&R(Qim{n3jleDQgtGF4k>g}y6iA{ml?W`6- z@0dhFPIS30+8-}SP1|hR+EU3fl*=Ui%;kg|>|#4r?rofZr%MIaV;S!LwIh5?u1w9O zN>or-*!Y3hD3HP3pxWv37ENQ$x|w9kWvyhfp^FeBrweEn(cKwW8<82A}6F%D#Sv95oq zym3Jzx21F@UI4WB&1fJPo_Pl%kbqhJzTpLcizu1o%JR4A|4qfOFvojLLPx*$6>F50 zFe54W4E6QxiCA!{WNvKef9>R%iOX7VZ0PIcHV_lznAkkAqzlBP5b@l4aRFtx=uos; zJ8F=HWf@AMG$nG<&bX8t|A=?+;I)UGmKn>@P%UVQN=YT`C7m~;er)C-kgAo8Eg2#o z2#4)Y+X8L1&CyiHVD@Jm(yY*R@s*zD5Mz@irpPsTZ$n#9-0nsJtu#p1m_pGg13qoW z&dF`m+B92+JNF{67NVD{&Ar+J|MNIFbfh8_9g&a_uhAag60-`-MMp=glgGM+IhFT@ zW~7mB&iyMAYc#tL+Bv^ME7!q)>y?!@xFbk6R5|U_lkS#wRbaTU+3>CZKX6Lop~(~| zr_;0a)#3IoshE%+8J5fJMtT-R8_R_tPtM4|TiU_taOpcq9xOP&i9{eJI+{s1i4g=8 z9=yzVIS5Js*b)#xBRJWg2)q@ME;W1niL0cQGJ9Q>FwM2f3rJ-_L#e4{@MpCW_$QqcPRX1t%XfwWkQZXN? zvOkR5awWie~|Ety3d|{ch#pxG9F9C3Z?DJv@ZfCwqAlo25u1?R3Kp=o666}CF z;<+02Te6&)4@K4Suh9uyc+E@rle+Vj)RiDbKh4Si;?I4r=cOFVQ$xZC`M=zZJzMJg z*+&mqy9t_H>ND6GCFk~x@M|gYEngq(SaRB1^Ue>aAmlcBuR=R(cjKr5cjtD28*f9a zsgD23 zxWJ$Tv`|zu036CAS(p-=sd|8aB8TCWNH1mxsqol2SmQT09^PWj6VCUX7^l(ZJx*+f zCyfH7p1|0cd2l3;Aqf*2XSBjH1>|^XrAkZXEIn7<$*vw8$U`GfW&3?RmTVJ+X9NVokfYB~DI?c7% z>iLUMT^;X!ocd@mni*sLT0VupSIEI+VXH!gE_8ghSdx1sO8lbUQvMN~cFT%J6$>OJ z!BoEM?L?|Ud^XMIQ}cy3r*bFg!us{ZNfsqCTg1bBIarq(mW+PE7>}dMf!Vn%KG}P zhKToCoV4je-sKH}KTt7%rC$@tt6a^h1Y7rO?9jD>_+8df1w04YPWR3xg_>Nl46XV$ z`1fDO-W7x>)W|8w8dQ27A8ez|*RklhPRKg>=4@@@Sr4pOcaFBP-rkSNUs?Lbd_0SC zLTdk;+Su9IQ}}~6Dk`8N&H4Cd#-fOBw`?q(qcZN^wrk5MQz3HgJQyw(v%&gHZHX9oB1r6G(!e@Q1O_YVdX;p9hK!A7+DdGz=zsRp@FR zT}$v#en!SOl9ejxmooCyc`noA1sUB;8Ch8k7KSwDDuHWqEv;9j92qU14y!zN4?w<} zH1{4bSn@ed7?6Xe`C9YRpK&?fymb#6pvr0kb^%8f^O)~VZc9KIRJlP2Sx0V4uh{BP#bRAFT@0M$vDE!$+U z?SjyY8t`8CTEdLr&cnMiTl?U-^~+?4;?vL6kgNT&3m+3;xe=bA{c|jgzkmNeGVs=k zOS+>G)2(;io;mgqOF!25&Z>8H>%8tb-n7BD9;uYwJDNfLQboO@;%lcQ2;0lGx2-@B zO>{lfKe5mPvUxfl{p|a7u!6L}$%DW3P@C2KfOAZwVPIkE{K`yHCCMB6qZP2?0}8{R z*DbVdT&AoMQwY{3CU1#3a`VlZ^(zAkUp8HnyE9DWqXRu1@NcLg2?t$~tT)Uv?DJWV zu=PKX`+e?@Y`E|l?eE7UlP=^9CP_pUPmH1bUk*X$W-(99X%4obFui+f{c7>c z>4dXMHr=QALx3Md_$DK6#!r;{@Y&2=LfgFuWB^AD49m;O3x0~1znrmO@V;HReCFjr zcyM^QKbsu~ZuisM#HGy2N=Fi5GvC}@?S(hMPtV5M9}63X<}~5UO}`5Y_Ief4Y!@r? zrM{^m1Bm-QIw7Bpl!&Bf!Gn3PT!L_ckNs{B1~=FAw5nRM8q@mQ zsG^U`6NW=KMEb+Y+6l>tgd{~pMO(YObon{C)cH%W3z75dS0`rojspWDX#fF|+cuhS z^uWWwKn?3Y!!<9}ZEEj(E}Wc-z4PG#5gJM?JhwEYY0#Dy2GL`TD`c<)uwujY^<7q7 zywsZsy!0U#C^F`rt*xcJz~1!X4b9*zK;y9E1w&Rd3^xNXj_obY^74wZvWj$#!WmVg z$Lj7;R-jXvHHC#0X{C0bjVQ@vG)k9$M_BXbXcJm`9m*VC9^L?04bWP2PB%n;&rHi~ zCEr$N`1%?~eKR!wOPtpG^nHPOdZw`?R#jCE4?FvBS`8KsMt&~lluG1n&jJ-9%;`!N zbiB>2n5m#mi9LV_u`2lL5{-Ap!*Cm@b-`A1ZaJOR(5f#aD(WROtGtbihbv1H*m^g$ zk6K^y3fMXy15}kJOTV3vAY?cmELSnPC=3831S!AnKDpJuEU)4_lXHB$zsK{Dd)Gq?XKSURzWoqdA9$EUcoWu3x>UQCl#1xbk>EuQe}6!)ZDoh81pB zXMfKbEAb0|WwSTj?QUzo$puPS@bdh8I*vu>cUBe-DQSnQ`(WH-sg!COK(YR-3n(ce zdjtD%TZacXWgnYOzrRRHNSNE&dh-uf-j=Iu(9Z7FGlj<#he<9N!GNox5)CNHve_k85mA@ z)6?47u6(Q3x31eCWFX1y%*}|5jC?m#hkbu;YGGj!&zkygf0Z(jyr!t3F*!cteScNb z(BKx!s7AP-n2_Y^!Cj_RMXNH-!O7YA!?6bn-}x1~u##s`s-c!z-&Q z312Hk82rJ%oT}zRZmobil&gAgi=;65%~$Q7tooE!!-EYZ)zs7&k%5M2h!=bqmma51 zCMo$ZP0*HmPW$2L_*mHc!S!m%pP2j2Z)O(4Z}vU&x$JmVDAyG45fI?cZ2CX)&2yR> z`8oe?J~+#C!oWb!!X0o>Bi6=JmUMLlnj*$_#cAJja@tPj)dU2%hY|;|K5un=y zY01d=D6Vz8>n8FwdN_&Ck4#F=v&pEN5#l-!6Et1S?T4(Lu0?v9P1?u(upz5 zNMTLbe?nJxbM~SmnF|n~t&WFkhW%{->xiA<^ z5{p8w-Zk-2W41JvgsVV-q<3b7=gf9vJiGV)@;JLF?*O{%^VA`3hiSW5?f4rib^INu zXMBiATwrr&*U%NtW~HIk77t!3W2*J%CW0PUM?;C=80U>RpSkjPC|Hk|0J@$`u(YIW z`Mu6&9v>UK-<)kIg^x-^1m5n4Qd(MCU0GOIs8Ocp;Q)Vk&2ZLKsF1E7O3YWWY3cK| zBr@w)S9EI0ao{yHJIgpY1Ug?8SOwk`fdl0chzW!->;hdCaXa6F?Ss)TB9jAJUDp0Q zp1-7bx>&4^OiX+h z*V=vz!~!ZdAWZ~^K5~WXayMKZFO1KqD=FPZTnckg9?Xs7@--N+k`*asBM+}mbm;2o z2~lx!^3d+AXJcO-TY3@r z#4lH@0G=3|3JD7ncHFWsGt1kni-9zQaRJbB(kdxA(QJ3??nW2u%Q^N&=WxKY*G zX13gr7Su$?Ku;m&&bbp)(epD)j*4=>J>MQ1dwdJaOgQW&DYfU$ekrrlhz; zvBh0k=6sl>?qvDCn)i09Q8m}YgWEiiLIji15j(KUIYr1LFE0;SAPV14|LC-=jdg<` zjD6AcC+cRf!yOxcrQ8s)XshZg86~je9|Bb;UZAAr6BCiFH1BI@YJOCT2n|(>e5Jdr z+vsw5NBi!(FDYsWL+w{bt34=%l=*j?vS(Z%Kjbhc9_dINq+J*fFK_(yHRsC8@aBg8 zYU6ftT$-Jc&C$*dht*VHY_a<8_6|GVccYL@QIyGZfKvNhsLsNF#`18Z4$vfXnLEbMiXl)L?KbovO74|&F$7Rt{foaaOpzIvUA-Y?}qE^HJm1n z*2hESldeyeM|U>`uRo{qJ14o--!C_&CdJLb#qD_gCX{!Z#IbaaD^ad-`#F|eLAfv# zq^))ANT81l4M8X2wd)E;mJ5Y!i9wl*Gw=wId>(|!u zU{MIQx(^3plH#i1g25`R1=+XZgzPCD3HR3&ViFQcHzu~mCAn((&v8jt@V=H;+b+`b z(8g`B>*Hx5hgx?hWVXx@D?sEZsChYUND8A>uCT+vVNQQ@TqVL2Kpr#>2bP{R~$g&7#gxR z5)exF`ic<~6Gzj6`bL@Rcfc%vl_S&sW(64;Yr8JVsUM9>Jm^mC#OgC>iP()S&TeIO zd#M7$`!qDhW@Zki3aPv-9USNdgby!Dz&Jhx)Bt;7(WYX^Sy%3={L1|^60qkB=wrFs zKiN9HfhfOie@UFAKc}ffM7RfL37z^OejL%?-+wq``$fSvT?p+8>*dfOHhNVH^4Pb` z$Y+nCVL@)mH*t{@J0P7ZuyBp_c)ydfvhwwbUMew9Op%sm2++-{Y+hWI2ym{xN-D&~ z!I2CjWxf03U#i!n8e80GHq5ULa+lrBuq?DJ(Wz_xdZAu)DwmWZ?3|P&%^=o4%2w}m z8(dU`${mrEkdTwJlz(M1Kp-Y2=4tgA-Ti$15yk2|?DVwWJyt^`DTXw&x^G)n!(zl2 z$@RS2{qg`4^XiStSrCca36d3wNcm=2K_5M_H*D`r0c=)hHScTgOZDj|GLRCbKr=_P zvCsTHs|ova4bntEQQ4wM)Dslw#q-?6GQEMD{FE2PXd8?#$ysiHi8i!5u2vu|$Ryw~ zxN~eH`@!_k`^Hdv5mMq}1Ao&}XT2B@g&Fg7+D7&#>=k;ms3E$*(f;};Pz`11oI;ui zR`Lf+L2+7}P7W5nT)3}q8Y%w`!9BJQ9Krtpb;&m|F#$kDl_R7#=h=mYdFjdisHULu zY2x7G%vZ{I7*qsMnsU+G7&nPw`!rWsBy|SD&FWs64x0@pjgJ*RgTFvYS5u6LH>hxC zYCM1+gR~JnbTyariSgN@4j!A2DYd21a;YGK3QS~Bg{Az zI{0nnk5R(lm3)QtiROmhPln^$ZXagHr*s<}F?5(38ym;?7c{km@a-T$z}B=~sLpcg zDb>@V^5@1;bFVTV&C$LdS#HwB6qhTJg@f>Miw4zR zmyb=?4Q|T1+3(0*C`V9V;Z^4--IJ?e|A|TWR9y^+~wKM?zfOM_A*j z8r{*+5r1drNJra+r|&i*Ha0Cy9uX?y`Q?XgNXQplB9-VP#7NmDC|dR#t18o*%uqQW z=n5QXaftw;WN2hIpqhe3AzVI>q3$a7!c>is=OM13_B0buE7yhX?#S{z@54j)FRSSy zBK*aW>aTOl?_~5+7Z%if)BPQ0Z&h4z2?)$hOu9hEc7|zyP|D}NSQjC_v$C9Pbfh1@ zMJ(O-3Jbcba`t6)XB%&8ds{_{ZGkg)&lX9m<8YKggkA#_Mxs?gkgL(xj>G7Pr5#m1 zXYCo*a!U%Wme3`Ax;oZzmrYJv4;^I`lMn}^ovIU(I?g{s6h*x2q5GsD!X^i?sL(lJ zlnJ5Cc{gI&e44uQhu&!47|k6b*-=n11q% zl7GiGs(fN{>`NKN8-qh{>whCWusR42yJ`TSoa-+RXnaaaex>z{&y#pqyE9zBiI<%& zGGH~!>=JwjEHh&K5$;X5G9p_)#TgW{?6O`N&HFNyckDV zH#aLz*(z%>BA*fqp;TG?ePH-dFX{to5Qjfm86zWO9MAW?&y}6svR`KE+**%%!zmb4 zg&{{`k!SPs2Cb~8Bg^LP??O{jxVWZ|kB))T+RN)vK9zqMF48x3JaIoK* z$?~6VeMDh8=(*=0Wu7<@6YljeG@NJhKc|2KU^WnLU|Sb7x{7n%)j8m(SY8xL*HNmVY}c3VDU8 zBS3Q3WW9UhJGxuxd|-j{wfy^)Ltcm9N}`67dBeJ*b%mDw*QUVfRf~L@;^C&L$;im)qk$b97--9Ia&S~u zf$1@s!EHDUg}xGkR<2vDb)}gZABnPVTwCK?a`N&L69|io3iEQkt+1vhiaKA~bC|DI z4(Cr7_k$^vRG9Yj5GvL!j~8kz5girGlnC_6JM>&By?M{>k^AXO2L}gtSwk7*^+Zz- zzxpkM`f(=Zj#5-q63eccsVt;4M*D}iPdGC2%+~Qx)nsh66=Y<1xHvq|Ho7G%n530Z zJuFB?ydAHOD0FpGe!Xx8B%~|4ID%H+gS&~%LZoZNck!?3NSBh4Vt zw1-E!Eto<>j%K9zTu<+~IJ+h+FJl6?D~1B11Rim~~NL zNCx{a7SKQRrW&O5QtyF@V}dg#R?UjZ>n^^yxXL2!v;2n?K(kqS&Kp-J0X-fGHR)8cci?&@B&$%ZJ)!k|5=1}n#A&`r`SjgG zopQK+VuFL8HsEmo= z7A`|JeMOot=H`Q~xwdwuw%t++5ABr5>1y=m(wl|Vez^zvG!M!gIyEqSmc|qgiV>V} zq@c7wVGR`xP7WTU)d{m4ucWxRrvo*lRZIqNvUwd3nIkgM4XAII0e;x`@7{oT``51N zQ08BFO;tYj1QnBtii#gCAN+MZ@{KQ$wE=Oh%GO5~?*_MqT{hjl`KtREXf`^){(siwMG z*z?BG?{U)n-3m){AO?y1?nr8pS`kpkn6$Fp@~`~)_JJ=o!J_yW(!paV!lcQ;-IX=x1f`oUAt^sMR3Z}~~ho=bxtNJy+v zQ0@c6$-#OEKosa{_1s^|IqU8C>~3vseZMaH%8Md+9xde5{hnN?vAD1(FE7`P%UVKd z188;Y;lZmQQbrOCk|`)a7FkFYd|_)28};n9W^+gr^parrtB8De|HhA!^yrx0DaXFT zr98j?;lb_#nsadwYmJD4K`3B1#bO}RO&qMRKg@6@M%D1jZmD^`K&jJCuSxO#>euPd zhh|R_5~hXaUWJ$BrMGKOq6Fr@D7Jrjacx@|LL_h? zJvIrH6hI;Ynz1(%4p?&UE)N9&g5T}@Xnt_+1E8e_pd^((cj$?bgp5L(@G-1Zv@C6T zG_@@v@r+eSDAkMnN0*NXkbBi$Cz^DS}d?4pyc@ zu?2^?1HzJj{(K2Q=VvaTHrUX5mpYjF`SYYk%l-zbN_lxD>F7c^pxFiDeKTZu_js|a z6jfbKg`1aGL0;bbQfBON3y=n6Wo4mRB_%s%uyKW*ve)1d;J=yRJ=n7_Xk)F%S?tbz^?2Cs z7s$2L=qwu?Nl8UXWC*=eD^|~)Tas>Da@9xC~j%d`}E21vrxyg9EXFQoU@FC0VOTiW%Qgaf{ zB^$xH{s&Uio?J73hkWM_fk47kskV1h1w5WcQWc~PgKA2{N=I(aj8jsG$BF?g$?CxB zsJtTR?Rcj-8DGrn!fds`i2+ttu1|;}B0hKGU#K5h-wS$cX>xs1;jOzMU~MfNdkXj~ z4S8}_`)jiM=F>Tp$Vu;0VK%IthhwqYN+v$i#-^XdG7)4vnkJNzN-}!y_H2RgSyyK} zrDy;aMOJ2JgX8u=_-fXm9q^cMJ_@Eseu!)LO-}n9HLJCZGbqmx{`dr?rKQ!>T=qxj zM=bySD|p(#%^SRLP&NR#yCgi1S ze_#K5{eL$fFbV%Vdt>uJ+8SUrIp2#ECA_h3@VFmn_gcJ><8z)!0F<6BElKQe2gBek zyH}wXLq4gYHQPHFO!j(0qW*FEJrc<1-(mn!mdbkOs_;J+wVWSJ9}u2Yc7~EZk4J)W z>5yBSwto?DS!u$bI(t2?DKa(O-2tjZyAGE1C}8;?}eFmklR_f8f!R=4{A97~bd93C{|a3Mx4`IO-kt7q9>x z8o?9~hnUChE+xLA>>p2Bgfb1tfm!RO%H_h04$fzgA0}be(==EAVOK(aMjcI8sAUKI>mLc!zM9fxtqCI$5bc?E!_(Vbop-{~%!U(E z;?i1ed&!B*vWlY8;#jADZ*6S>x95hIfr3~9qAsr~wgni6!pTL3pXze!%+c7etVz&> z^p<(;ang_i$pt+hzK%^&ayEExPc^wv1cau1upRgyiJ~*mAm|Qrg15KX-`!Q=I@zo? zDwLI)<O@gvghj-dCR^!TP_uOjj~e(a@naGh>C6kEBDLWfCx_e{kHXFrS+VW(s45{wKD*g z4N8hj@;-;%hU!2ZaTAi0Qa&`sd&nLqijUkhTzU~dG<(cq*7C#!y^{98BIR?0QB#G! z^Sf*0=jC8$SJhAfq~_iaTl*s-Sj}$H^!%Xskz)_1{Vz5q1)3`C{Ipkq%*Nx2A}rje z^Qo>h&MaMjnS^he_kDpzc7TzEMS{=TvdA_0K!5-C&gsocXa?PA0U;I{$Dj5Qej4s$ zsBu2zXkk>!@?fh1&>I5qmnVGv@z-fVIsx+zem0=vVv2jx-pJRkIcz^R3Oa1Ezotd; zSd?EzkxToqP$Qk){LuX8&;5mu4r3#~=U*F#?IAv6Q4P?*)_U!>ZlECTFBR(bLQ0N~ zZ7;wVX@Qc=`i=a6OHv1j=9ha3@u8^)yvl0ZQ+liI%&5j&pp}3+4Vg=^X(q@=eAaYwG1Sboy9Kl?HSG%2_9-; zb3vRTeV^Xt;e4TvJhXO`waeXDe=_~PUmWrLW?z8VJ}T3F-ZbErmX{9ak3aEOQBaR?qbFa`q4nSRwdib3+h-J_wn zpx}p)&)H_Pc$q;j=Y(QG=6j<(1m0O%b^M(|%Y7H9P{#5#U|!m}m|0UH8;|5Rn~FdV zyHaAWpp#FlsHr%a&c67Qxk)bM-68LAxglMoFt^@vAI@x0Q`%=V#uF42rdMfnJod?} zaHM~DuxSSjo*%dr_Xc&va{-ay8~i<=I1MN-s-pV+;Y_YynE^uT5sx#V&F^o3ud#=Y z_K!qb39A*U-h%J%cuHDSlqUeg?O#is`2>LJV3P6=$d~WcHK@n!02&$>sECQMx6MTT zyKM&LD3x@7L4wp#Kq=w~zSxsnXek8G1pcm{J&W;m15lkmsrRteitNBAE)Qa_MUa6A zp6Pa`=$(2AC7nSDad+sF(b0TO|8&Dw6IGZkyos?Ub}6~>!`yrd;FE|9$jg%eysLi! za!d*vD;ueIOeOK5x#EE4ifvPW|G;8W!sDE4Zk8?LzAr&ZG&)L!KE!Ypax$lGP?q+q zN=2`PKin@(Y47tdLqof}(L}VNYi{?hHAb}r@@0M{)r-?J6~LBKwsQiQTHmx*;%@Ei zyb!|3qn_;z4{1nzh4B+P_=lbW5|aN2+2W5Mtr@AZK{#v**MFL>H#c+pW=ZF&Xn-UN z$k*Dl-^MP~BzrWvKo=sF310=-&%dHa)~R*^8W}XQrm6U}L-M?=lVV+#3PaVb(OC%M%A42_)%jcA%F@f}I|}vZnZWd}gMhtbI5v z1bxAvIX>q0>&_d-V8CL^Yj)1%QNP@HR9h?w|zU_ap0Ndk6z*QP!HI3SQ@v#A7dq-(Z<@YPz>xS(h z=T)`@CIz*wst-4JED&Sf@X_}H<}rFBW_tSiV~T{>R8VpSIR7f1)j)Q%&xF7)3`8t1 zCs$clw?CDMfzcM`vpJEYE}e@amu@d5#7C;0Cls!iR%WMPaC@XoXJWg2qN0^p!&3tBC*>fjN7( zn>|4I;5#UBqxw7~C+P<*pyNE<@CVm$aTkh>6Y7u@v!*VL`?kCcH`)D?VE`RXB`M_h zx?^YOIvVb)aRqy8YP`;i;s$mYD_vfi#A`S_8fRGAtt8R>Mq30+|k{D ztu_v;QZtd>D~~Ex&UG1O1(=G_&z~8vj{u=K01*K8r3OptxPMP{`GD&$)Ee&beyu9A z(&XABvjM}d@@K#|OMBQo@?DLaM4ykGTIvOrf1Q*c=j;QV!F1s#Bs|q3E(-&h1>9%0 z=MmVO6oL^qC(sP)(DO!iK6|t#K2m=z88Ep(2 z3Gde)7Q+v`83qb6Tuvu*@qYAwfudaDBYY0?2&V3^(T>#&@Xg1Q=xXHn|xMX#=94v%dV|E#AS98K6!V! z|IS?z(58oCeiypOD${NG-s+DX;FCPVmd<4e8=@d6pENPwMJMJDLuIVd9#kvg|I$YY znHwMXUTtr)^sUGaC@P?bS2_@RfbhMb2KRO0#KJ!pdglGkngB5@@N){Vcn*$kDBD_9 z>qaq^whN?odh12(Rq^cEcJr^y>ZGozuAk>$V-^xPY%x7@(eY*xJ?i9BKm2u)+lU|R z9LPzw+qac%l`3Xfh01(@+vo4+%MquhMhm&l-JD8&DvhXJ0Yt`oI(GM~>us%qhYq<5 zHFq$I_PAi+#~Q*&c_OZUS~P;13!{7X4ri0ut;yqevfr#EM2g-4ZpPWj%_WnK;_M3J z07iOM3Vug^fdI!}Fj2*=Uvtj={rDPmdwW)3Zn{TwvX!=MXQncc4x|FUtug`RE`+B} z#!VH~0$Z!YFd;MA9$-INeIB+Cg8(%b(f;M(WVG*X?%=HBJO*Ww3jKtzM1C8@>AE=L z#Whv~_K)=^T9eV$dK;b864HxvBMTseu)sECg_eWkd+O`rf4)_V4Vn%KRv zC}kEqbkN%*tl;10l?9=V4CpCU+k9wn>wUB+3j+2l#2!q8;y{XNhZ2`&1$nOLI3Ms<%ck{K*Xu%#0 z0wa5x8HNC01w77>kqC&xZTv;AbEm2OkYR=TdTB+V6XCavrMn{rdG!lJLkVQrMMZKx z)>DdWI}(R9YT{E<)AM5=S9^Qofo~=mo_=$?T2WC^U0b^*LXk#t{NT@|i`QblYM@#K zAf`q)nK{ydkP^?*`(XX9YM={P_*Oa+Dwh97g-pq}vei!y$o9Ien|GmX|BJo1imGyb z|9+Rr0tKW?K)OM4(g;YGFbM$xX_%C>w1R+icXvtWB&AEhNyj9lyF2&I`o({bcf9Yx zKHGbY?TM~~HHI>uc|Z5{jnB2k8goWIXES@daVm646!<;3BLnc}eW54@wyPOBwGo`w>u>=I5V=O%!Wu zQ+wx_#VVdjb^&Od*-IdQqgR{lc*~sip_X@@yz@Xket7eb@bKSk?QLwv1YhPe z(a?Ar#5E5NY*a>umy0|C_)fOQvTVFA%f1QwFz~gJRl@nwceWZ?MGL|?>d_19@4a9PqL2ZcJeLT*~ zQI$frNai`X)bAZoxdq+@MGg+7J*z28(^~*1hKW4s-fZL4g`9?7XQv2;Yg@|;Y!Ch3 zwcR5F2}wz)nvH=GAvSiGy|5r8ah(A1xiDvI!z^e}>enqdC#U{n4LcY7d5=py@)m; zrFsvdh|@Kvx-BL$6J$OTLpvR>v1`)uqR9wZ-_^o zUnnS*(G#x`cf2hqKvj8UPWhGJCGJAk0izIBC}I6qhNg0#kJa~B^|l%6Tz3wRpt%5r zq_~KuImz`7mv$F2lR-U;sG*@d+6;`IXh{VRnm>E{4E9UR=jNc+Wcbw+Q=!*fp(?8s z2l=E7B*p}Ba&Us=G#Wa(p=$9Gy@DlDao`)^F* z-)^UvQSEJ1gL;kEg3O=_SX2@_jwH|P?e}v0WZZZK^O#x=t@o>6mu4pkVKJ9@IP37| zk${7PBgX~J?fDP3Ad5*lhFIriR z{XgA9k9?6&UU9uEPJHFtAzZOMJ28uvjVeGf{w}Hn*Bl1>9&4JTCEJPfvZO@eLn5!O z%^4YQn@DS`sYgy>DC1jm?tt8SN#L&@YaW5eqF+GJ1)syP1SL5shr_zgKIs%s>Y}4`uH1djrYTYsSOSX zvIuLlIjeWf?O#-k4Po&A8kSXqkndeIXUMDcGs)F-YchjMc50sCP6MF?uIr4~+tE z-Crp!=Ogm2j&cezB>V=H6W!kconvu6=g0BbCF8Sxd6;bBzdzAvfsYLzjSBv@Nej5T ze421r%0}hR^*nCrW94geJtZm=9){tyEp=IkY8vnw9BHs;TUZ zs+{$~SrjL9WTz6R-7nnSALlS<_%f)LVt4kM43k+B;16; z4sR-RS)Z*AZci4Av|}b6sa?39l}`vzdwIP3-s+WAK<}kPY{7(JXR3#HY|p>dm+5Eg zVbicx!2VHs2tFIDoN0OA!f>j4>cpE|wJu>^*$!R9A37RAYscgj73(jjM@Q>Ax*;6i zp5jjc?@Z|8@Qo-SJb++~B(Wt^8hk2_=^FzFvmKEb2-&C91sf zmfWle&W%s2Ov`aL=hbUzF;Y&H#V4SZJn}lZL_Z?k*x1C!#r=d3rdrP!DS(YdVxpn> zho%V%m~UEMelG|>h3M)jK^SS(t562~PDlg28m)C$5SeBs1|5GlC>ou+P%*QBX&Fff zCQGVEK2@W~n0mGA__*#yciQf>*Ao-d)0_Qe`*Iiagq^I6q^?LpP-f*GD^&>r`Tz;x zI;bsh7~|oPNNu%QONQq7CVX5y7#4bPED&DTd|gBpSVbf%RYvo28czkaqX~PtKhdr3 zDEW4`$$yD%AUM+`ues&BvnCLe#vizx9bx5vxe>QRybI|hA-{$46Qkq7o<9pK= z^{|{RrtrB1a6A(kOr#{LAnE_Q-Z=)e6SGHC&)WI-oS$ zh)y)xB5mn%<40cHKZ$6sW6$z?HceP6bN4qMyKakO`sY&HCBN;Q2ge~F0hJ z{WEi4=HlqdGyK(D@CIeP)d6OUANs{8!l$MNpIbODC+Eszb|sH6u5>Q_x!nBRY#k-P z(MLTs?iiBh+93IaWac{OuF0Ns%dLLm$x^z8aV`%qX_%*Je`c{!=zfLn(ba*OYe7)7#%aJ3Jgr3Y|wZ7g$8CuTN59Zedk6UqiGSYFHQwS}`!mM*Xqb zA=a}d=Q7gr^&4BISw%vit%W!MqTNW)nmi?CRy$QzG6}?TaxV9&;D5A$1?XudJkO1Y ze<3{oS_&V0@?YeOf@|~h3+acFI1Tr|%z@UjwzejaW_hP)KD%-?dA7%S(PbIUc3I(C zf!<;(V(wP?-R}lx&C}Cy;!W5N|4GK3Zlk-^==aw4r)MMYGzJFxOZPsS8ky}=QVt_W zzujqoksI6uDH4Z(L=Nn15F?tL(L|t@XZG~2q~7=oCBhwdC&znw7A}rHxoI;oF+B?$ z2uP_*~h`T95q2XTTxsh+G(~wqj-`Gh;w?~ z-8Perl|9iwR?BP=kxyEf`o$thndnz*IX_T>n|5OSZK7~;YU^@y`qpCHy1b$y`D_GJSC_1SfnhL&M0wS$9mv^jGb4<60r!{wOkO?) zJ~&`2G~LvTDy6Qj5$M)A#CY`CfaeyI>}m0Qokv?8mK5er{oTSr(S*(Dm|DRl3p4%u zn{E>);>**4Ee&DUYwB%@Y+WHz*@AakU)_??$pP7nNyFycsx^6bW_aojt56b{<=JzH{-^|#n_%*CI6%$r5&^xo1Z^9+n9zWhtH~8Z97}RfFo6VeE2s8 zI*2&f!WN{*&g(;FE{2xF9JTM>!_AKT@IV6%2tB%~3JhENjCQDzA=NZ^ABkUc;|Gt9 zmn`j!$=4Oz1qm`s2BYy++@Eqr8piUUKw$&)+iD}AHzg_4(EA^h=Lh80fVMMqlzPk^ zWG1CTlE%S=2s5>q`=ukHc7e#E6L8)$y-P|=AU9PspK99zmNdWP?ao;Yl^;ep zW2@-6^`v@}>&bX=<4n~l1{zu_m*b$4h+6ZvWu;*RIPS(XjI=BJ8;OHHzmO z?p{L?W)}qmvEJyAHOa4MyKFkmr>oVK^2T_iSBHC9dHjx+BlR&FApB#@G_Kq13IH5QPuF{#{qfPud0w-F+*aeTR)@Xxi-2V4`k1NdiM#rn)x0w-2K%f=LW2>^6 z5A4(a)N|w;q@mIl8qpP~wv{I6GTvm-tr1I zmP3lmWd3WrrRTk@))p$5H+WtEte9wYmlH~B1qQfG<(XkYK}LC3#_Q}o<^5u{P+z7G&Vi>;Fa9t44X4yaoRAFsqAv7hue&l zQYy=bicQ+R*o!^+>-*!Dp8Jje&q-x*7H0V!%O?aAZ{JE*JP?73#{3MOy}Eh0`+R$% zzjbiD2rjU)dTovJUHId9S|!0V5&U5jXDng57(4na%-g2TFoj?)fC|CJ!V`j>f7F`x zzV_al@POFND*!-E6F7mV$+v1IC*N~Bnt$kV7yPuoho0mleIgifehz86#2^i7koZ8^)!h^ZP*9xpnct(9ea(LKd$xP>saWs+gfQ;*hUMZlfP#r$sOr z?kHC}-ex+b($y%DRC3+&pW}JEFf-SxSJlAYL_tPTW~RmvlS;r^SAdihPvCRMg_uJOm&H!x>U%p}^-aQt<_rgUzz4$gRTSSMlz98 z3)iUdbNcmykZRwIueyp(yTFMW^RiszSGvE-e?e28x>^8#_~%!6e#O~;L9?&0{(nL( zC|~}6s6zSwtYG>-JlX#RG^}DaJG`|auD7c;k4R-m6B6JVb|*aNxyO}?IpOpqqkI)c zIkPgnr5RL6&R-ZvWKSq?=dZC*=;v`=ez7`p?p!MvElR3@&WJ5gTWol11+3i+8s&HS zgWwr^qp4=dST4~rxG@bE*VRom?H?o}N|3nS0*r{B^k&+wr$G0cr>6cU>}A^zSy&cX zJ0DsG34p%7>Zw1V#okeCLoSRqU3D@9TJS{XTmZpo`N>N_pvc=h4A|aN7i+iS;jd5i z?p_LfG%$ESjpCE~^o*P{+R9k%;{NBH{- z^bv}-HWNEkh0*9F&{w;5PqW2b;L$tU98yi(@beGCG^;+UvT>!@-1a9LuExJ@)@~DmW z_q3QVUg9~5pX%WJ-Oa(AzbB54&0H^kJwbS#>>`YBhd4oL>hoRe()aK5R#q$|7IJxh zp`AlNJAQq`O8rcFy~T@8&op6YYb~}0b1;}_xcd&IFCtGZS2xxh56^Lb=J}bghhr;A z^*rXAtAacJaM1N%ZvlSTePcE6M^-^WR`ChHurLE(3@HxiG*64)>CPLBGbuXB?izWOvAA)mN9Cj0}L9UZEgYB*BGTw=f~RvC*B!fDVltcf90!wyB^$AIpc} zwmI^T>1H-Nh^nQ$c69n3WqLf`2}g{F6w!u~_tNru#tZ2=^hLCzkP3O4%!CRBM{o7> zJ1ufeuyWZVdw`j%m?F6AM$5~H^zm0B{1W+{uVQ#)7$B6VD-E-NuLg_+_v5;}dY>qEagNe$GcPlyO0f&uyLU*+Iy~>yDko2P?2y_nQ=8 z3uV!MKyxFU%hpn@aGBW!|8!y!q8>nNz{QnLz6&l`Dqz^|K|lcv*rTUUxBeQ_hV4w9 zC8;G;DgI`pbSTY#glnlAz>7@Ij}wkqbq@4J#zx0nwsO^wPwucmqk?F`Ex=8{Wb}n= zdHXX@ZP)D%BB#%QUR!CZ_=mO;I*!$OXb@{RBHEC75M(ypC zDy9_w_!UMr?Xh|6!aqdD?jGJ$jAu0ls1sJmMk+@B*c6lhO(p}xJfO>4t`1wg>3VDc z;sy$+l$3_R*mvGWrp2UmD*T2+8$x%qreE@-jEKz+b%X$2q24vl5)#yXb1>W zZmu6h+ANyAo6pco+XVy5=4N3zyKPd-4LXSwf%i|_Xv@Gm2=t z_SSBG09e<6%9LjcO(SV0vu1U`4N|1d4gZzInWeO6jg0=#&4plR6L8w0dgLMS-axSU)_IMufo@=Z(Iu$jSF?f|#pL)g%e~sj*j)8S|HZ`Ap zkzLYbXJ?zbyLYGfEW_hW0de;xc^jEe$hhxZvxn@qxA>k()ns_ZV`4%Jn46%u+0+yB zP!$w3NlUVd)!z5~E-y1Ud5U06QF44+tsw8P9f@b*kFhD&tq7u<+-XVu>Lmm$AwZO9 zVTm_1FbIzicR0B$rbMA7;>c%HgVWObZNfGIJR>YkaQ0&DD<#2!%nzA!OP9WkFhc$> z*l7Qg6XDngIT34bw1UUypPVf~de(hySKN4II-1|1tab&X%I5f}&)vfa4N7VZpd_;laj6};XR195y)3GLI5CBQqOAya&mO zC`rZ9NE1u5*SU+AGyQ#o34$INO*NKRQFEz4oAQt=oq2Fp*IP2*I1u{W4XZWU$FwpR zr#tMs3z73puAY$2PIVE10RJRjn!K8X%ThhwZi#}5%7|{0=MpkMqa+mLsuYZKM0}R7 zsOq9GRRC+ue#sBeb;R;gGs*L$BZ)CLvd2aCcc+dt=&^X*rM(ms9Id@WEaF&htx8Hl zPh*ONDTdk;xnQ3@%{x81aYa7H?YX(#QgW=Wez+&X>$vJJX<`D#vMqthK+k@1CIUym zN*YM|7L_-o{9aE8$Cb?x@Lqz!3Ug^C@lA4p>4=-~#+`!CeH+*9?OUmCl_fssQD(-R?yo0a z%v+-w3Ma5bKq&-_SY+tj&6?<`&&9<>4hw8cU00yyTHneXi}-T!ynyq-X0FO&W*AilCXI<$e#TXq+KyGB{G5O`aZOYq>Q}DJycG=E(fk zxK6VT3HFTG+|`hz+i3RDv9YN-CzpdFRB9Cs=xnn~b)-r$;LgJ6=>gTsWAwWy(rXK5 zZarVoHQseNche2heGWTF>yGdT602{vin6k9u3a9JCQVIE0ZCB!bRrG+h~SQuojag| zMM=+g`?vLUB>A&vL&*)%iILNA!x<50%NHrR*D-%74G2Akqsl(Ln8nC`u(ztG@@xKh zEk>Y%9?!0QBJ4EOEaC-oe4d+=6GrE?eCHqNO`t&~37hWQU?P!}e(Ue0eB^@ezjkkm zCai~NxGf;|{-0#Eh#{uaH4U}JSsz?PJ^ys}PgtWMl?#fw#Lgd4!YujoM- ze`GdhhjFFfi|Ie#ph(?T5aOH|ZreWZtqguec$y;Yn4IU&l=8UpE~g6(?a`*dG;~Iw znkR0YF8@3MS8Bk*2jw*P>;9+aop!*1Ifig^D>xWw!T8VEQnPhbB_|s-v;5is0ly$o z%}cwg@674v>43!t9pa%YN7U-Tk+P-`Zm6i4{-k6v%+5O#)Qtoux@b0ykxZ_LpWzQY z6713?CzO|R%ZuGDw|3XDd}!qpbc{I8a#=_FgtqdYpa#eUFCcZQ)dv!}-k^_qxH)H0 z_umIBaHar${&yF-u){({Oj_bXe!OzbMZ__6ar8GkEY@Ku7k2W zhCng;Nb-7i_5)9`p0Ih_dV&b+$2{|?OuidZ9vFv)dJJq#_1(Fh93M+SOw1GRvBA_U z5{QakDH&A=BFk@h9?+A@LdqQy8(zR+58Y8px&us5`G3H|3fg7`G7bYlXaBgE7(RjhWzD~- zECbk>nc*xcXk;`e6%`edA!%JFzVbvuu8b*mMKg@c!Jqjvj9>AsqAwDueOF=gw3{o?|087vOJaZSyrPl@`6?>D_dtoQq zM1P!k8@*7BKk-;ib>2Gf|7<4S+$_4Cta2L?b(QN)Z#l)=IgKw87cOoV*h!4JxjJ58 zg)Ky@N4*xTxgM1V*(O zLbiC+3G5BktyD_Iu_h{!N5E*AT`pjiCi1xxi@qXh0*-YBN%k<=>G2&ej_Y?z6gMox zIUiOVoR2lcbpo3?FPIsrzOx7*G6$2c+JS35iGRXvQTuxM^M!1bv4Ujz)~6eZygc2I#A*XN8@#`gLEue>G8LVawd=~X z>~S1%0-XIgWE+(!h=m0WO^<~y>Cs|9W)?t$<1&6yChAm1q}lL)L?`~8=j!-RO6EZP zI_aDJ8XNRG;FVmjxOL)34w6m}CtA;)GJMJY16XqGG_#p{WO$B72dd3fMQEK{E-o$* zn@bmNo7Ih}aixsA>n5`%w_3x&FFtxmsHs550CH8)G&TUzR$wF2k?9H2{s-38<0 zAl3p<*e#A%x=!&m;%|){NJH2(K32mv62Lx~g+GSdGn12b7860ae*%#xwj+=)7)l;K z*c{J5It5!9EkNtaqvT2#7hYuw<`yn-jWx;bnL~|-f|~J3!(A<2dstVoFwW^!-115r zrv0@TEH|Us!)NJwGpnh3tYjd#$TDy=U5(ZsRY9%ZVyPIYo;+avPS3N(@<89@N#}M9}-YbQSEGN<0IY%g1lNriRRs9Odri-~9So8^`DU;tFv|uB#c^|RrL(kGv*YK11C?9OE`|1crV}TR zqn*G4>&oEi9lUq%GzGlmXsMe$j?W9sAP*=g{v6m~YuD@x-kzmeOjrv&Lq$hLU%I0w z7sCqr_zZXIl`^}e-=$tI`)F1Rt~u@MRzxa#a+oGGSnfg!qkUTlno7SZQTz!zZMz84NZ?@S!2eJn+Nt!5 z%Xt@R^JmBQ_81Ec4i6rj8Gv|A1w~AL>D7~Ts{X<8zR8|1hYv5?m^Ry~n(NhBIXI@< zXU95v-f>+}Dz_z3Bj!GFaL#GE@4gMlTmk;DzCIQoWn9|ZxA;3g?d`KUQniDttF&5< zo1^E+WW}1$@^j}H^(bj06WThtAdLM*<2QFl15Z{;AAim)O>ePWmVda1v;e~|$nko# zkr~AYUbz@|kZC&b>b0!Q6w3i1RYSL^_rnduFBSoTwYD6N*qveNAD%_(c&ZGmCSB39 z=~}yB0{wsy)LFTTTbi3`0GPojm}GK-b9&#A@C1g&z_&N{>a}8?_f4SN8Ad~I@p3-{ zpG%Crxt1hePh0`N9h|RTN4@wf>7I2X9RZ%?{Ft3 zi)o!kD_y({sKlYjXPGot)f}=DtQ0O``(i0n=pHGUb_QwkaAb z&Tqt6FYX*idO<;Ia-^2ln#(AmVqQ`-9!UpOK`b$-M5YR<+rj?B|=; z++1N~0y{fvVq#d+;aE6bA!NgaIcJjyaU%T#-DW#d0y}9{sYyC%$*zXdaT+R}QcM4@SD9bRRbdW3qrrKCwBSyYhDD!Qfmr(?$#26c|8JRSDoYPA? z2o8z0>4_O+p3lAP%-06Y23lI0fCQ7lp=bV>q`z~Z4Z=bV!$Dmi>fCn#RF8QOebT#jJuYpzsFxs3AH-nZI#zG~p08YE)oE0zvX4DWW171^$KY_T+?EiM zF`LOZzqj=oY8F^Y&;le{^2I!LiDab4bNYp&7tCfW_-J_P&z&90PEJ~&xbN1;<0aP&lg|^$i=a69I?aOTfFn@IBz}i5C-Z-vpZ1vsqMN{pb0pPM zso%YAr$RKI)Ko%-N2emSHoAruhH9$`(W0_}3pG!8b{9uWSn9Z<@9;9_O_eX`$+*W< z3VW~Rc99;h%5U^E;j!y8(|z8bc{i*OBXvk55?f?2mxq3U!j-fxaQ||yZb*ZknkFYc zkuc`;%a@K?nbBZPaZyqCJk;fmg39B}3t%aD_N05R=F&px!V(0$*deXJ;63uxlx2fG zAqCFL9+?i9=?}V!XEG;bzeglfz9%qVDGkgFtmvB<$tENrc^p@bmndLA z%$6#hiQc%@TCI3ASiG9~^Uw>3x-G6uf`U`@L9+pjeR?!y`M9WeCmXtDhZ<6#k@^e` zExLtOLW0BA!_^u3E??Mf(FPgw%%8p z0o%=OkOKx|So!`$+EaAW?wFrw1$$oVJCM7k#Q@tgl>0ba!-XZzh1H5J*Ne?MQId3Ei9AA?yF zpvJYCKH1#CQ0Yr|Nu%32U|_@kk?rQjDfq3cBz2dcH*Ey~+@_LyQ8g0u_8s=`W^r2n zI|!4Odm=~e&O{Y8Ny8(8fq?NQz6_vt7_5jq#I}Q?Y{q`SS4akdpHPR&ea#xbYFUiK-V~4)xvh{{FY< zWoZDko$;Csp;jaNB@AeSBZ7DDYbB1?OeRtvMHidxZqVLV&M&T=1P&=sQ9S}L+|^VC zuv&!`c$e;+i$(Jt+1cP_`%~cTj^D1a*=P1!IaQt4K`Gxew8u&L9j31lHfS`m;GY}= zi)orlZ}a-+cy|NGdwb_pfR^Lql;NPy=jW&?Tvg@_>zl#Ei6A~%nsK`#yE-jfEr~%O zNF3fkqP{54`1Z|$5G)pS(ZmLXw+Ufwg?naa`v{zpBf)^?q0GYw(9^i(xx4Op19JJZ z4Ni>4vZCU#K20I#nj0hlMuMH%_4Ve6k(Ukm%id7v|%_q$kDlR*ZiI%Qn1PH?IRM9 zJD!FYP=;YrljPcki z7jow28>*}D@z0Wz0)I`|Jn?XgFs&{`n@OIM`<88BY9ZkkLh9sbE^h0x^?0E=8b)dz*Qkpk_U0E)CPBPqL8pi5y2ry!*wI#IG!370HD#6a{`?jf^`iwo~TeZMMxxE~dbGJe1 z(}>HnKRzR`;IW?SJzAQ#SEi|7SyQ50OdUXC?9CrsOMEM`&q}9La;$0!Qj#h7in`>7 zN%mVxLetmovH8ZvjFY>gF^5EkOmDB1w#(MeL{7r;zXK&dQBvMC)O)&qdSms61@B(+ ztpy^A?8)d~uqB#f%r&vCJmKBT45EVjeY&a(DajI-Foba?@3i>~UV|Il) z28|9o*n*0;*B9Hq{nZu|u;DsoPfuM* z$z0X>Hq(B#4~_Ry7?d{DdSeCaC2?$0($eV9h|m;A5)q-ASTCA)P4y2+@G2oE`*dt< z^L4g9i|_y-4X>`Q!r`cwtLK9vrMC~9&DqX&r>eo{6c;2U;%k>RTkn+pK%7d{wAZO- ze7oFzDVF?B(H@L?5=O?RH;o?;(gb*zHIMCUQ^nU=?h=o7Jz6WxJ>z-4_E~*?%Y|+; z)ttnnxW!|gC2ue>2%v;J!uqm~=P*jiL6M3E8 z`uzC8Oh7;fOYF&vTH+=l8Fw}tuKQY_NbFk;;`X5_{FOk^ImI^+=47yE^N{!ecQOR3 zI*85XO@Y*C;|f6;Skc6OR!eXoM4*-l-WcX0zfy$kD{|lojo#M*UW0(w7d)5)DCQ)< zdn4j9PSe#X(ufOlJE@oU_IVf&0zo09+@o!6ql4+QZM#8T-H1*AqD#xf|aBv8}52?Sp))) zYwMlbYk(4ab+)5#VJM^Rqj-F_E%3IL4$}JH#12a*bu>-JLb%rT+tTW}8vD{X|Axv+ zoSAk?-{LKZr3jT>*Twn)l;1w*5Sga|sj&@P^p}vEkRCe`;>N-x;j;xh2~x?d!KzKG z*>eAf*{QQFu;bje4T4XmA6s-WoN9CjW*HuzG?2bqW=~i|P@)sD>mT>DI(W{PSjjPN z{x?u{|2+atN9JMZUsQEcH^0v0KfM-2L$w%cZjXL&d}=)oHr0gw05#)loR_=SgGXz( zKbyGO*_T6qSPP-Fd_NzR>Fewl7FF_=!XQ~+|0tJ%71PBe40*KYiAGT1loLMymuYvh zYO-KNE6K?tbla$?#)?1$M}x#ra>T_T5OWv3yzbnRYIf0ZTm(CS#|&ueQt0IJ1^)jH z5|L6Jel)xtiy%~mp6o*0`?A@i8-5KAHh((U?5~>u>VKQUr?a{C0H_IAN?UJwHh2Ii zz*bZLWV(h|5Wp_diq!S+$0VD~OK6ar;b8%yX!eJvPjZCQuAmEgsQG9|#K#T$9P0JW ze85?-82jP4r;9*7w%Vjq@=i&9NdkerX}xy7b;%jqo~@J%7*aw&^66anr>C_LL0HF# zC=k`BD8FP0xY3L@Kk|n^MzLB0 z^04C$vf0XFZ*>5vrW!*o=n2hgR!H-+aXT3ge(tNIJ*!MjELKRRS7B@}7vfL`uH`tc< z#ZVxFcD>mc)U9*B(+^Mn5cA;1H6Sfgg@Tq=GGtbZr!DSr6f4Tz7ZDv0UzWNjw;~lX8 zTbs|Z@1Fet{9REcpEFWkJD@zP+MnOl!ok)(CJwuiaUBrqGic7*gCnR9KRH|NZdlt` zSn2CC0z%zU_Y<%Jj)fy6A>d%Lyq$R5nZAb&TxEL`9kmyi=5Z5DKyDb^1%gAK>oxu@ z;{0bbqrIDOLnc|K2!G(}coSw}aYIYdI)68p=$LeLc=(o%-izWsO>!viEuP$Tg~{1g zi64L(dKVx5yR3I)tuff6^RMW|yRvZkG;TId&Zw_@MOBgb`1sB4WBkPN5YsM5$Qa0L zJ6m3~1B)fM^lphx>4Q!(nnKR`;}g;yNQsWRn&R%Iqn^tX7q+2XMf9z(Bwng*iN}zENZ%un-8?$hTnB5N zUXog_-SQTvmYnu+lMtCpC(8gJgP9RfXyxKO92_?>$R=k7$6?#wh(P0E5|yzm9DKlU zTwb+4p!p9}gMRi-p8^ho*kAW{_1Mh8#*nXDBBrd@TsBxujt*rr4Hiqs1vq^#8U_;@ z_9fm@KN17+$hnH8AwUkf;jmFZ=-2M4Lx`)XMtf=2ZG&Yg!LKMdK2As5Qu$*ha<36M zJp_RpS^2l!jW4+@Kj`X$UWOK3=q@=&{vKFTU|_g(&f>eA0Fn|4sjnF!5S!!k4Pd03 zKhMz-6iRg396jBSz}c4n&)-~i?r}HR64=<3SPh%6)JwCr9t=T8M+bFX#S}g-uPu+tzV7JF}8*!AgEB)zjPg+=5n6D?Rp>9kTm9+uAAZO2_RgpM!8Of+t z$b9J-S|o=fA<_BeX9KuL&fl%YP8`^{o|1McmU$czgT20rtaD&h>~=gT-~R4puYMZT zCHKGKSV&|Ru%^tMtq-?O_Pi_4HE@t;P6^$c@``Vg*D6p~V3a^c8%m;Q5D3T@Ie~nN z9|ZIx!PSoaQyi)8f3yI0c4>L(deE=06AZu@nb7#Q^?>dM<4tE$nS z5lyQzsoU&>O`|u?*OPyix}SrsC+=W{$dHLOILiQBmFaF$8s#BXh@JXF!3k#&Y%A6V z=^AhlNkDj~YTcsz{P;-^0Wt)-U-|LR;gpDcO$~?F`Fbz7m~hND<(Zq=pKOdZML<2k zQW9<$Jz!H^pv>KX&G02ghov(7&ajDc9VR!onQLU@+8?Z{W{JSSw+h6NYd~Lkal-l=;^6K5d+o!zVhz``#8%V z%>2%l7WyW`mGhr=D>?I&wr3iyKv4noYv`GoUvqNjKx1!ELce#3tT>!cGPL~Fs!%gR z7nUWF$Y=UM;I8Rhk}snAXh1%2J|y2HE%uC#aw)Dm6L ztAiKXS*WvSMrrX+7ia6a3*GEHRKBwc~oTh9#^_%UU zuc?op+;ygx8C}J4gFP*^*AD?Gyxz$=E>-nK!dZt9PJm0EY_ZoBPUSFPYK1)L}zvU`(y=cRZ`xf~G z#JsAy!I72zQy2uh%synS24^=RfUJO9KW9E8xiN&dfE;mrcgGV+vVV1fg5R0St_D|BwiT&iPk<29Qe$ z8LBO20@Yb~dAAQ^EC9p=V)k+GV&+3%QQ)eI42b>%VXD!#e}4W>*M2A$T+v@(5jozq z8s2X8=kZ78CzB{hsQLC0j{UWb)nQ<$F+DrnRkAZ(ldNwgdQnY)rL0}M6T!&fzA~-Q zs`iL<=DX8OYwleB=Smxz*ec*luQH3sMuAjh$YCXtP(K>cdA1?4bujji!lL}9z$9Y+X9H#(YCd6JPVUU~dtfWp{Oc{Pdiq$ZAD`^VOUDkt zUrt%L-&H;uP0udX3nP|h)4j!2QcQde`_)5%`|H|qnOC4IE5QO;G~pq^`a2z;B2YRZ z5C705@oyR9NcZrMak>0X9{mOC5+`Y`08SO2W2ScPhaJ#UFk5Y+I9FqLZPZU|U*i z8u_8sZwIWc4ckqTyV`EP@ele?I+LNpq;+e|G*PKwdVN+3FObQ@u=4gv!z30CO(ZH( zEvWd~7H?u5%q6c73|tteyFW_|BdcYmcdBBbx5Mwa82>D;q&(!BMVl+HrCn0N^M*h5 z2A7+Rk$&`}zd5lJR3i%KrL2Rub`8ht&mZ;B9UWmT$fmVdP28`4Us>o)2{7SRdV#tP ztt*YMe?vc52YYq4(Mro}cKPjX>mjsE){8-wt$aiQIEJU4(K1<;_7y0YBuX1}lJ8AU zw~=qOtEIig71VO>(%CIBtj7-Lr>hQ64-a3==Q9<8V9(G=j(8-NC0TCSzF~k|WJ(IB z**Y)d^9Rjw%Z2KsuZ;kle%)+{mKR)2_#L;{h?SMn_^r>wAM8w53EFMrwwKawj1-Y{ z)&iQAF5LBzge#XHht&VTJYHW16Y`Yh8Yt|#q625oqv3+b!M^0f(NvYOzZoO!E|n!Z zV6M>-Vr6BWo#Q)I7r<$KfhyY%^u)Dai6DU_z|-1Vxf=bRREF9!OWBvxYxmc%u-n?; z4FIQ%m1z6>;e6BJbK$bD8l&geF55F-kli#Kp^8^qxU`RXy_? zQ!dw#NfX|+#EEG&f@2gQ<^|ACU`sDcqu`)k9X7)cd)aM778kZ@W=XEB7ij83G3qsj z20>OmCvZ{0AQRl2#%8Ke{%>E0?v2X0y6vZ^cr}559hUy{yl;%;!$m*bqAM) z50=n|8V+uKW$DowT-%T2cyQtzV-cW)+WK*CT^F|himV_bannZn1xK~%Z z!F?4_vsF(1S@#xy(qF=$Xhj{g# zUp@EaFg!A13{U*T*wj|{TVtcg1t`_Q4y~Qm;QC-^zG!4^!m;C@R#{P@rWQjqM?Ls$ z7Exesesgt7DBw!3R?IT(pfL2p{cTYREe$VY;Xmi?h1%)k?vpLgPN~F%gxB7=j!L_O zRv6XmcI~6L<83ob*BeyA5cfw9cRRZ}%PA~q0KHtni<9FqT@WAKTRON&H7TUXrG(9k zf?^16O^|JDWcKDj+uVcZ-AJaYk`U0}-nmn!os5kkGFpZtE{DCYkBO*g#Kna!-L895 zv1418q25bQKWB5T2SG-3+4*V^1U7N7=T(k$BJv)^;ur%qsJXAN#PatKy0};jI^AfQ z;O&m-90x#T&{u_Od5R&#X>GxY+;|Cr?YmU6Isu`ZBRd9sOMWom8? z-Y=vSmVt;rY64#o2~W~TQj!vKVE2}?8WDe47#J>eX6tcZ1~N;sAbNGXJf>Q3QK54R z5)y%Bm15uL&7u=xCYMzHbc4q z{pERz9d0eEp?VtSQg!PgEolJ*aGHebbJlKv%=p*H@pdd6Z&1QdRX|Gk(!F zYG_=kY+ZPDN$i5%I~Zm2=gz#Imbswhm7xolKl>SvK|Bs&_8Ky{i2Uthi>&bB&2|3;z@=d5fdZ9Pz)DQjEY;+esmwb zdLwjv5u~6kC;e)5W$h>dAauQ*R-GlBLq?mLt`Cpo`SBk<+#|j2hj4Jvw!CW5gih!R z@k5K6*Nr+GC<_lgvYODQ%xru$!~oLeLvQEo*4qHo%cSJCv$opBii%45rc4c`iLU8L zFYl$coFcH6eskkb7cH+~A{;nu7a#5-n;E=hmVA^3G(8y@yn`NFOsEHjc`Z%i%;?W60PR zbTye)W}_+%B#-pxjBegkwb{+{IKBrYDQZD`dkf;~<9-7I>p4F@G=P$U&*h2rOy8B$ z#GBpJxJ70Dl#$mlm_zsPiQ4V6D!PA?1fGRXxP=p{ z*M%_^=h*mgRSG_u&dJGF?}tyA!EHH*pxCaKb;tktrl~cI!|^a4enh~Dx2zy$AS(K` zA~JHlhjM}gSC0T_7CBE?a(3p0n;H=6i9!dEnr?i_Iz)6dEGJuinSpmE?@OSa6(YiN z#KTUO5h}`9h0RlwYxZKRGg7+P znx!DivAy}fSbNK;wzsYAyL(fmh3*zJ#fv-Cfa1lS6b%~OB~>U;ptuAnUff+$ z+@ZJ=T!TZ9kmOzLbIyIvE$1Egc%G*p7^9;!NY;O?x#qmC--X-p@ZwLaf1{UO0lI8} zU;4^T2V^d(-QkCRK5Pt&Wd9+1c-T-Q7pD56XEnU%y6<&WOSRbh)Q+-`Dj2fJEpw;> zcx5S=SOBVLT**lLYU_%^i+}V2{5;j|N~=Tdv@YJFXSz}1jVh_vjgSb%1S$~ldhdCb zCvcj{$|@N=wTsU9{6G*7+@3%!@hXZOy}rIqNpM#xm^*W7rCM;Lze0aAS2ODD4xQK@ z1cFi3tG26nyfl*Q4muD_!PL>?v}t8N_K{!u&zK%xSIX<{{W>wr9gtRU5N0`U{fLi` zuL}P>_!hF}j`;RSuC&q-0>CiV+doBrN?icQUZRA6eI^%u(Ng=+LmR>3e35zy{rR~I6QKuzb4-ON40aRk&pjfz^{sU!!7Xi z7a2)&`UT13%Fm_E?fVK}fp|fV{UR0g@K~qAX+T+cT!+_8^&vmB;%S=JLZaq^AXT!2 z5P0UAni$x76kN(S9cinIk{8bCSgEfWMKNy8)_EU!-n0vKwbdJ;G<7Q*ypk| z7SKJl?jv6R_));l*S7)qV%J^+{wm-KT)yIygGm-6DK6o2vzqI$mCm~Q;mGIwgrynL z5(n71pGulB6=l-NHL@j@<(b|hIGQ3mq`}2Td&$zL`Sr=ve+NmF-uukcWb+weO*TNt zA-1#nqu!8DSXc^hH`AK4e!7o;!!rtGs`SWmyeB7DIq!^o#LpPjFra?FRYM5y#8THj zPsVSoZ+y`ic09wLNPgX&521RL*sP`&6}TJt5#Zk@`0cs27(MUR-1iyi-i`@N`<$m?F5@}S=HAsws$$9N^c&DgtGvWxu2$Ziota)HuVmG7qJUsk+eX>87K zKcbq+&dE`|pAfHk81Db+Q{|x+>RBiYt=Z@Eg5u(`1UUB%Q6@#Y)6EATv#Bm>(uT3uFqFkYYB%bPdNRbU}YHI+lfUalf3JzC^;^qe}4DLarQ_Ur7JF z3z;4;VX<5&d~qE!Z!QVF8u2CP4&kR4fTGiF7ocMSwMtFgL!;=5#0<`PA#zSNPl8%of(74e1(FjH;`JhtG}8%!*-)S^m~tTDcXrLso&=+mg4sy8E4q$^lp| z{osX&;DWg$et|-yb-Ki1gg==&o{9>zb{iY}ElU<4ZhPVV-+!wgE!4UDfN?E(2k;SO zLXn;!m&$hm#$=|}IwF~nn4TU9aI9Ok7;Xxgg)_$wNmslCoJ5`Wzk_ZRn27?)G;plP ztyY2@I4kR$bS6etHm~62<(nX^)Z|mBLK6({Ds~k5LNF(FkOs6ttUCOgTAZS$tCT_X)kr z^3PPtCcq^8v5XmSG^ixnnb6gHe4PskO?OyY>m21kaOs>JOx%nC3ek~thcsa4{QC87 z&D$zAo49kM$;+(rz$3(0XNHBj$^knBvnX_Vg9I4gO1-8$0~?l>a#iFQnFXPzIWA^v zHBvp&x!>fTEu3v^Y-s!R4XfwtN@bgKxcWSp=eQ-7ob@tnFnuo#Kiwel=dQ1~fh}}Z zx=daDlsp+cJ0<@r<&eog?Ci`o&y)tOCW|frvIc0uU=urN>DpK|=t`}wEP1-~WoTLt zoPPk%5*fpni62!kedMEUvxMyI0C}=35N|CU?JNJ`zVT>`vP(;i_fgv?hvsXy*V0n+ zUYN0Si2DFhIYrd~Ucxm8pr7Yoo*@u%>FMcJLW0?xTu6t5z6CW_^+KiA@{{I{O{)>0 z&Mjru!z-7rw2UycrmOi># zr1_Cpyu;kV*^Xsq)F*x?-x9TtttT}GXbw_Wfo@8!?>sDpe=4t=ciC(M$*$nF924c_ z>hWw7#7k_2|0h3{2EX`6fWqNvFIiJJjOKERvQi6O*qd5QpJe6o4;^f4B|eAmdoz4-k&^TX)QTI~3v8zJIYQnt}I ze;>E^>8F_(YTA5w2_85~4jmi_D?JNwovA6y;+<2=>OWAnzx7}|>m_z{dTNxTey#Po zUbkM^dRH){)@UkN4-YPcU;{|+cptxrxlkS4P;)rR+c}5C)Vbf8E%u?dvaNMGZd5+F zw>5CsFfKg2l zatd7IL*g33sqV87Ev!sG*`37!THwawz2@a-f1wmb*H2efzCc6aValh6l%%i>fiWsC;HRCqIpk}a5aFu@R0?| zS8FF`e+iBToE+1WlWes%VL`{#kz1Zrb%dWNsc`lM#sH4d+AE)f47S*m0ZHrWceLMHl$-v>?)m3#n-3p-q5ij$pSq%-YK=*I zRG*I7O=q^qh2ce4di3r;pnaKaJ66Gnd&F*7u`&l~zt19@&^eD(2G8waMJkz};EfxR zc1duD>3J?=L|9d4=gEJQ)lnL=eF%0)@!^OLI`5Ly4S=Jzf0pi1yN7p%@)B zaUgC3oLv`xo{|3>s)&Tp-#+2evz31h*7$$KwD|jL^W47i&&-bh%}f8^3l6?dlauEJ z!A83DuUr(0P@gmt$o35U)71njq47ywZWOS7 z#;aw0b%HIW7Zgw(^0@<(TqSPjsjAgXmo@081ILIt6e{jTS#!`&1RzxbN^imCZM7X7 z3~eB7`?CKhywh1zC%lgvr3Ip`YBj)rxH!Y{8ep(XJ6YjaR0@g;b@e=lla7GT@|qNJ ze*My$L%DkWu*6%pHYq5*zXk-0?v4!%K{>$}1wLD#v;uh+fbDUDMd_8ooB;h}?Xov< zKug@kvJigQ_^=OP#~;k=1hrglhbz3c7++dfidfLqy2o$-1FFT{aYYyx(J8WERkx6!sx zYkt?JueWt{0QLMIKl$my{~w{klG6VqR5)Q40*gvHNk~LgG>h@g5vVMxGL4e&3O}PI}{Jl~bX{&3?!# zLEHQH0P5gL=Ck81*@@sj@oOOTdf>hbf4Q2>vC6C|wxAwN&b=vL{w){p_b`^re_|bgB7riq1lgH?>ECj;I1oFfyTrT8^{NgW|;<4UX*0!sk|=t%?8*!~VVv@P#BtBvMn5 zEv~|$*gl`(7p+Qv%z3deiB$Ce44an0pvQr-#A57cB8rDtmlS)r-B#~&wySndMtg8k z^@u_DK|)9EFGQ+n&9x%k;QXl8qSH!ZQ$7a_ zjn>A53pf?YDY8$ux6gv7jtSMvF6W3OAOB)98&qA}NJeo)kf0l-{CrEt{Kp^s+I)sU z==EPQ5}bDxUDl@?WMW9$r2PW# znm(+&;-sK(>n>S%fgzIO0R_Vu1VChfS@r_b#n_D`4*=+&6eF&)+f=>5VO4O@@!8y% z?r3RwW1uL`!*jM5ktIqH+g(w7gmthgH7GvRg26;9eNPKCw>;l8Gl=$NeJitE=7*u} zX>IeHUiejv1ddRj6Ky*ZXeC`wPPm)lvEr!VmhsX!L_mPbt5?Hak^+P8f4)vjxR^v4 z)EgUZMjN8-e+|7IAW;IOuJn`?C4X;|tTXaTcI_%}K<~}Z@1d9Q+Gs!j6)4VKO0wygAtDP6biVc>Y~`}qc9Un%u^yj6Y-FYJ?q zNJ4ZD&8>p5>qVudS`S3m3^K}~;VhQR5YSaUAW~ti2(R3k?r!j*IXnbRLiI|3ELU|B zPZrjWM*tpm-TY=ho!=+Yz-}$OL-cIGN;4f5$)+f1jF!F^Nh#SoE>;5xDTf=gajQ}^ zz*_*PpLUraoE(bLG}W*jn@y%3Kvk|b~`eXLxv3>yJ7)|<|-;G4bH9p ziVEKhyhv36NP{8<@$H|FcL}7C+hO_(sE1Sz{-d*2f{36)>i3$8l5j02w|h`#!aFaGTMt~6t^=S5s|yGGHAM$(<<4A+d`jqqc4;HAON;Sp<(;AS@^f4 zBqJNsU!`795f3vm8l4H@NY0essM)#!IS8OR)(17{F&`hMaGh{nm2#M>%uC5^)${$0 zg@wgHv{GJ~4V(XmF@}ql-1&((oGvVu+yZ7iou;=605ib|KHjxX-m{&L{-F~i>x0Dx zpbG|E$U`*a9+~MG4hJ#XubSco9(6pKY!Z%;Vmr|AK}bz9QC2kvvKE^{}^DJ}a) z&YK5mRPVYK{}6D^nCazhOv%cUhet%HzLEik^zQ2-e>kK+ZOBYb&50+bMWm9|QEKv# zl2+W3eE86)EMCz7(b3)QBrZCvnIk2-ptI{FQ2X5PHubaW^?O{8EFi-}1F)6t$qL0F zR7{=(n0|w67ERJ}3pA~@?kfOrrd^IGaohqal&+0E3c>4RfdmybRAa~;L#3wR6vde6 zc$l?GZv%+&e%yC)g0j9cQ?@U&ndc^qF}5rFS|z7kwQ_wIzi@Q4sY0~g+MT@6DN80D z{6P5A2Y?x%fwsHzIc2ETG(5Uzv1T!r@g*`_2*CUgQ{Qtl_>ogmMxTmo_}~7R*>e(L zOX;=G{^9m6GRJ)xKCUQyvlQnBK&?=4 z5K5vpCx#sG*sdVEy*{@mNENn;l>FmW+na2LzRzvS?=@$unZc*E3IEyuccFr4LL9Pki(b&N?JxVCTIcMC9u} zZcNF{8HE43FL15W>eLQ!t-L%uc6ZJT{|}@QZ$O{*@6rggs=E|~92 z_>!~VFbnw?XvfI|ZkxA?t?|=GR3W6USXVpabm!&xeqbkfrKW;Cwn;J5e2$c}Ru0kf(VnBv&fFI)m$$yqd zFa{>-&D7|Ec2Y(?AAevQ(eP+JsL=q^lYrkE&L+7s2&WfqHC$3o=}xMLbE{JEeOEr( z*q4tfG%Kb4TJ$MF6s{wqHT75YhrXVDYF@f}5SF~vg~FF-GA9FSzETTz=wdq)lf?o9 zWM^a);P5Yn?;sj}D-!_`D6xS<|1KcpkHr0@Y^P}oX`3(dB;8`j3@`>|0qixgh*>5^ zMrNmG0QyE>9xl*JuRb{=kvy}uF#WkZTB%$KEW^O00wr=;@DhE;qZXV%Z7pt|M95bY19ABn&3@J+!mUdWT2ND1#GeDf6pFm9wpIsCYnatO9AAGm5 zdLjl$$MH2*V|`l_mFgB=M{7;j3rOFXyNkN*5#wwh4hsJO$%$p#s}hj#Hg6?rhbO1| z>_TNp1s8)TwdarNz>*T9_ZFB0Fk=DR88aJ;XOf18IceF|wyP3AmD;$yHe6N)tojO6 zl2&_79)|)3?&4oG4W91-KiGe4uE-CIXD-MEhTfjbSpy&!#L*4r^rQ0&b*AQbpc7nG zrcaU1fA`L-*uepC>v*G7m6QY+EUfQ-ngBwGFNyzF2w^i>5@dMG4oDOOLzhY$YD7d1 zk57ZHZ$m| zE7=9oVFrnB26f!2u6y!GwI+n(Rlo%DZ+Rz~&mwh0vkhWsbxJcIsX2`Myvk-92m@3! zFlJzq_5-KYbjRAb5KM@JHu-J$cCLVcvu=HzE&Ps;Em?6W`QJXPDi z%J=R*Z`U$4{R+0M9F4V)f&Ao&2tLn!_E&tLZH-`)NIPX289lJESqG)V)>r*Df21b- zbD0cxn#kOuEpj@>FJ|?zc4+NPqzy#|q=DLoNeLIWT1oDkq^Irv3dje?gScE?Q)Ci1 z7k+!4a0Bc&>R$k4*Znl-Q?2Qy)eX*T;y_s3$|fO&KQdfmhyNSOL0p%=I5pe(6N?iL z@}wO~V(RzHxi?(@0CV=x`nTyez)l8mJQ*UZlxZzO3H@g|H@J=|#A&n8KmFO)EByX7 z*dwU<7>#B7PkANFQm>ZQiigIn``A9Y8gK-<^M1;QCzO>rXXeRGA&2>D%$FCw_I&+2 zEa7UK6!QErB)>@)cEc-?bc&}_R{7o%7hgleC+1vjE&g-mLpBY@pEEV8Pg+Q{axpAn z+!oJvfCxPE=gN6&cYpJvAKb~Rx8ZE5YF5bi zloNvi0|pm6F66mbM9AlNKfSII_A~57{zE{aRfyMk&N@q>62*$*|CakL7^CUV7^%w9 z7^Od5uXMrNM=g=F4E_fA(TXySyFe@p@?AzxR(n3*yjQ6Df#LZ$*|i&<`!>5@_MFU> z$}391AX7mnU|sUu8-Fngjx`YFEuV_sc=}J5c5by0~yU za?4wecT;F+sB;=%98SCy0|R##Brwchl^=!)kzE`}e}I90nBJh;^xgl3<{~+b_dj|8 zf9WsWc>bIIqPX{CD}l|Hp2ow&Y#M1}^>L6!zdw_hc*L63cZAN+`$mv{&bNec* zJflI;J{Y7~trvrNdG&}_kUvhuqi6awD2{la>0$Br@83HTF;WF)PZ~G@+f?pmsQeTX z5Ejz%`2b+SCY0l=eVR(Ct=tvmP>3mFn}xqk{TrCqH-t*m*8trL2`xAG zqLX7|ZnbmoSXl#T|B!!(&bsT)Hfqo(qHrv5yTT&XR{# zSsDihYacKQ>0aMaK3(mJxi(z}Th>t4f*y>{P*IS$I6e8z)X1odw=s-WK@|ko1t{6Q{ULKCfT;M_V?fzH^2v+w9doiQ zKcFy`dh@2(1)CJPG<@a2Tt_$7VG&jD1<^Z|SC?(1n;P@E12+H7ehTX^-9F^r?0LFJ zdM*}CaG!&ND`P$#8aO|L+&WJRJ0qA}uQ8)*dk3abWfB^6+^F(MViWQ0&)2fChzF(h zCU<4LY99?1jlHt4u&~E{qS8k<4^~17Hwlf>_V!udWe-5|2ai+o$UtgYt6zo=(S438b>nm%;C}mcouQIIZ z4`sJF>b?1M96g;#u4>eO)Tt4!LUu8V%@?CK-F8Cvv|7Z@+PT^=<125vnq?*Ui9)R}pw z=EAZYB4yUHa3Z2@?!hl05BUnl*-q{#0HL=C>OcFLy{8{ipH#hkyw(}x-<0zshn$5d z4^7iZ>lDZ@SC#kD_+gm4`~JkfnVM;u#ywZ|N0R~Jb5oy>RrioXyYq|8k+c<+8CUSb zisAM7{L4e@tM7cev;MiO&vse_tT}IG79v9mFrbI_s=d;7tJjdc>v|~#h{JeA$Yrg| zetwv`u(U)jGUeoaLVo`?^&sSQvqF(F@v4d!`4uVSv$r5pD8r7ALfU~Mr2njB%{eYU zfVHBw>JeT7f1AO(D$TEh?DCInIVtzn#!QY{G*wj$#yI)O!#l}G^^S_au0a8fWdhHz z&gZ%Nb5?34;!yLK^Js(OO^ofLG|3MKW#`}Jw0}`jgD}jHzL;o1tM5q?E;PrZ%`;Mm zEe1gI*)%s?mKq~g)LV3BjBQKH`-VDlI!v|C?LY!Nzv=|_uR>;Q^b4My6*_R2_2pQj zDh1&&T}|>2EyAQj@Ate8(B-$B2du#HO1|8HMd@fEvyvhJ4UOk~D*XRMsPX*qO8R}v zwK?BglIov8pHDTT-S$xqE&(AFpu|v|-dayNJ^btEyu3uQ{3?b-u5;|Q`a^zZ#I|!0 z*Tc7z$bs>sKjpj>lTX)I%E39n{Q)mmTWV)%nV3M;($c`bul^^G>){*LTwt{0Xn3q{ z7!5bgcuEeHymg zH-d{YQfxgv!&E-tPXSvw#hiQK z#t(W}WLsh%A6uoZ`K~su}F+S}4^*t$9K7v#H zYGzE@)OG2uBS3}vGDrp*p+esFtIht(!1%<+#}8O_Tp|(hKK<`Yz=dE!CE(oC)8Xu7 z`QoN>Z2)4fvHANEb*1us!38kEDC2Z~QCLtQM@CLbo`*N#742OLFrnm1xMzPXks;sH zs|Yd+p`VVU@9E3|<5Bw3Qbm5<5oS|$)56zx{mdj08+xeJxUUtA};I&4r&U+lxQe!miDhmRG#~!_c??^}h|edBEu0XssxpU0ZH$2>u5iqpK+)uM*`(Ql)NbyGQYyvtBSsMwx*!R%D65^=h zvcp4LQH=VWG!{Fa4agrLzsU|}4x)G$7N*l{>dxDGMT3;H-_(mxjNPS|-rnBcZ;ssK zf*><34-cKKM)D{qC~6JUf7dE7z&6DpL6%<5Q;m&v3pKw-2Q%1=Zo-r1mvCT<;PG6V z!~4{#@jDux=u`9oxT|#VeK8w*NfMWl>AG`ZPM7w(3R=6pia~}^piivCa!HPuAVQF- zSp1qVdR!DGmb~$WU>AMAOdYT)OfUCS-<{qzf?A7Px0zB^Idq5Ce|obZomTb&#A>U* z%DyyBTF1t$73F&!L`Buuuj_`tKeT0Qb8F7 zKRXq2!*|oh+`V}t`L6-xX{Xf(1_``kVFQr5poe;9GHel)ieFB^s-K z-Iz`{s;!u{8N207TIM`4`K7}G#ssQb11oz#QEodO1s^w&9wil=Q>1xMLP7rgpfb*R_ zeC`iqLp_!xOJ4ynXwYah*wY)ndR>fLQisklSUD?}j9Xt2PH8{AjzLks_`EdzneC1WaPQsD%;4zYs`8z2JHX74-{+;sdBOTyz~<)miWq$R_H-oh z+-_=e8Tr>9(VV|2QgHXFe&B4!a+W}(N{~F-G%6$Ol_k{OI4_DOB zlznfFp6-O2*W<(DiaGgX%D{&`%uB6Bk{m03*#gWhKluI-~uy-K2r?Qyk=G`~Qz z@u2HBoz%{vPYUghzq>pTuzEDY0XiNkR})H#%WA>h_>EZOb0%eM7_lU7_aduQ!k?6W zv1A;qeFBP|`;cTKz%U+aZEeP;a8vc_dqw-*35$pc_^~Zr|Y&3^#m`}a_HV(4AJUN!mZpJck%qagP?9(g8 zFgcycS3wzy=kV2AL(aN=!jF9lk82M^3WbN9R(kfuc>8w_#10ftSUUH|YE-u+&QHc5 z%F4Xjx<;{LW^#qIw_Ub9_3*2PQKn2Rm=~Acp@WU0e}e{m zeCGc9#b^GJ^z%Z(@rn8W@So0i+&2ciP;`fbgZN6D32-X9z1`ky3E84dUTK^acO;v3 zJSdMNP(-n5)S$!RbtmXF2ET@A*kqV3Y3EORqjqz}K^k{_HPqA>>Qx5wK#5l(#n)O7 zR}IkzubIB9DTzoJoX)se>x2h*Vb;hb!<}EBoV* z6!DiiTqjcurWiKHat(YF_am|tPIuEnA=E-AH*RuW`nk_wf3Cx>T{O3`36o>SOqz^k zTnPa`lmcqZaFdH*^4rXVV5jUINIsH zR==ki);UXmIv*;Di-q?c7G^=O8xQ-Z^$V>w^-JI$9e7O^>}i^HMXvj{iyup#SgiD? zIF0GCY35a(oU);Xw+_{m)|_9|?k!6Cq}U;Wai~K0@aGnl-OT#16O(dMeB#{hOVX+} zLLYWLD|z;Thz)vNIY+B7TJ_-l$Dx1d0$wlLR*(bzQ#8Z-j|876R?XP`<(RlA09U(}z2`#+UYsd2CO6WF;OQ3tmMg zVq1xhQKCfPcUu~MHKfFBY;C;3wmZ=+PYwF9+G)jy$Ea!3t}aU8HK%sbpQ6u?^0GO|4V7z0tu{m5{LKl-z&veu6`633Ld?t;39@NSF_G@)#D8z?|^k7{?2 zSoa=gg4^EmY3R({dmrYngtA_4TBp@R^gy}8A_t+y^VImTAEO1F`K6sW4*oMfg0w@+Cugx9c_%9qJy{!Y8$40KL2>YEbr9EaEv-y8tNB6 zI~k%4v70JtG`B20n0h(8=_wzo+y;+lnWpnyhvNr+%tP3;a-MGGuG`g%FQH-#dExl; zM{w8`b{$Ki69?PSX`50-Vye;M>>Z@!#(V!{_v8Bc(|aZ8_R7bVmE&1y;qIrOnMZRq z`MqkicKjW=*_cJM3>*|!7boe$lGs*ylTn3)TrGnsvprE)%fb4AgOGx1`ocPN>S2_U zLcCD*k%a$BAL@s1eGtLLuwKMvl)citW{A%BFuT@k2D0>GyPh!5Ra>QyNz&l< zRBV-d64lU&nlD=W9_JR+bY(NUjC*9!Zj2R*x}urKX2*}V9`3B*E4Nhqak#qAUgi`! ztnwC#dk(7dGR{sbHvj+8;k|LM%OaO;#ZU4EP8_BNyieg;q72Ya@Zm<7!p@Q z8Ya4o>eLe0hz>TTRVQZz{YV}>^=|2y@;VeNm>CGh*PMc^NwBj-1VQGFlS42TGy6*s zA%!aSlcAF4gA3nS6~fq}ZR$1BkcmzkU}wxL#fT)sB^)|_l^u#dHEM#MlF>}8%t@0} z{?M;p$Rd;2am5-)Ef^FBL1m-!s77vLET%j+rOO4iB@H@;d%OTk?qXModeTu)z4>V#R`~C6! zImkmtf(m``tnXC*PHmRg7Kzm|(`)O%7~CrTrbZ!VMf7E|_e!-6%G+tJ5oL;a^NCocttx$2tJ+=fYMXFC(@87Hlc8>;YXc}Y;Wv>>T)PxN! zx8-7{prQPlT)gJ!lgaWil=-Ig#6hSX+&O|NI7=ZZe!I9I85>KiUMN~i=iBj{lyCi} zqE<%vs+%8avV_lBUoXPoZ09C##=z02sM@X^#L^TYP++c{RXDbv+I(d-aiZ8h+8uM+ zkR}}rE140f-)Z1qF6t>PDVxHwiK$h6Xc!9V<>{X46Wwy3WT9p9#+%#LKm_&WZ=-Q(4c4?~ySJPPiiC`K?Te@8xb+y1?o;IW3F!z+=~+z`ghm zhfxZW4TC^_lh=$FGHB-eLM48-$egsn>)QlXM8FV%viOlFr;D{^QwSX;Wtn?8Y#`r` z%eLbbPiD4$w(+rE0mN&o{AwNMEZ(e}&f%ny+1UcYQp~;B23_5Cwo9j1qw2=H@4*ZE z6eG;LliXYtLr;pr=*3XS8T?&&dzGci1`7}U<&7V>>B^FeMm%Ot`n5gx5koC*-XlXF zYWeGJDRsfA-G+5F!Do5o`NY(TUeYqGX0Izz4;@=TkjFt3)AlwC8u--Y^eFqHU(P;= z7G;hKDPC;TDp0pv3>NGm=j31a0+CcaNS$)4%~|`cWw6ZVPaC)j8$9Dml_b~K7;YOZ zM9O=KO!`ztkLjN#TWREyx*r9TJ6nzB4U`{@i1JNI5Zv7CW=h)g1z`>AO!Q!#nkY-~ zTJA5^W2W;vU4xy-5`N8(*LpcyR^Td{WxRJMe>Rp|ji9|}ma$75K8!kIK?Wrt&HZfc zqZ_^RTth^rf?}z4&fBcS={?B3Bn12+qqoPEOZdl{gW^KE=wbF?uh5PunJH zxW3WdQ=|?qtjDjEQE(;>dHZM1)ad)1Wiuy%`f|e3b;>2?upV~9I(^bAVF(ya`Sk$a(&6>nXwuyB`OCt&L-t;n?!R9Qi zCf8k6k8FY_`y@3K>gBJ!IWLO{NtT4quk>;;Db*e02YsZaac3?{LZ@i-)hSv8e|7$p z3$v?**G3$ii$~{x7Ll3Xuu5250HvWBaho~C*qMCePaa!GyYaUNS;-#rO>l~@L_-~0 zD@}Vwx+R9&1S^c2R!?~O%TlKG1bNO{Op1&z?8AE3a89-TJA<5dH_J-F(uAat5?=2~ zh5E0SR>OI-i+x@&_OE|hu6Pu=h4S^GT{jcs!sCQZ%w3sK7R_ht*jVmG%H&mLk@+fO ziY@|nFtn&%SV?FGW*Jz9SH*yP;Mx#p8P)oDd=#uz15%tHD{A!+mt?Z@F zE7wS}E4FK-`XozwA6ho_`fOEuZz87_tk>sw zg5l!(917GxD}*1lMD(xB#zt=e@@Q_fj&F%5t*N9DtJ<6ID-tKWi*c$s>i31r`}CKF ztQy#8PPJI3A2RmF!E1LH229#qZQu$hiQCBW)i5@Kmr9OS+#rG%x;<0B-JPU#tbn?Q z)yh}RkUF3ZRH!J+N*m_e9G?9SC%m69{l;>uu@Jd8N~vd4bGm{s?U%i&RPK_Sd4(An zngw02^t;uY1oLu6@Q*%;Fw}EOK8!5rEbXt4C7zL{9_da}LodX!z&hoWVe2`wGn@En z4aGaFNmx3in@6Og=XJCN)G-Dq%V9;{4+$!U!bh?;&Kf_jSLY|KAWQ!KyVX@n= z!rPvk%f5w5ac9e3&9nXRsq-HyCQOP+HB$wmk{J7bUz{Pe@J6!=eMldzt|VmA(QA?C z_${PDgD02V+xf*9HLFHJtn}}o{^dLHmpk5a;;O4_AxxSsl7xyZ{NkvzdE--mG}=ks zm^olW#jxyqE@W4EU`H%zU+lOX7`M!f&CaFwEqnShonp-)`KvO5Z>XGgpC!Llw`~hY zF~~H^NB5fH=cCn~amQqo`?rC;#e2eit;}Q+ibROujWPLP7Q(qonuP9xe!M_&=KJZa zWDc4a=}*H7tnzhlR`wReGHxD?q0qy{Gu6<nl+XB7vMla_N)iA}SZS9bJ7S+YMd zi97B4pQdgx+J;u@Tpf(fv-EMItIY!$+u=7U&&y8YCfsA>-Ltu998Vk+5jF_pSDqWz z^;4YK?NY3D;cbaU^i6r+*eHePX9?kwo96Vr=f|!%$EfIY=d$PXktS`v;qa9zhebU; zJ53}k(PrR>Ug2Bi;Ib;S=v1Y|qoLz=x{c}+cm^~aJ*e`x_0zTe)DhesvkD)2WD`!1EPsBL*GT3TiXrq{%|Z~#Af=#{!EemmW^Nd_F_n+9%{232Z4le?Y^ zvd~q`u@XbHE3K0FX^U&Vo3+beK)V^SmPcU&CbNu@wX`lnQLl8hk50l~JvUl3gChde z%-jd6O`R98ct zdXD-x`Ajen={aASQfNe68D4qJ_K#kGl{asV^T+XwnOO*P@XNtq97k;lS8tw9&{yt~ zBB5aYii}}Q` zZb4L%L*M6WZl`QI6nNR5eRmPol!;O()K_^VhXVb_;Z~j$W$uH|^?7m`a&d!t7e}L6 z|6}1&B$sD$dN@MImsK-Q$P1Hj-p_h=mK)x1gA>~J^+9&l#qAbuQLkxKgX7uZloP}R zH`+mulUX4t=e=W);-L^l@c4Y=%Z19>j8>vJ_f6(u3{ko2oIDeQNg+9uO2SS99)H&E z$VNdpP3v85hWLrPOsdjP=S1a#9@XvD1VSNDLR1dP{QVTuou@v8)vb>@1PM%-E^xKq zFbv}=y!7lko8{bzF9waUTMujKih-7Y09-uRf=5 zzem@Jbj&cb-AxwQ+9cT=Q*7>FEV!NMGkfR#X?81}l&E(nzn}NcbxY~4i{U@<4pHq! zgdW!H)|L7-2&Q&ilg@h$3df?BgNr&>vzMxJ+Er^zZ>J+sXKAjGP1==T@)_Ls-H2o8z+o9R144eXxhpFIwu zz01Dv(HVN>OL0EzJ+-tr-ivjpcG4UV=Rcg8f2l0Vl{gNY${%{oLUNA_zv_Xdb5_T| z<@Zl0y}WoC-9-W)iH;lA?%wI|jLz1-X?XsSt=4>k$1M6>uK25HzIJz#tY+*3Ug&6k z>GNv-?qy7(ju<65n`oBC6Nm(%2W`yb!V+XpOjhZPti^H&@{JppDp*E>Ym1a`-kV*S zEVy`mhbgH4yGA>SgZhXlh`E+>!P{*$U-}%g_E5g|o9B@g{LM68wA)aOx0OQ<MOm zEUDx1xxViAOAqtX+vhrD5%zYQv!x&>$ZmSvIU<-c2~tIoD>q9$ya^5mLXc%IOa3R@ zDx>=Im)rODTJJ?@>e-fWRZf{(lBM%!mG!BEd%VJp^pV3dUDq=mIHc%pqus;0~uSLxHp8FagKn%FL!0cNfP`oZkd{iT(t{+fl;jbM<_-cBLr{dTfJo-2_oa| zy3@~Od2y#crlFSvy<3`a$!zL*Z;*yFJ;Z|5yY)DPZO!ic*P-$=ljTr_h6%SCAygpqNAiZuok{53kLNPgw(fP!2)?PaC2PK%~N!Y8DuoM~Mnpmw=k8j^EUx z^S01_*SoQyTkyevEvMB4d+)|sLEJtms@6CLV zA-(6M|9I!?_pKUxzL|eThg$lHofi@DW*n|9_NNPPeFLv#aEfWCH7J;l2j|(tDXy-3 zo$cvTrA}mqWfI!myAgUR2IJ1TZah_qJ=LiP4{U8EOxUEYXACZEV_!V$jZJjcDzlmJ z9#VvFU)Qspux~e?3Z*Bke+f$~SrxS9CxG3{oCoHkH_cV(R^=PN)OZWUF{rkd^U`v4CWn0u! z@5*a9+nOm*-qZs>zMi*VkH}zq-?DPO`2s1o=3(V^^z)9 zDo@q8!HP}r%hSV0n6ekHb9k)HMA5ugvp*cWh4v#6EL5!?G{ly7Dt+_Kz|z)>lu51( z_;0fcc@iQmU986Brh-U?mSWKkG+xsaUI)Db6KO8F%=FdJ@!c?p55G?u$)zRdhF!Gg2)h^Bl)pQJ5BEfuw$J|U-@3;%X_ZJuEkVx5n) znR4Ic`*~m7+$PLKgwrj?&|wBMW$V)=OKV7dXpT>6TR+4yNGgc0N!~NqHJBfuv8zpk zhAnC~{HlacrQP0iY^GS0U>Pq0y&rsas6KAX(7hOSgEqt#jt&DgNrE83pKrE6FALLd z(!M;ZqZMn^jM{P8dASv0d9X|5Ru5W>mREe*Y2(usCj?O?yY;;N^}B-*Y8zMUvCXq1 z`ZwirQ9xh|-))q!^y^`_vyRp~ICtv*0s2(ERGS&qBDPonHP#|OU29){WXrzgxJW@{ z=wmW6qN#Z2VMcJD0gUUk@EDDI8#aoYqxT$U39uFxmrv&byIY*HuF-JY`UUiR-3V2NJvj| z$;zC@Oe+mtCDBchK~wTd2;?mw{be9ZR5hOGzOB1oSh-)z$#B| zi;e^sr<(6^AaFxWYk%1DA|*2h>@MxKoKy-XvbG+%4e`@BCXAL2b21Esr7y3L{9an* zNF3d2!FL-Ku~5u14yJGNI~RK}uyQp)-YL*%X$bCo6E6l-NgA92?5l`sSnjJlr#UDB>zMS(pp*9qK1qxr{f?=0gT%Y<8|~#j5i9 z=`2O^2HsU`-UUWPNn#kjZ)3J0Y%UmgmDJAr;I=uexO0mLh(Z?%+ZCiS5;PPy^#^Xuy$sS1JO0tsI4NG30o2cQz(L zYE6sw-*LI9amW&$PZ>0jKrTu0)f>J?iwYDt4X5*na=+dM*;@;~ruDSv_dRD*PxM~4 zFN@Le^Xr`T}gu&cxF!19KxZkVJ}5{R|9_( z-DV$}u{44Zr6MRB3W?rut$x}mEbh?9Gvif6|4r#Qi+kwn!= zP-lZ-qZ=>wWVwJd%Bi`<>@o2X5HADnJ9gTTI)|{AreDrmB9-Hmw!FEAn)4yvqhoGe zOdf?P6P2(7qX#E&1MkW_D@fgPA9Xa(ib?OE?yr6}StE~OWrtEiv!P_vVc*|h|5`~O zS2saP=QDkL8fx>)4c9JUiBHRU6~PdO)=cjX@S>;Rp>7kpkwCgGc20^eX8R5u$Nz=& z7SuQ3_FjAkx8Pub)|aqeeeId%m0;SY9PdjH01w8;Sn8PoukAgs+$f#wK2XlDQj{=cU-^0sJj)BpNLh!KlnKt`e)W5=EEE9*{k^s zUFiBB$XV{9RS1o(+i=oiFkE>$shZ4SfD8ls`GUrUYuQ71Gm-TEkgUCVi@xTtFf^B` zP-zPqaU+w*{T0JO89O5f3mPqK;-gB=+PT8w+m}JM`45{KPus*Ff&Omy@kO$RE%Rq- zRqw6WJh=sNYH^wHATY~kA75eSvB?p-ne)x|w-EA!qSuTk3X9Dvpo+n+tk0STKmA)& zSVu=L{v+f1)bjrt3ZK;$)|*~Id-H#Z;|tym{ey|~W@c+aucL>5F>CsQ7h?K&SCc|b z^J+;9C6ks-S~eXpmc{|Yq-B$qOV_fLk;T^QAD%K_hgp#AqZl!WVCfu3WVK a=4P?;mm&&Y&`O~vW?ny^JX-E?_U1o0H2{JD literal 0 HcmV?d00001 From e2d8e568b1e4bb23c81b59f379e18bfb06a31904 Mon Sep 17 00:00:00 2001 From: Zeying Zhu <50204836+zzylol@users.noreply.github.com> Date: Sun, 4 Oct 2026 17:49:03 +0000 Subject: [PATCH 3/4] Add persistent KLL pane merging and rolling Prometheus demo --- README.md | 3 +- asap-precompute-rs/Cargo.toml | 7 +- .../plugins/asap_sketches/sample.toml | 3 + .../src/bin/asap_kll_stream_demo.rs | 478 ++++++++++++++++ .../src/bin/demo/prometheus_export.rs | 55 +- asap-precompute-rs/src/config.rs | 6 +- asap-precompute-rs/src/kll_windows.rs | 512 ++++++++++++++++++ asap-precompute-rs/src/lib.rs | 1 + asap-precompute-rs/src/otap/config.rs | 24 +- asap-precompute-rs/src/otap/processor.rs | 97 +++- asap-precompute-rs/src/sketches/kll.rs | 33 +- asap-precompute-rs/src/window.rs | 4 +- asap-precompute-rs/tests/kll_windows.rs | 291 ++++++++++ demos/kll-grafana/grafana/dashboards/kll.json | 78 ++- demos/kll-grafana/verify-streaming.py | 84 +++ docs/demo-guide.md | 6 +- docs/images/kll-streaming-grafana.png | Bin 0 -> 74680 bytes docs/kll-windows.md | 174 ++++++ 18 files changed, 1803 insertions(+), 53 deletions(-) create mode 100644 asap-precompute-rs/src/bin/asap_kll_stream_demo.rs create mode 100644 asap-precompute-rs/src/kll_windows.rs create mode 100644 asap-precompute-rs/tests/kll_windows.rs create mode 100644 demos/kll-grafana/verify-streaming.py create mode 100644 docs/images/kll-streaming-grafana.png create mode 100644 docs/kll-windows.md diff --git a/README.md b/README.md index 900c5e2..14e46e7 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,8 @@ For a presentation-ready walkthrough of the real YAML pipeline integration, see the [live OTAP pipeline demo guide](./docs/demo-guide.md). The guide also includes a [Prometheus + Grafana setup](./docs/demo-guide.md#write-kll-estimates-to-prometheus-and-view-them-in-grafana) that writes the KLL p50/p99 estimates to Prometheus and displays them in a -provisioned Grafana dashboard. +provisioned Grafana dashboard. For continuous computation from retained +tumbling panes, see the [persistent rolling KLL demo](./docs/kll-windows.md). ```sh cd asap-precompute-rs diff --git a/asap-precompute-rs/Cargo.toml b/asap-precompute-rs/Cargo.toml index 71e7512..3c9fe4b 100644 --- a/asap-precompute-rs/Cargo.toml +++ b/asap-precompute-rs/Cargo.toml @@ -51,7 +51,7 @@ async-trait = { version = "0.1", optional = true } humantime-serde = { version = "1", optional = true } serde_json = { version = "1", optional = true } libc = { version = "0.2", optional = true } -tokio = { version = "1", features = ["sync", "rt", "time", "net"], optional = true } +tokio = { version = "1", features = ["sync", "rt", "time", "net", "macros", "signal"], optional = true } [dev-dependencies] proptest = "1" @@ -104,6 +104,11 @@ name = "asap-otap-demo" path = "src/bin/asap_otap_demo.rs" required-features = ["otap-engine"] +[[bin]] +name = "asap-kll-stream-demo" +path = "src/bin/asap_kll_stream_demo.rs" +required-features = ["otap-engine"] + [[bin]] name = "asap-stream-bench" path = "src/bin/asap_stream_bench.rs" diff --git a/asap-precompute-rs/plugins/asap_sketches/sample.toml b/asap-precompute-rs/plugins/asap_sketches/sample.toml index 2d8d40c..03fc2d9 100644 --- a/asap-precompute-rs/plugins/asap_sketches/sample.toml +++ b/asap-precompute-rs/plugins/asap_sketches/sample.toml @@ -23,6 +23,9 @@ plugin = "asap_sketches" ## Window size. Rust duration string, parsed via humantime; ## passed verbatim into `PrecomputeConfig::window`. window_size = "10s" + # window_slide = "5s" # KLL rolling lookback of 10s, emit every 5s + # Set transmit_sketch=false for overlapping sliding windows. Equal size + # and slide can transmit full disjoint panes for downstream merging. ## Output metric name stamped onto every emitted envelope. output_metric_name = "http_request_duration_ms" diff --git a/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs b/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs new file mode 100644 index 0000000..3b9f05f --- /dev/null +++ b/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs @@ -0,0 +1,478 @@ +//! Persistent real OTAP pipeline: synthetic scalars -> disjoint KLL panes -> +//! tumbling and rolling estimates -> Prometheus OTLP/HTTP. +#[path = "demo/prometheus_export.rs"] +#[allow(dead_code)] // The shared file also supplies the finite demo's file export. +mod prometheus_export; + +use asap_precompute_rs::envelope::{Encoding, SketchEnvelope, SketchType}; +use asap_precompute_rs::observation::KeyValue; +use asap_precompute_rs::otap::codec::{decode_pdata_to_observations, encode_envelopes_to_pdata}; +use async_trait::async_trait; +use linkme::distributed_slice; +use otel_arrow_dfe_config::{ + node::NodeUserConfig, + observed_state::{ObservedStateSettings, SendPolicy}, + pipeline::PipelineConfig, + policy::{ChannelCapacityPolicy, TelemetryPolicy}, + DeployedPipelineKey, PipelineGroupId, PipelineId, +}; +use otel_arrow_dfe_core_nodes as _; +use otel_arrow_dfe_engine::{ + capability::registry::Capabilities, + config::{ExporterConfig, ProcessorConfig, ReceiverConfig}, + context::{ControllerContext, PipelineContext}, + control::{ + pipeline_completion_msg_channel, runtime_ctrl_msg_channel, NodeControlMsg, + RuntimeControlMsg, + }, + error::{Error, ExporterErrorKind}, + exporter::ExporterWrapper, + local::{exporter, processor, receiver}, + message::{ExporterInbox, Message}, + node::NodeId, + processor::ProcessorWrapper, + receiver::ReceiverWrapper, + terminal_state::TerminalState, + ExporterFactory, MessageSourceLocalEffectHandlerExtension, ProcessorFactory, ReceiverFactory, +}; +use otel_arrow_dfe_otap::{ + pdata::OtapPdata, OTAP_EXPORTER_FACTORIES, OTAP_PIPELINE_FACTORY, OTAP_PROCESSOR_FACTORIES, + OTAP_RECEIVER_FACTORIES, +}; +use otel_arrow_dfe_pdata::{OtlpProtoBytes, TryIntoWithOptions}; +use otel_arrow_dfe_state::store::ObservedStateStore; +use otel_arrow_dfe_telemetry::InternalTelemetrySystem; +use std::{ + env, + sync::{Arc, Mutex, OnceLock}, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, +}; + +const SOURCE: &str = "urn:asap:receiver:kll_demo_traffic"; +const FORK: &str = "urn:asap:processor:kll_demo_fork"; +const SINK: &str = "urn:asap:exporter:kll_demo_prometheus"; +static OPTIONS: OnceLock = OnceLock::new(); +static FAILURE: Mutex> = Mutex::new(None); + +#[derive(Clone)] +struct Options { + endpoint: String, + window_seconds: u64, + slide_seconds: u64, + run_seconds: Option, +} +impl Options { + fn read() -> Result { + let mut options = Self { + endpoint: "http://localhost:9090/api/v1/otlp/v1/metrics".into(), + window_seconds: 60, + slide_seconds: 5, + run_seconds: None, + }; + let args: Vec = env::args().skip(1).collect(); + if args.iter().any(|a| a == "--help") { + println!("asap-kll-stream-demo [--prometheus-otlp-endpoint URL] [--window-seconds 60] [--slide-seconds 5] [--run-seconds N]\nRuns until Ctrl+C by default. Window must be a multiple of slide."); + std::process::exit(0); + } + for pair in args.chunks(2) { + if pair.len() != 2 { + return Err(format!("missing value for {}", pair[0])); + } + if pair[0] == "--prometheus-otlp-endpoint" { + options.endpoint = pair[1].clone(); + continue; + } + let value: u64 = pair[1] + .parse() + .map_err(|_| "duration must be a positive integer number of seconds")?; + if value == 0 { + return Err("duration must be positive".into()); + } + match pair[0].as_str() { + "--window-seconds" => options.window_seconds = value, + "--slide-seconds" => options.slide_seconds = value, + "--run-seconds" => options.run_seconds = Some(value), + other => return Err(format!("unknown option {other}")), + } + } + if options.window_seconds < options.slide_seconds + || !options.window_seconds.is_multiple_of(options.slide_seconds) + { + return Err("window must be a positive multiple of slide".into()); + } + if !(options.endpoint.starts_with("http://") || options.endpoint.starts_with("https://")) { + return Err("endpoint must be an HTTP(S) URL".into()); + } + Ok(options) + } +} +fn now_ms() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("wall clock") + .as_millis() as u64 +} + +fn traffic(sequence: u64, timestamp: u64) -> OtapPdata { + let envelopes: Vec<_> = (0..200) + .map(|offset| { + let index = sequence * 200 + offset; + let phase = ((timestamp / 10_000) % 3) as f64; + let value = if index.is_multiple_of(100) { + 300.0 + 200.0 * phase + } else { + 10.0 + 20.0 * phase + (index % 97) as f64 * 0.1 + }; + SketchEnvelope { + schema_version: 1, + sketch_type: SketchType::Unspecified, + agg_id: 0, + resource_labels: vec![KeyValue::new("service.name", "checkout")], + labels: vec![ + KeyValue::new("http.request.method", "GET"), + KeyValue::new("http.route", "/checkout"), + KeyValue::new("http.response.status_code", "200"), + ], + window_start_ms: timestamp, + window_end_ms: timestamp, + encoding: Encoding::Unspecified, + payload: vec![], + hash_spec: None, + metric_name: "request.duration".into(), + count: 0, + aggregation_temporality: 0, + value, + } + }) + .collect(); + encode_envelopes_to_pdata(&envelopes).expect("encode generated metrics") +} +struct TrafficReceiver; +#[async_trait(?Send)] +impl receiver::Receiver for TrafficReceiver { + async fn start( + self: Box, + mut ctrl: receiver::ControlChannel, + effects: receiver::EffectHandler, + ) -> Result { + let mut interval = tokio::time::interval(Duration::from_millis(100)); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + let mut sequence = 0; + loop { + tokio::select! { + message=ctrl.recv() => match message { Ok(NodeControlMsg::Shutdown {..}) | Err(_) => break, _ => {} }, + _=interval.tick() => { + effects.send_message_with_source_node(traffic(sequence,now_ms())).await?; + sequence+=1; + } + } + } + Ok(TerminalState::default()) + } +} +fn create_source( + _ctx: PipelineContext, + node: NodeId, + config: Arc, + runtime: &ReceiverConfig, + _caps: &Capabilities, +) -> Result, otel_arrow_dfe_config::error::Error> { + Ok(ReceiverWrapper::local( + TrafficReceiver, + node, + config, + runtime, + )) +} +#[distributed_slice(OTAP_RECEIVER_FACTORIES)] +static SOURCE_FACTORY: ReceiverFactory = ReceiverFactory { + name: SOURCE, + create: create_source, + wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, + validate_config: otel_arrow_dfe_config::validation::no_config, +}; + +// The pinned engine routes one destination per output port. Explicitly +// duplicate complete panes to two named ports for the comparison demo. +struct PaneFork; +#[async_trait(?Send)] +impl processor::Processor for PaneFork { + async fn process( + &mut self, + message: Message, + effects: &mut processor::EffectHandler, + ) -> Result<(), Error> { + if let Message::PData(pdata) = message { + effects + .send_message_with_source_node_to("tumbling", pdata.clone()) + .await?; + effects + .send_message_with_source_node_to("rolling", pdata) + .await?; + } + Ok(()) + } +} +fn create_fork( + _ctx: PipelineContext, + node: NodeId, + config: Arc, + runtime: &ProcessorConfig, + _caps: &Capabilities, +) -> Result, otel_arrow_dfe_config::error::Error> { + Ok(ProcessorWrapper::local(PaneFork, node, config, runtime)) +} +#[distributed_slice(OTAP_PROCESSOR_FACTORIES)] +static FORK_FACTORY: ProcessorFactory = ProcessorFactory { + name: FORK, + create: create_fork, + wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, + validate_config: otel_arrow_dfe_config::validation::no_config, +}; + +struct PrometheusExporter { + node: NodeId, +} +#[async_trait(?Send)] +impl exporter::Exporter for PrometheusExporter { + async fn start( + self: Box, + mut inbox: ExporterInbox, + _effects: exporter::EffectHandler, + ) -> Result { + let endpoint = OPTIONS.get().expect("options").endpoint.clone(); + loop { + match inbox.recv().await? { + Message::PData(pdata) => { + let error = |message: String| { + *FAILURE.lock().expect("export failure lock") = Some(message.clone()); + Error::ExporterError { + exporter: self.node.clone(), + kind: ExporterErrorKind::Transport, + error: message, + source_detail: String::new(), + } + }; + let observations = decode_pdata_to_observations(pdata.clone()) + .map_err(|e| error(e.to_string()))? + .observations; + let (_, payload) = pdata.into_parts(); + let encoded = + <_ as TryIntoWithOptions>::try_into_with_default(payload) + .map_err(|e| error(e.to_string()))?; + let OtlpProtoBytes::ExportMetricsRequest(bytes) = encoded else { + return Err(error("expected metric gauges".into())); + }; + let url = endpoint.clone(); + // Curl may block on network I/O; keep it off the local + // OTAP executor so ingestion and timers can continue. + let result = tokio::task::spawn_blocking(move || { + prometheus_export::export_bytes(&bytes, &url, None) + }) + .await + .map_err(|e| error(e.to_string()))?; + result.map_err(error)?; + for o in observations { + let quantile = o + .labels + .iter() + .find(|l| l.key == "quantile") + .map_or("?", |l| l.value.as_str()); + println!( + "exported window_end_ms={} metric={} quantile={} value={:.3}", + o.timestamp_ms, o.metric, quantile, o.value.float + ); + } + } + Message::Control(NodeControlMsg::Shutdown { .. }) => break, + Message::Control(_) => {} + } + } + Ok(TerminalState::default()) + } +} +fn create_sink( + _ctx: PipelineContext, + node: NodeId, + config: Arc, + runtime: &ExporterConfig, + _caps: &Capabilities, +) -> Result, otel_arrow_dfe_config::error::Error> { + Ok(ExporterWrapper::local( + PrometheusExporter { node: node.clone() }, + node, + config, + runtime, + )) +} +#[distributed_slice(OTAP_EXPORTER_FACTORIES)] +static SINK_FACTORY: ExporterFactory = ExporterFactory { + name: SINK, + create: create_sink, + wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, + validate_config: otel_arrow_dfe_config::validation::no_config, +}; + +fn pipeline_yaml(options: &Options) -> String { + let pane = options.slide_seconds; + let window = options.window_seconds; + format!( + r#"nodes: + source: + type: {SOURCE} + panes: + type: urn:asap:processor:asap_sketches + config: + sketch_type: kll + window_size: {pane}s + window_slide: {pane}s + output_metric_name: request.duration.pane + agg_id: 7 + sketch_params: {{ k: 400 }} + transmit_sketch: true + fork: + type: {FORK} + tumbling: + type: urn:asap:processor:asap_sketches + config: + sketch_type: kll + window_size: {pane}s + window_slide: {pane}s + output_metric_name: request.duration.estimate + agg_id: 7 + sketch_params: {{ k: 400 }} + transmit_sketch: false + quantiles: [0.5, 0.99] + rolling: + type: urn:asap:processor:asap_sketches + config: + sketch_type: kll + window_size: {window}s + window_slide: {pane}s + output_metric_name: request.duration.rolling_estimate + agg_id: 7 + sketch_params: {{ k: 400 }} + transmit_sketch: false + quantiles: [0.5, 0.99] + sink: + type: {SINK} +connections: + - {{ from: source, to: panes }} + - {{ from: panes, to: fork }} + - {{ from: 'fork["tumbling"]', to: tumbling }} + - {{ from: 'fork["rolling"]', to: rolling }} + - {{ from: tumbling, to: sink }} + - {{ from: rolling, to: sink }} +"# + ) +} +fn run(options: Options) -> Result<(), String> { + println!( + "Persistent OTAP KLL demo: {}s tumbling panes, {}s rolling lookback, {}s emission interval", + options.slide_seconds, options.window_seconds, options.slide_seconds + ); + println!( + "Prometheus endpoint: {}; stop with Ctrl+C", + options.endpoint + ); + OPTIONS + .set(options.clone()) + .map_err(|_| "options already set")?; + let config = PipelineConfig::from_yaml( + "asap-kll-stream".into(), + "demo".into(), + &pipeline_yaml(&options), + ) + .map_err(|e| e.to_string())?; + let telemetry = InternalTelemetrySystem::default(); + let ctx = ControllerContext::new(telemetry.registry()).pipeline_context_with( + PipelineGroupId::from("asap-kll-stream"), + PipelineId::from("demo"), + 0, + 1, + 0, + ); + let entity = ctx.register_pipeline_entity(); + let policy = ChannelCapacityPolicy::default(); + let runtime = OTAP_PIPELINE_FACTORY + .build( + ctx.clone(), + config, + policy.clone(), + TelemetryPolicy::default(), + None, + Default::default(), + None, + None, + ) + .map_err(|e| e.to_string())?; + let (runtime_tx, runtime_rx) = runtime_ctrl_msg_channel(policy.control.pipeline); + let (completion_tx, completion_rx) = pipeline_completion_msg_channel(policy.control.completion); + let observed = ObservedStateStore::new(&ObservedStateSettings::default(), telemetry.registry()); + let shutdown_tx = runtime_tx.clone(); + std::thread::spawn(move || { + let signal_runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("signal runtime"); + signal_runtime.block_on(async { + let lifetime = async { + if let Some(seconds) = options.run_seconds { tokio::time::sleep(Duration::from_secs(seconds)).await; } + else { std::future::pending::<()>().await; } + }; + let failed = async { + loop { + if FAILURE.lock().expect("export failure lock").is_some() { break; } + tokio::time::sleep(Duration::from_millis(100)).await; + } + }; + tokio::select! { + _=failed => {}, + signal=tokio::signal::ctrl_c() => { if let Err(e)=signal { eprintln!("Ctrl+C listener: {e}"); } }, + _=lifetime => {}, + } + }); + let _ = shutdown_tx.try_send(RuntimeControlMsg::Shutdown { + deadline: Instant::now() + Duration::from_secs(5), + reason: "streaming demo stopped".into(), + }); + }); + let key = DeployedPipelineKey { + pipeline_group_id: ctx.pipeline_group_id(), + pipeline_id: ctx.pipeline_id(), + core_id: 0, + deployment_generation: 0, + }; + let (_, pressure_rx) = tokio::sync::watch::channel( + otel_arrow_dfe_engine::memory_limiter::MemoryPressureChanged::initial(), + ); + let _guard = otel_arrow_dfe_engine::entity_context::set_pipeline_entity_key( + ctx.metrics_registry(), + entity, + ); + runtime + .run_forever( + key, + ctx, + observed.reporter(SendPolicy::default()), + telemetry.reporter(), + Duration::from_secs(1), + pressure_rx, + runtime_tx, + runtime_rx, + completion_tx, + completion_rx, + ) + .map_err(|e| e.to_string())?; + if let Some(error) = FAILURE.lock().expect("export failure lock").take() { + return Err(error); + } + println!("streaming demo stopped"); + Ok(()) +} +fn main() { + if let Err(error) = Options::read().and_then(run) { + eprintln!("{error}"); + std::process::exit(1); + } +} diff --git a/asap-precompute-rs/src/bin/demo/prometheus_export.rs b/asap-precompute-rs/src/bin/demo/prometheus_export.rs index eaf64a7..567b99d 100644 --- a/asap-precompute-rs/src/bin/demo/prometheus_export.rs +++ b/asap-precompute-rs/src/bin/demo/prometheus_export.rs @@ -10,7 +10,7 @@ use std::path::Path; use std::process::{Command, Stdio}; use std::time::{SystemTime, UNIX_EPOCH}; -fn timestamp_gauges(bytes: &[u8], now: u64) -> Result, String> { +fn prepare_gauges(bytes: &[u8], now: Option) -> Result, String> { let mut request = ExportMetricsServiceRequest::decode(bytes).map_err(|e| e.to_string())?; let mut points = 0; for resource in &mut request.resource_metrics { @@ -34,8 +34,19 @@ fn timestamp_gauges(bytes: &[u8], now: u64) -> Result, String> { } // Synthetic windows stay in the trace files. Export is a current // snapshot of the completed estimate, not historical telemetry. - point.start_time_unix_nano = 0; - point.time_unix_nano = now; + if let Some(now) = now { + point.start_time_unix_nano = 0; + point.time_unix_nano = now; + } + // Window boundaries are timestamps/metadata, not series + // dimensions: retaining them as labels creates a new + // Prometheus series for every emitted rolling window. + point.attributes.retain(|attribute| { + !matches!( + attribute.key.as_str(), + "sketch.window_start_ms" | "sketch.window_end_ms" + ) + }); points += 1; } } @@ -55,7 +66,20 @@ pub fn export(path: &Path, endpoint: &str) -> Result<(), String> { .duration_since(UNIX_EPOCH) .map_err(|e| e.to_string())? .as_nanos() as u64; - let body = timestamp_gauges(&std::fs::read(path).map_err(|e| e.to_string())?, now)?; + export_bytes( + &std::fs::read(path).map_err(|e| e.to_string())?, + endpoint, + Some(now), + ) +} + +/// Export estimated OTLP gauges. `None` preserves window-end timestamps for +/// the streaming demo; `Some` publishes a current snapshot for the finite demo. +pub fn export_bytes(bytes: &[u8], endpoint: &str, now: Option) -> Result<(), String> { + if !(endpoint.starts_with("http://") || endpoint.starts_with("https://")) { + return Err("Prometheus OTLP endpoint must be an http:// or https:// URL".into()); + } + let body = prepare_gauges(bytes, now)?; let mut child = Command::new("curl") .args([ "--silent", @@ -119,6 +143,7 @@ mod tests { metrics: vec![Metric { name: "request.duration.estimate".into(), data: Some(Data::Gauge(Gauge { data_points: vec![NumberDataPoint { + attributes: vec![KeyValue { key: "sketch.window_end_ms".into(), value: Some(AnyValue { value: Some(Value::StringValue("2000".into())) }) }], time_unix_nano: 2_000_000_000, value: Some(otel_arrow_dfe_pdata::proto::opentelemetry::metrics::v1::number_data_point::Value::AsDouble(198.0)), ..Default::default() @@ -131,12 +156,24 @@ mod tests { }], }; let updated = ExportMetricsServiceRequest::decode( - timestamp_gauges(&request.encode_to_vec(), 123456) + prepare_gauges(&request.encode_to_vec(), Some(123456)) .unwrap() .as_slice(), ) .unwrap(); let metric = &updated.resource_metrics[0].scope_metrics[0].metrics[0]; + let streaming = ExportMetricsServiceRequest::decode( + prepare_gauges(&request.encode_to_vec(), None) + .unwrap() + .as_slice(), + ) + .unwrap(); + let Some(Data::Gauge(streaming_gauge)) = + &streaming.resource_metrics[0].scope_metrics[0].metrics[0].data + else { + panic!("expected streaming gauge") + }; + assert_eq!(streaming_gauge.data_points[0].time_unix_nano, 2_000_000_000); assert_eq!(metric.name, "request.duration.estimate"); let Some(Data::Gauge(gauge)) = &metric.data else { panic!("expected gauge") @@ -156,8 +193,10 @@ mod tests { .unwrap() .attributes ); - assert!( - timestamp_gauges(&ExportMetricsServiceRequest::default().encode_to_vec(), 1).is_err() - ); + assert!(prepare_gauges( + &ExportMetricsServiceRequest::default().encode_to_vec(), + Some(1) + ) + .is_err()); } } diff --git a/asap-precompute-rs/src/config.rs b/asap-precompute-rs/src/config.rs index 3041825..ba8e032 100644 --- a/asap-precompute-rs/src/config.rs +++ b/asap-precompute-rs/src/config.rs @@ -20,8 +20,8 @@ pub type AggId = u64; /// Picks the windowing strategy. /// -/// Only [`AggregationMode::Tumbling`] is implemented; -/// [`AggregationMode::Sliding`] is deferred (see [`crate::window`]). +/// Tumbling uses the general runtime; sliding KLL uses +/// [`crate::kll_windows::KllRollingPrecompute`]. #[derive( Copy, Clone, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, )] @@ -33,7 +33,7 @@ pub enum AggregationMode { Tumbling, /// Rotates every [`WindowSpec::slide`]; observations land in /// every window whose `[start, end)` range covers their - /// timestamp. Only Tumbling is implemented today. + /// timestamp. KLL implements this by merging disjoint retained panes. Sliding, /// Processes one batch end-to-end with no windowing (`mode: batch`). Batch, diff --git a/asap-precompute-rs/src/kll_windows.rs b/asap-precompute-rs/src/kll_windows.rs new file mode 100644 index 0000000..6047f8f --- /dev/null +++ b/asap-precompute-rs/src/kll_windows.rs @@ -0,0 +1,512 @@ +//! Retained, mergeable KLL panes and aligned sliding-window estimates. +//! +//! A pane is a half-open tumbling interval. Range queries merge complete +//! sketches rather than quantiles or raw observations. Exact time selection +//! requires pane-aligned bounds; the quantile itself has KLL rank error. +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::sync::Mutex; +use std::time::Duration; + +use crate::config::{AggregationMode, PrecomputeConfig, PrecomputeConfigSet}; +use crate::envelope::{Encoding, SketchEnvelope, SketchType}; +use crate::matchers::series_attrs; +use crate::observation::{KeyValue, Observation, ObservationValueKind}; +use crate::precompute::{Precompute, PrecomputeError, Sketch, StatsSnapshot}; +use crate::sketches::KLLWrapper; + +fn invalid(message: &str) -> PrecomputeError { + PrecomputeError::Other(format!("KLL windows: {message}")) +} + +struct PaneSeries { + sketch: KLLWrapper, + resource_labels: Vec, + labels: Vec, + count: u64, +} + +/// In-memory KLL tumbling panes, retained for aligned time-range queries. +/// +/// Each observation is inserted once. Closed panes can also be merged from +/// full ASAPv1 envelopes produced upstream. Delivery must be exactly once: +/// sending the same full pane twice would count its observations twice. +/// Empty panes consume no storage; advancing time expires old panes. +pub struct KllWindowStore { + config: PrecomputeConfig, + pane_ms: u64, + retention_ms: u64, + closed_until: u64, + panes: BTreeMap>, + k: i32, + seed: Option, +} + +impl KllWindowStore { + /// Create a store. Retention must be a positive multiple of the pane size. + /// Only KLL/ASAPv1 full sketches are accepted; no delta replay or partial + /// pane splitting is supported. + pub fn new( + config: PrecomputeConfig, + pane: Duration, + retention: Duration, + ) -> Result { + let pane_ms = + u64::try_from(pane.as_millis()).map_err(|_| invalid("pane duration overflow"))?; + let retention_ms = u64::try_from(retention.as_millis()) + .map_err(|_| invalid("retention duration overflow"))?; + if !pane.as_nanos().is_multiple_of(1_000_000) + || !retention.as_nanos().is_multiple_of(1_000_000) + || pane_ms == 0 + || retention_ms < pane_ms + || !retention_ms.is_multiple_of(pane_ms) + { + return Err(invalid( + "retention must be a positive multiple of a nonzero millisecond pane", + )); + } + if config.sketch_type != SketchType::KLLSketch + || config.encoding != Encoding::Msgpack + || config.delta_transmission + { + return Err(invalid("requires KLL with full ASAPv1/Msgpack encoding")); + } + let k = config.sketch_params.get("k").copied().unwrap_or(200.0); + if !k.is_finite() || k < 8.0 || k > i32::MAX as f64 || k.fract() != 0.0 { + return Err(invalid("k must be an integer between 8 and i32::MAX")); + } + if config + .quantiles + .iter() + .any(|q| !q.is_finite() || !(0.0..=1.0).contains(q)) + { + return Err(invalid("quantiles must be finite values in [0, 1]")); + } + let seed = config + .sketch_params + .get("seed") + .copied() + .filter(|value| *value != 0.0) + .map(f64::to_bits); + Ok(Self { + config, + pane_ms, + retention_ms, + closed_until: 0, + panes: BTreeMap::new(), + k: k as i32, + seed, + }) + } + + /// Mark complete panes through `now_ms` and expire panes older than retention. + /// The watermark never moves backward, including after a clock adjustment. + pub fn advance(&mut self, now_ms: u64) { + let boundary = now_ms / self.pane_ms * self.pane_ms; + if boundary <= self.closed_until { + return; + } + self.closed_until = boundary; + let cutoff = self.closed_until.saturating_sub(self.retention_ms); + self.panes = self.panes.split_off(&cutoff); + } + + /// Number of nonempty panes currently retained (including the active pane). + pub fn retained_panes(&self) -> usize { + self.panes.len() + } + + /// Number of distinct series across all retained panes. + pub fn retained_series(&self) -> usize { + self.panes + .values() + .flat_map(|pane| pane.keys()) + .collect::>() + .len() + } + + /// Insert a finite scalar into its event-time pane. Once the watermark has + /// closed a pane, scalar observations for it are rejected as late. + pub fn observe(&mut self, observation: &Observation) -> Result<(), PrecomputeError> { + if !self.config.matches(observation) { + return Ok(()); + } + if observation.value.kind != ObservationValueKind::Float + || !observation.value.float.is_finite() + { + return Err(invalid("expected a finite scalar observation")); + } + if observation.timestamp_ms < self.closed_until { + return Err(PrecomputeError::LateData); + } + let start = observation.timestamp_ms / self.pane_ms * self.pane_ms; + start + .checked_add(self.pane_ms) + .ok_or_else(|| invalid("pane end overflow"))?; + self.advance(observation.timestamp_ms); + let (resource, labels) = self.labels(&observation.resource_labels, &observation.labels); + let key = self.config.series_key_for_entry(&resource, &labels); + self.admit(&key)?; + let k = self.k; + let seed = self.seed; + let entry = self + .panes + .entry(start) + .or_default() + .entry(key) + .or_insert_with(|| PaneSeries { + sketch: KLLWrapper::new(k, seed).with_wire_encoding(Encoding::Msgpack), + resource_labels: resource, + labels, + count: 0, + }); + entry.sketch.update(observation.value.float); + entry.count = entry.count.saturating_add(1); + Ok(()) + } + + /// Merge one full upstream tumbling pane. Multiple sources may contribute + /// to the same pane. Overlapping wide sketches and unaligned panes are + /// rejected because their observations cannot be assigned to one pane. + pub fn merge_pane(&mut self, envelope: &SketchEnvelope) -> Result<(), PrecomputeError> { + if envelope.sketch_type != SketchType::KLLSketch + || envelope.encoding != Encoding::Msgpack + || envelope.payload.is_empty() + { + return Err(invalid( + "inbound pane must contain a full ASAPv1 KLL sketch", + )); + } + if self.config.agg_id != 0 && envelope.agg_id != self.config.agg_id { + return Err(PrecomputeError::AggIdMismatch { + envelope: envelope.agg_id, + config: self.config.agg_id, + }); + } + if !envelope.window_start_ms.is_multiple_of(self.pane_ms) + || envelope.window_start_ms.checked_add(self.pane_ms) != Some(envelope.window_end_ms) + { + return Err(invalid( + "inbound sketch must cover exactly one aligned pane", + )); + } + let mut sketch = KLLWrapper::new(self.k, self.seed).with_wire_encoding(Encoding::Msgpack); + // Decode before changing state: invalid payloads cannot advance retention. + sketch.apply_delta_encoded(&envelope.payload, Encoding::Msgpack)?; + let cutoff = self.closed_until.saturating_sub(self.retention_ms); + if envelope.window_start_ms < cutoff { + return Err(PrecomputeError::LateData); + } + let (resource, labels) = self.labels(&envelope.resource_labels, &envelope.labels); + let key = self.config.series_key_for_entry(&resource, &labels); + self.advance(envelope.window_end_ms); + self.admit(&key)?; + let entry = self + .panes + .entry(envelope.window_start_ms) + .or_default() + .entry(key) + .or_insert_with(|| PaneSeries { + sketch: KLLWrapper::new(self.k, self.seed).with_wire_encoding(Encoding::Msgpack), + resource_labels: resource, + labels, + count: 0, + }); + entry.sketch.merge(&sketch)?; + entry.count = entry.count.saturating_add(envelope.count); + Ok(()) + } + + fn labels(&self, resource: &[KeyValue], labels: &[KeyValue]) -> (Vec, Vec) { + if self.config.global_aggregation { + return (vec![], vec![]); + } + ( + if self.config.omit_resource_attrs { + vec![] + } else { + resource.to_vec() + }, + series_attrs(labels, &self.config.aggregate_by), + ) + } + + fn admit(&self, key: &str) -> Result<(), PrecomputeError> { + if self.config.max_series == 0 || self.panes.values().any(|pane| pane.contains_key(key)) { + return Ok(()); + } + let series: HashSet<_> = self.panes.values().flat_map(|pane| pane.keys()).collect(); + if series.len() as u64 >= self.config.max_series { + return Err(PrecomputeError::SeriesCapExceeded); + } + Ok(()) + } + + /// Merge all complete panes in `[start_ms, end_ms)` into one full KLL per + /// series. Queries never consume or mutate stored sketches. Bounds must + /// align to panes, lie within retention, and exclude the active pane. + /// Missing panes mean no observations, not interpolated samples. + pub fn query( + &self, + start_ms: u64, + end_ms: u64, + ) -> Result, PrecomputeError> { + if start_ms >= end_ms + || !start_ms.is_multiple_of(self.pane_ms) + || !end_ms.is_multiple_of(self.pane_ms) + { + return Err(invalid( + "query bounds must describe a nonempty aligned range", + )); + } + if end_ms > self.closed_until + || start_ms < self.closed_until.saturating_sub(self.retention_ms) + { + return Err(invalid("query includes an open or expired pane")); + } + let mut merged: BTreeMap = BTreeMap::new(); + for (_, pane) in self.panes.range(start_ms..end_ms) { + for (key, source) in pane { + let entry = merged.entry(key.clone()).or_insert_with(|| PaneSeries { + sketch: KLLWrapper::new(self.k, self.seed) + .with_wire_encoding(Encoding::Msgpack), + resource_labels: source.resource_labels.clone(), + labels: source.labels.clone(), + count: 0, + }); + entry.sketch.merge(&source.sketch)?; + entry.count = entry.count.saturating_add(source.count); + } + } + merged + .into_values() + .map(|entry| { + Ok(SketchEnvelope { + schema_version: 1, + sketch_type: SketchType::KLLSketch, + agg_id: self.config.agg_id, + resource_labels: entry.resource_labels, + labels: entry.labels, + window_start_ms: start_ms, + window_end_ms: end_ms, + encoding: Encoding::Msgpack, + payload: entry.sketch.snapshot()?, + hash_spec: None, + metric_name: self.config.metric_name.clone(), + count: entry.count, + aggregation_temporality: 1, + value: 0.0, + }) + }) + .collect() + } + + /// Estimate configured quantiles after merging complete panes. This is a + /// quantile of the union of their observations, never a quantile of p99s. + pub fn estimate( + &self, + start_ms: u64, + end_ms: u64, + ) -> Result, PrecomputeError> { + self.quantile_over_time(start_ms, end_ms, &self.config.quantiles) + } + + /// Answer requested quantiles over an aligned range of retained raw-observation + /// panes. Quantiles may differ on each query; sketches are merged before + /// estimating and the retained state is unchanged. + pub fn quantile_over_time( + &self, + start_ms: u64, + end_ms: u64, + quantiles: &[f64], + ) -> Result, PrecomputeError> { + if quantiles + .iter() + .any(|q| !q.is_finite() || !(0.0..=1.0).contains(q)) + { + return Err(invalid("quantiles must be finite values in [0, 1]")); + } + let mut results = Vec::new(); + for envelope in self.query(start_ms, end_ms)? { + let mut sketch = + KLLWrapper::new(self.k, self.seed).with_wire_encoding(Encoding::Msgpack); + sketch.apply_delta_encoded(&envelope.payload, Encoding::Msgpack)?; + for point in sketch.estimate(quantiles, 0) { + let mut result = envelope.clone(); + result.payload.clear(); + result.encoding = Encoding::Unspecified; + result.value = point.value; + result.labels.extend(point.labels); + results.push(result); + } + } + Ok(results) + } +} + +struct RollingState { + store: KllWindowStore, + last_emit: Option, + upstream_complete_until: Option, + stats: StatsSnapshot, + closed: bool, +} + +/// KLL sliding estimator implementing the same runtime API as tumbling +/// precompute. `size` is the lookback and `slide` is the pane/emission interval. +/// It emits the most recent complete range once per boundary, including warmup +/// ranges with fewer observations. Missed ticks coalesce to the latest range. +pub struct KllRollingPrecompute { + state: Mutex, +} + +impl KllRollingPrecompute { + /// Construct an aligned sliding KLL estimator. Overlapping output is scalar; + /// when size equals slide, disjoint panes may be transmitted as sketches. + /// full upstream inputs must be disjoint tumbling panes of `slide` width. + pub fn new(config: PrecomputeConfig) -> Result { + if config.mode != AggregationMode::Sliding + || (config.transmit_sketch && config.window.size != config.window.slide) + || !config.window.allowed_lateness.is_zero() + { + return Err(invalid( + "overlapping sliding requires scalar output and zero allowed_lateness", + )); + } + if !config.transmit_sketch && config.quantiles.is_empty() { + return Err(invalid( + "scalar sliding output requires at least one quantile", + )); + } + let store = KllWindowStore::new(config.clone(), config.window.slide, config.window.size)?; + Ok(Self { + state: Mutex::new(RollingState { + store, + last_emit: None, + upstream_complete_until: None, + stats: StatsSnapshot::default(), + closed: false, + }), + }) + } +} + +impl Precompute for KllRollingPrecompute { + fn observe(&self, observation: &Observation) -> Result<(), PrecomputeError> { + let mut state = self.state.lock().expect("rolling KLL lock"); + if state.closed { + return Err(invalid("instance is closed")); + } + state.stats.input_observations = state.stats.input_observations.saturating_add(1); + if observation.value.kind == ObservationValueKind::Envelope { + drop(state); + return self.observe_envelope( + observation + .value + .envelope + .as_deref() + .ok_or_else(|| invalid("missing envelope"))?, + ); + } + let result = state.store.observe(observation); + match &result { + Err(PrecomputeError::LateData) => state.stats.dropped_late += 1, + Err(PrecomputeError::SeriesCapExceeded) => state.stats.dropped_overflow += 1, + _ => {} + } + result + } + fn observe_envelope(&self, envelope: &SketchEnvelope) -> Result<(), PrecomputeError> { + let mut state = self.state.lock().expect("rolling KLL lock"); + if state.closed { + return Err(invalid("instance is closed")); + } + state.stats.input_envelopes += 1; + let result = state.store.merge_pane(envelope); + if result.is_ok() { + state.upstream_complete_until = Some( + state + .upstream_complete_until + .unwrap_or(0) + .max(envelope.window_end_ms), + ); + } + match &result { + Err(PrecomputeError::LateData) => state.stats.dropped_late += 1, + Err(PrecomputeError::SeriesCapExceeded) => state.stats.dropped_overflow += 1, + _ => {} + } + result + } + fn tick(&self, now_ms: u64) -> Vec { + let mut state = self.state.lock().expect("rolling KLL lock"); + if state.closed { + return vec![]; + } + let wall_boundary = now_ms / state.store.pane_ms * state.store.pane_ms; + let end = state + .upstream_complete_until + .map_or(wall_boundary, |complete| complete.min(wall_boundary)); + if state.last_emit.is_some_and(|last| end <= last) || end == 0 { + return vec![]; + } + if state.upstream_complete_until.is_none() { + state.store.advance(now_ms); + } + let start = end.saturating_sub(state.store.retention_ms); + let results = if state.store.config.transmit_sketch { + state.store.query(start, end) + } else { + state.store.estimate(start, end) + } + .unwrap_or_default(); + if !results.is_empty() { + state.last_emit = Some(end); + } + state.stats.last_tick_ms = now_ms; + state.stats.last_emitted_envelopes = results.len() as u64; + state.stats.output_envelopes += results.len() as u64; + results + } + fn drain(&self) -> Vec { + // A partial pane cannot represent a complete rolling interval. Stop + // without inventing a future boundary or repeating the previous result. + vec![] + } + fn update_config(&self, configs: &PrecomputeConfigSet) { + let mut state = self.state.lock().expect("rolling KLL lock"); + if let Some(config) = configs + .configs + .iter() + .find(|c| c.agg_id == state.store.config.agg_id) + { + if *config != state.store.config { + if let Ok(replacement) = Self::new(config.clone()) { + let mut next = replacement.state.into_inner().expect("rolling KLL lock"); + next.stats = state.stats; + next.closed = state.closed; + *state = next; + } + } + } + } + fn active_config(&self) -> Option { + Some( + self.state + .lock() + .expect("rolling KLL lock") + .store + .config + .clone(), + ) + } + fn stats(&self) -> StatsSnapshot { + let state = self.state.lock().expect("rolling KLL lock"); + let mut stats = state.stats; + stats.active_series = state.store.retained_series() as i64; + stats + } + fn shutdown(&self) -> Result<(), PrecomputeError> { + self.state.lock().expect("rolling KLL lock").closed = true; + Ok(()) + } +} diff --git a/asap-precompute-rs/src/lib.rs b/asap-precompute-rs/src/lib.rs index 8943f61..edff0a0 100644 --- a/asap-precompute-rs/src/lib.rs +++ b/asap-precompute-rs/src/lib.rs @@ -21,6 +21,7 @@ pub mod adapter; pub mod config; pub mod control_channel; pub mod envelope; +pub mod kll_windows; pub mod matchers; pub mod observation; #[cfg(feature = "otap")] diff --git a/asap-precompute-rs/src/otap/config.rs b/asap-precompute-rs/src/otap/config.rs index e0219ab..86deae0 100644 --- a/asap-precompute-rs/src/otap/config.rs +++ b/asap-precompute-rs/src/otap/config.rs @@ -43,6 +43,12 @@ pub const SKETCH_TYPE_COUNTMINSKETCH: &str = "countminsketch"; /// runtime config + sketch factory + observer triple. #[derive(Debug, thiserror::Error)] pub enum ConfigError { + /// Sliding KLL pane/lookback configuration is invalid. + #[error("asap_sketches: invalid sliding window: {reason}")] + InvalidSlidingWindow { + /// Specific validation failure. + reason: String, + }, /// User-facing `sketch_type` string didn't match any of the five /// supported sketches. #[error("asap_sketches: unsupported sketch_type {value:?} (want one of: {valid})")] @@ -88,6 +94,8 @@ pub struct PluginConfig { pub sketch_type: String, /// Window rotation period. Mandatory. pub window_size: Duration, + /// Sliding KLL emission interval/pane size; zero selects tumbling windows. + pub window_slide: Duration, /// Output metric name stamped onto every emitted envelope. pub output_metric_name: String, /// Controller-plan join key. @@ -130,6 +138,7 @@ impl Default for PluginConfig { Self { sketch_type: SKETCH_TYPE_KLL.to_string(), window_size: Duration::from_secs(10), + window_slide: Duration::ZERO, output_metric_name: "asap_sketch".to_string(), agg_id: 0, sketch_params: SketchParams::new(), @@ -187,12 +196,18 @@ pub fn resolve(config: &PluginConfig) -> Result<(PrecomputeConfig, SketchDispatc encoding: config.encoding.name(), }); } + let sliding = !config.window_slide.is_zero(); let pcfg = PrecomputeConfig { agg_id: config.agg_id, sketch_type: dispatch.sketch_type, - mode: crate::config::AggregationMode::Tumbling, + mode: if sliding { + crate::config::AggregationMode::Sliding + } else { + crate::config::AggregationMode::Tumbling + }, window: WindowSpec { size: config.window_size, + slide: config.window_slide, ..Default::default() }, matchers: Vec::new(), @@ -211,6 +226,13 @@ pub fn resolve(config: &PluginConfig) -> Result<(PrecomputeConfig, SketchDispatc global_aggregation: config.global_aggregation, emit_window_stats: config.emit_window_stats, }; + if sliding { + crate::kll_windows::KllRollingPrecompute::new(pcfg.clone()).map_err(|e| { + ConfigError::InvalidSlidingWindow { + reason: e.to_string(), + } + })?; + } Ok((pcfg, dispatch)) } diff --git a/asap-precompute-rs/src/otap/processor.rs b/asap-precompute-rs/src/otap/processor.rs index fcd3cae..65ace8e 100644 --- a/asap-precompute-rs/src/otap/processor.rs +++ b/asap-precompute-rs/src/otap/processor.rs @@ -119,6 +119,10 @@ pub struct AsapSketchesUserConfig { /// Window rotation period — humantime format (e.g. `"10s"`). #[serde(with = "humantime_serde")] pub window_size: Duration, + /// Optional KLL sliding interval/pane size (for example `"5s"`). + /// Omit it for ordinary tumbling windows. + #[serde(default, with = "humantime_serde::option")] + pub window_slide: Option, /// Stamped onto every emitted envelope. pub output_metric_name: String, /// Controller-plan join key. Defaults to 0. @@ -167,6 +171,11 @@ impl AsapSketchesUserConfig { fn into_plugin_config(self) -> Result { use crate::config::SketchParams; + if self.window_slide.is_some_and(|slide| slide.is_zero()) { + return Err(OtapConfigError::InvalidUserConfig { + error: "window_slide must be positive when specified".into(), + }); + } let mut params = SketchParams::new(); for (k, v) in self.sketch_params { // Only numeric tuning knobs survive — strings / bools are @@ -180,6 +189,7 @@ impl AsapSketchesUserConfig { let cfg = PluginConfig { sketch_type: self.sketch_type, window_size: self.window_size, + window_slide: self.window_slide.unwrap_or_default(), output_metric_name: self.output_metric_name, agg_id: self.agg_id, sketch_params: params, @@ -206,8 +216,36 @@ const fn default_transmit_sketch() -> bool { true } +fn timer_period(config: &PluginConfig) -> Duration { + if config.window_slide.is_zero() { + config.window_size + } else { + config.window_slide + } +} + +fn build_precompute( + config: crate::config::PrecomputeConfig, + dispatch: super::config::SketchDispatch, +) -> Result, crate::precompute::PrecomputeError> { + if config.mode == crate::config::AggregationMode::Sliding { + Ok(Arc::new(crate::kll_windows::KllRollingPrecompute::new( + config, + )?)) + } else { + Ok(Arc::new(PrecomputeImpl::new( + Some(config), + Some(dispatch.factory), + Some(dispatch.observer), + ))) + } +} + fn requires_precompute_rebuild(current: &PluginConfig, next: &PluginConfig) -> bool { !current.sketch_type.eq_ignore_ascii_case(&next.sketch_type) + || current.window_slide != next.window_slide + || ((!current.window_slide.is_zero() || !next.window_slide.is_zero()) + && current.window_size != next.window_size) || current.sketch_params != next.sketch_params || current.encoding != next.encoding || current.default_key != next.default_key @@ -270,11 +308,11 @@ pub fn create_asap_sketches_processor( resolve_plugin_config(&plugin_config).map_err(|e| OtapConfigError::InvalidUserConfig { error: format!("asap_sketches: configuration: {e}"), })?; - let precompute: Arc = Arc::new(PrecomputeImpl::new( - Some(precompute_config), - Some(dispatch.factory), - Some(dispatch.observer), - )); + let precompute = build_precompute(precompute_config, dispatch).map_err(|e| { + OtapConfigError::InvalidUserConfig { + error: e.to_string(), + } + })?; Ok(ProcessorWrapper::local( AsapSketchesProcessor::new(precompute, plugin_config), @@ -312,7 +350,7 @@ pub struct AsapSketchesProcessor { impl AsapSketchesProcessor { fn new(precompute: Arc, plugin_config: PluginConfig) -> Self { - let window_size = plugin_config.window_size; + let window_size = timer_period(&plugin_config); let sketch_encoder = OtapSketchEncoder::with_sketch_params(plugin_config.sketch_params.clone()); Self { @@ -432,6 +470,12 @@ impl local::Processor for AsapSketchesProcessor { } } } + if !self.plugin_config.window_slide.is_zero() { + // Completed upstream panes already have a boundary. Emit + // promptly instead of waiting another whole slide interval. + let envs = self.precompute.tick(asap_wall_clock_ms()); + self.emit_envelopes(&envs, effect_handler).await?; + } Ok(()) } Message::Control(NodeControlMsg::TimerTick { .. }) => { @@ -465,11 +509,9 @@ impl local::Processor for AsapSketchesProcessor { let factory_changed = requires_precompute_rebuild(&self.plugin_config, &plugin_config); if factory_changed { - let replacement: Arc = Arc::new(PrecomputeImpl::new( - Some(pcfg.clone()), - Some(dispatch.factory), - Some(dispatch.observer), - )); + let Ok(replacement) = build_precompute(pcfg.clone(), dispatch) else { + return Ok(()); + }; let pending = self.precompute.drain(); self.emit_envelopes(&pending, effect_handler).await?; self.precompute = replacement; @@ -483,16 +525,13 @@ impl local::Processor for AsapSketchesProcessor { }); } - if plugin_config.window_size != self.window_size { + let period = timer_period(&plugin_config); + if period != self.window_size { if let Some(timer) = self.timer.take() { let _ = timer.cancel().await; } - self.timer = Some( - effect_handler - .start_periodic_timer(plugin_config.window_size) - .await?, - ); - self.window_size = plugin_config.window_size; + self.timer = Some(effect_handler.start_periodic_timer(period).await?); + self.window_size = period; } self.plugin_config = plugin_config; Ok(()) @@ -514,8 +553,26 @@ fn asap_wall_clock_ms() -> u64 { #[cfg(test)] mod tests { - //! Unit tests confined to config-shape validation — full lifecycle - //! integration tests live in `tests/otap_pipeline_e2e.rs`. + #[test] + fn sliding_config_selects_pane_timer_and_validates_alignment() { + let parse = |size: &str, slide: &str, transmit: bool| { + serde_json::from_value::(serde_json::json!({"sketch_type":"kll","window_size":size,"window_slide":slide,"output_metric_name":"rolling","encoding":"Msgpack","transmit_sketch":transmit,"quantiles":[0.5,0.99]})).unwrap().into_plugin_config() + }; + let config = parse("60s", "5s", false).unwrap(); + assert_eq!( + super::timer_period(&config), + std::time::Duration::from_secs(5) + ); + let (runtime, _) = super::resolve_plugin_config(&config).unwrap(); + assert_eq!(runtime.mode, crate::config::AggregationMode::Sliding); + assert!(parse("60s", "7s", false).is_err()); + assert!(parse("60s", "5s", true).is_err()); + assert!(parse("5s", "5s", true).is_ok()); + assert!(parse("5s", "0s", false).is_err()); + assert!(parse("3ms", "1.5ms", false).is_err()); + } + // Unit tests confined to config-shape validation — full lifecycle + // Integration tests live in `tests/otap_pipeline_e2e.rs`. use super::*; use serde_json::json; diff --git a/asap-precompute-rs/src/sketches/kll.rs b/asap-precompute-rs/src/sketches/kll.rs index e8a142e..483bb4d 100644 --- a/asap-precompute-rs/src/sketches/kll.rs +++ b/asap-precompute-rs/src/sketches/kll.rs @@ -28,14 +28,9 @@ pub struct KLLWrapper { sk: KLL, k: i32, seed: Option, - /// Snapshot of all observations seen since the last reset. Kept - /// alongside the in-tree compactor so [`Self::merge`] / - /// [`Self::apply_delta`] can replay the peer's items into our - /// compactor without poking at private state. The compactor - /// itself drives [`Self::snapshot`] via the wire-format accessors - /// added in `asap_sketchlib` (wire_levels/wire_items/wire_coin), - /// so cross-language byte-parity now lives against the compactor's - /// actual state, not this history vec. + /// Replay history used only by the legacy proto path. The ASAPv1 path + /// retains the compacted KLL state alone, keeping pane memory independent + /// of the number of incoming observations. history: Vec, /// Outbound wire format. KLL is full-only, so msgpack means the /// self-describing ASAPv1 form; proto means the legacy `KllState` envelope. @@ -87,7 +82,9 @@ impl KLLWrapper { /// Insert a single observation. pub fn update(&mut self, value: f64) { if value.is_finite() { - self.history.push(value); + if !self.wire_encoding.is_msgpack() { + self.history.push(value); + } self.sk.update(&value); } } @@ -100,10 +97,14 @@ impl KLLWrapper { I: IntoIterator, { let values = values.into_iter(); - self.history.reserve(values.size_hint().0); + if !self.wire_encoding.is_msgpack() { + self.history.reserve(values.size_hint().0); + } for value in values { if value.is_finite() { - self.history.push(value); + if !self.wire_encoding.is_msgpack() { + self.history.push(value); + } self.sk.update(&value); } } @@ -308,6 +309,16 @@ impl SketchObserver for KLLObserver { #[cfg(test)] mod tests { + #[test] + fn asapv1_keeps_compacted_state_without_raw_replay_history() { + use super::*; + let mut sketch = KLLWrapper::new(200, Some(42)).with_wire_encoding(Encoding::Msgpack); + sketch.update_batch((0..20_000).map(|value| value as f64)); + assert!(sketch.history.is_empty()); + // The compactor reports retained weight, not the exact raw input count. + assert!(sketch.inner().count().abs_diff(20_000) < 400); + assert!(sketch.snapshot().unwrap().len() < 20_000); + } use super::*; #[test] diff --git a/asap-precompute-rs/src/window.rs b/asap-precompute-rs/src/window.rs index b572d11..0657f60 100644 --- a/asap-precompute-rs/src/window.rs +++ b/asap-precompute-rs/src/window.rs @@ -42,8 +42,8 @@ pub struct SeriesEntry { pub count: u64, } -/// Per-Precompute window manager. Tumbling-only for now; -/// Sliding lands in a follow-up. +/// General tumbling-window manager. Retained KLL panes and sliding +/// estimates use [`crate::kll_windows`] instead. /// /// Locking is owned by the enclosing [`std::sync::Mutex`] in /// [`crate::precompute::PrecomputeImpl`]; this struct itself is diff --git a/asap-precompute-rs/tests/kll_windows.rs b/asap-precompute-rs/tests/kll_windows.rs new file mode 100644 index 0000000..844049e --- /dev/null +++ b/asap-precompute-rs/tests/kll_windows.rs @@ -0,0 +1,291 @@ +//! Pane merging, expiration, and aligned rolling KLL semantics. +use asap_precompute_rs::kll_windows::{KllRollingPrecompute, KllWindowStore}; +use asap_precompute_rs::precompute::PrecomputeError; +use asap_precompute_rs::{ + AggregationMode, Encoding, KeyValue, Observation, ObservationValue, Precompute, + PrecomputeConfig, PrecomputeConfigSet, SketchType, WindowSpec, +}; +use std::time::Duration; + +fn config() -> PrecomputeConfig { + PrecomputeConfig { + sketch_type: SketchType::KLLSketch, + encoding: Encoding::Msgpack, + mode: AggregationMode::Sliding, + transmit_sketch: false, + metric_name: "request.duration.rolling_estimate".into(), + quantiles: vec![0.5, 0.99], + window: WindowSpec { + size: Duration::from_millis(30), + slide: Duration::from_millis(10), + ..Default::default() + }, + ..Default::default() + } +} +fn observation(time: u64, value: f64, source: &str) -> Observation { + Observation::new( + time, + "request.duration", + vec![KeyValue::new("service.name", source)], + vec![KeyValue::new("route", "/checkout")], + ObservationValue::float(value), + ) +} +fn store() -> KllWindowStore { + KllWindowStore::new( + config(), + Duration::from_millis(10), + Duration::from_millis(30), + ) + .unwrap() +} + +#[test] +fn aligned_ranges_merge_tumbling_panes_without_consuming_them() { + let mut s = store(); + for (time, value) in [(1, 1.), (9, 2.), (10, 3.), (20, 4.)] { + s.observe(&observation(time, value, "checkout")).unwrap(); + } + s.advance(30); + let all = s.query(0, 30).unwrap(); + assert_eq!(all.len(), 1); + assert_eq!(all[0].count, 4); + assert!(all[0].payload.starts_with(b"ASAPv1")); + assert_eq!((all[0].window_start_ms, all[0].window_end_ms), (0, 30)); + assert_eq!(s.query(10, 30).unwrap()[0].count, 2); + assert_eq!(s.query(0, 30).unwrap()[0].count, 4); + assert!(s.query(1, 30).is_err()); + assert!(s.query(0, 40).is_err()); + assert!(s.query(10, 10).is_err()); +} + +#[test] +fn upstream_sources_merge_by_pane_and_preserve_series_identity() { + let mut receiver = store(); + for (value, source) in [(1., "checkout"), (3., "checkout"), (100., "other")] { + let mut upstream = store(); + upstream.observe(&observation(1, value, source)).unwrap(); + upstream.advance(10); + receiver + .merge_pane(&upstream.query(0, 10).unwrap()[0]) + .unwrap(); + } + let merged = receiver.query(0, 10).unwrap(); + assert_eq!(merged.len(), 2); + assert_eq!( + merged + .iter() + .find(|e| e.resource_labels[0].value == "checkout") + .unwrap() + .count, + 2 + ); + assert_eq!( + merged + .iter() + .find(|e| e.resource_labels[0].value == "other") + .unwrap() + .count, + 1 + ); + let mut wide = merged[0].clone(); + wide.window_end_ms = 20; + assert!(receiver.merge_pane(&wide).is_err()); + let mut malformed = merged[0].clone(); + malformed.payload = vec![1, 2, 3]; + malformed.window_start_ms = 100; + malformed.window_end_ms = 110; + assert!(receiver.merge_pane(&malformed).is_err()); + // A corrupt future frame did not evict retained observations. + assert_eq!(receiver.query(0, 10).unwrap().len(), 2); +} + +#[test] +fn expiration_boundaries_idle_gaps_and_late_observations() { + let mut s = store(); + s.observe(&observation(1, 1., "checkout")).unwrap(); + s.observe(&observation(10, 2., "checkout")).unwrap(); + s.advance(30); + assert_eq!(s.query(0, 30).unwrap()[0].count, 2); + assert!(matches!( + s.observe(&observation(29, 3., "checkout")), + Err(PrecomputeError::LateData) + )); + s.advance(40); + assert!(s.query(0, 30).is_err()); + assert_eq!(s.query(10, 40).unwrap()[0].count, 1); + s.advance(1000); + assert_eq!(s.retained_panes(), 0); + assert!(s.query(970, 1000).unwrap().is_empty()); + // Backward wall-clock motion cannot reopen expired panes. + s.advance(20); + assert!(s.query(10, 20).is_err()); +} + +#[test] +fn sliding_outputs_use_union_of_observations_and_evict_old_panes() { + let p = KllRollingPrecompute::new(config()).unwrap(); + for (time, value) in [(1, 1.), (11, 2.), (21, 3.)] { + p.observe(&observation(time, value, "checkout")).unwrap(); + } + let first = p.tick(30); + assert_eq!(first.len(), 2); + assert!(first + .iter() + .all(|e| e.count == 3 && e.window_start_ms == 0 && e.window_end_ms == 30)); + assert_eq!(first[0].value, 2.); + assert!(p.tick(35).is_empty()); + p.observe(&observation(31, 100., "checkout")).unwrap(); + let second = p.tick(40); + assert_eq!(second.len(), 2); + assert_eq!(second[0].value, 3.); + assert_eq!( + (second[0].window_start_ms, second[0].window_end_ms), + (10, 40) + ); + assert_eq!(second[1].value, 100.); + assert!(p.tick(100).is_empty()); + assert!(p.drain().is_empty()); + p.shutdown().unwrap(); + assert!(p.observe(&observation(101, 1., "checkout")).is_err()); +} + +#[test] +fn many_panes_stay_bounded_and_unequal_compacted_panes_keep_weights() { + let mut s = store(); + // Force compaction. One large pane and one tiny high-value pane make an + // unweighted merge or averaging pane quantiles visibly incorrect. + for value in 0..20_000 { + s.observe(&observation(1, value as f64, "checkout")) + .unwrap(); + } + s.observe(&observation(11, 1_000_000., "checkout")).unwrap(); + s.advance(20); + let estimated = s.estimate(0, 20).unwrap(); + assert_eq!(estimated[0].count, 20_001); + assert!((estimated[0].value - 10_000.).abs() < 800.); + assert!((estimated[1].value - 19_800.).abs() < 800.); + assert!(s.query(0, 20).unwrap()[0].payload.len() < 20_000); + let mut downstream = store(); + downstream.merge_pane(&s.query(0, 10).unwrap()[0]).unwrap(); + assert_eq!(downstream.query(0, 10).unwrap()[0].count, 20_000); + for pane in 2..1000 { + s.observe(&observation(pane * 10 + 1, pane as f64, "checkout")) + .unwrap(); + assert!(s.retained_panes() <= 4); + } +} + +#[test] +fn rolling_can_consume_upstream_panes_and_resets_on_window_change() { + let p = KllRollingPrecompute::new(config()).unwrap(); + let mut upstream = store(); + upstream.observe(&observation(1, 42., "checkout")).unwrap(); + upstream.advance(10); + p.observe_envelope(&upstream.query(0, 10).unwrap()[0]) + .unwrap(); + assert_eq!(p.tick(30)[0].value, 42.); + let mut next = config(); + next.window.size = Duration::from_millis(20); + p.update_config(&PrecomputeConfigSet { + version: 1, + configs: vec![next], + }); + assert!(p.tick(40).is_empty()); +} + +#[test] +fn invalid_windows_quantiles_and_nonfinite_values_are_rejected() { + let mut cfg = config(); + cfg.window.size = Duration::from_millis(25); + assert!(KllRollingPrecompute::new(cfg).is_err()); + let mut cfg = config(); + cfg.window.slide = Duration::ZERO; + assert!(KllRollingPrecompute::new(cfg).is_err()); + let mut cfg = config(); + cfg.quantiles = vec![f64::NAN]; + assert!(KllRollingPrecompute::new(cfg).is_err()); + let mut cfg = config(); + cfg.sketch_type = SketchType::DDSketch; + assert!(KllRollingPrecompute::new(cfg).is_err()); + let mut cfg = config(); + cfg.transmit_sketch = true; + assert!(KllRollingPrecompute::new(cfg).is_err()); + let mut s = store(); + assert!(s + .observe(&observation(1, f64::INFINITY, "checkout")) + .is_err()); + assert_eq!(s.retained_panes(), 0); +} + +#[test] +fn series_cap_applies_across_retained_panes() { + let mut cfg = config(); + cfg.max_series = 1; + let mut s = + KllWindowStore::new(cfg, Duration::from_millis(10), Duration::from_millis(30)).unwrap(); + s.observe(&observation(1, 1., "checkout")).unwrap(); + assert!(matches!( + s.observe(&observation(11, 2., "other")), + Err(PrecomputeError::SeriesCapExceeded) + )); + s.advance(50); + s.observe(&observation(51, 2., "other")).unwrap(); +} + +#[test] +fn upstream_timer_waits_for_new_complete_panes() { + let p = KllRollingPrecompute::new(config()).unwrap(); + assert!(p.tick(30).is_empty()); + let mut upstream = store(); + upstream.observe(&observation(21, 42., "checkout")).unwrap(); + upstream.advance(30); + p.observe_envelope(&upstream.query(20, 30).unwrap()[0]) + .unwrap(); + let first = p.tick(30); + assert_eq!(first[0].window_end_ms, 30); + assert_eq!(first[0].value, 42.); + assert!(p.tick(40).is_empty()); + upstream + .observe(&observation(31, 100., "checkout")) + .unwrap(); + upstream.advance(40); + p.observe_envelope(&upstream.query(30, 40).unwrap()[0]) + .unwrap(); + let next = p.tick(40); + assert_eq!(next[0].count, 2); + assert_eq!(next[0].window_end_ms, 40); +} + +#[test] +fn disjoint_mode_transmits_full_panes_for_downstream_rolling_queries() { + let mut cfg = config(); + cfg.window.size = cfg.window.slide; + cfg.transmit_sketch = true; + let creator = KllRollingPrecompute::new(cfg).unwrap(); + creator.observe(&observation(1, 42., "checkout")).unwrap(); + let pane = creator.tick(10); + assert_eq!(pane.len(), 1); + assert_eq!(pane[0].encoding, Encoding::Msgpack); + let mut retained = store(); + retained.merge_pane(&pane[0]).unwrap(); + let answer = retained.quantile_over_time(0, 10, &[0.25, 0.75]).unwrap(); + assert_eq!(answer.len(), 2); + assert!(answer.iter().all(|e| e.value == 42.)); + assert!(retained.quantile_over_time(0, 10, &[1.5]).is_err()); +} + +#[test] +fn small_high_value_pane_cannot_outweigh_a_large_compacted_low_value_pane() { + let mut s = store(); + for _ in 0..20_000 { + s.observe(&observation(1, 1., "checkout")).unwrap(); + } + for _ in 0..10 { + s.observe(&observation(11, 1_000_000., "checkout")).unwrap(); + } + s.advance(20); + let result = s.quantile_over_time(0, 20, &[0.5, 0.99]).unwrap(); + assert!(result.iter().all(|e| e.value == 1. && e.count == 20_010)); +} diff --git a/demos/kll-grafana/grafana/dashboards/kll.json b/demos/kll-grafana/grafana/dashboards/kll.json index a78a6da..1a0ca71 100644 --- a/demos/kll-grafana/grafana/dashboards/kll.json +++ b/demos/kll-grafana/grafana/dashboards/kll.json @@ -1,8 +1,8 @@ { "uid": "asap-kll", - "title": "ASAP KLL estimates", + "title": "ASAP KLL tumbling and rolling estimates", "schemaVersion": 39, - "version": 1, + "version": 2, "refresh": "5s", "time": { "from": "now-15m", @@ -12,14 +12,14 @@ { "id": 1, "type": "stat", - "title": "Latest KLL estimates", + "title": "Latest tumbling KLL estimates", "datasource": { "type": "prometheus", "uid": "asap-prometheus" }, "gridPos": { "h": 8, - "w": 24, + "w": 12, "x": 0, "y": 0 }, @@ -50,7 +50,7 @@ { "id": 2, "type": "timeseries", - "title": "KLL estimates over time", + "title": "Tumbling KLL estimates over time", "datasource": { "type": "prometheus", "uid": "asap-prometheus" @@ -76,6 +76,74 @@ "overrides": [] }, "options": {} + }, + { + "id": 3, + "type": "stat", + "title": "Latest rolling KLL estimates", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "targets": [ + { + "refId": "A", + "expr": "request_duration_rolling_estimate{quantile=~\"0.5|0.99\"}", + "legendFormat": "quantile {{quantile}}", + "instant": true + } + ], + "fieldConfig": { + "defaults": { + "decimals": 3 + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } + } + }, + { + "id": 4, + "type": "timeseries", + "title": "Rolling KLL estimates over time", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "targets": [ + { + "refId": "A", + "expr": "request_duration_rolling_estimate{quantile=~\"0.5|0.99\"}", + "legendFormat": "quantile {{quantile}}", + "instant": false + } + ], + "fieldConfig": { + "defaults": { + "decimals": 3 + }, + "overrides": [] + }, + "options": {} } ] } diff --git a/demos/kll-grafana/verify-streaming.py b/demos/kll-grafana/verify-streaming.py new file mode 100644 index 0000000..8f4d358 --- /dev/null +++ b/demos/kll-grafana/verify-streaming.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Verify new tumbling/rolling samples continuously reach Prometheus and Grafana.""" +import argparse +import json +import os +import subprocess +import tempfile +import time +import urllib.parse +import urllib.request + + +def query(base, expression, grafana=False): + path = '/api/v1/query?' + urllib.parse.urlencode({'query': expression}) + if grafana: + path = '/api/datasources/proxy/uid/asap-prometheus' + path + with urllib.request.urlopen(base.rstrip('/') + path, timeout=10) as response: + payload = json.load(response) + assert payload['status'] == 'success', payload + return payload['data']['result'] + + +def counts(base, metric): + return {row['metric']['quantile']: int(float(row['value'][1])) for row in query( + base, 'count_over_time(' + metric + '{quantile=~"0.5|0.99"}[5m])')} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('binary', help='path to asap-kll-stream-demo') + parser.add_argument('--prometheus', default='http://localhost:9090') + parser.add_argument('--grafana', default='http://localhost:3000') + args = parser.parse_args() + metrics = ['request_duration_estimate', 'request_duration_rolling_estimate'] + initial = {metric: counts(args.prometheus, metric) for metric in metrics} + observed = [] + with tempfile.TemporaryFile(mode='w+') as trace: + process = subprocess.Popen([ + os.path.abspath(args.binary), '--window-seconds', '6', '--slide-seconds', '1', + '--run-seconds', '16', '--prometheus-otlp-endpoint', + args.prometheus.rstrip('/') + '/api/v1/otlp/v1/metrics', + ], stdout=trace, stderr=subprocess.STDOUT) + try: + deadline = time.monotonic() + 40 + while process.poll() is None: + assert time.monotonic() < deadline, 'streaming demo failed to stop' + for metric in metrics: + rows = query(args.prometheus, metric + '{quantile=~"0.5|0.99"}') + if not rows: + continue + assert len(rows) == 2, ('expected stable series, not new window labels', rows) + assert {row['metric']['quantile'] for row in rows} == {'0.5', '0.99'} + assert all('sketch_window_start_ms' not in row['metric'] and + 'sketch_window_end_ms' not in row['metric'] for row in rows) + if metric.endswith('rolling_estimate'): + observed.append(float(next(row['value'][1] for row in rows + if row['metric']['quantile'] == '0.5'))) + time.sleep(1) + assert process.returncode == 0, 'streaming demo returned an error' + finally: + if process.poll() is None: + process.terminate() + try: + process.wait(timeout=5) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + trace.seek(0) + print(trace.read(), end='') + for metric in metrics: + after = counts(args.prometheus, metric) + assert all(after.get(q, 0) >= initial[metric].get(q, 0) + 6 for q in ['0.5', '0.99']), (initial, after) + expression = metric + '{quantile=~"0.5|0.99"}' + prometheus = {row['metric']['quantile']: float(row['value'][1]) + for row in query(args.prometheus, expression)} + grafana = {row['metric']['quantile']: float(row['value'][1]) + for row in query(args.grafana, expression, grafana=True)} + assert prometheus == grafana, (prometheus, grafana) + assert max(observed) - min(observed) > 5, 'rolling median did not follow the changing input' + print('Verified repeated tumbling/rolling writes, stable series, changing rolling values, and matching Grafana queries.') + + +if __name__ == '__main__': + main() diff --git a/docs/demo-guide.md b/docs/demo-guide.md index 9d387c3..6c96188 100644 --- a/docs/demo-guide.md +++ b/docs/demo-guide.md @@ -69,6 +69,9 @@ cargo test --features otap-engine --test otap_pipeline_e2e The runnable binary additionally asserts that the final output contains p50 and p99 after the four child processes finish successfully. +For a persistent stream with mergeable tumbling panes and rolling quantiles, +see [the continuous KLL demo](./kll-windows.md). + ## Write KLL estimates to Prometheus and view them in Grafana The optional export sends the validated estimator output as OTLP/HTTP protobuf @@ -106,7 +109,8 @@ previous samples within the selected time range. Values use the demo input's units (the sequential input is synthetic). The outbound copy uses the current wall-clock timestamp, so the synthetic 1970-era window remains available in `out.otlp` and debug traces while the dashboard shows the completed estimate -now. Original gauge values, resource attributes, and point labels are preserved. +now. Original gauge values, resource attributes, and series labels are preserved; +window-boundary metadata is excluded from Prometheus labels to keep series stable. Series labels stored on OTAP scopes (including `quantile`) are also copied to gauge point attributes, which Prometheus uses to identify separate series. Only the `kll` scenario supports this option. HTTP errors, invalid OTLP diff --git a/docs/images/kll-streaming-grafana.png b/docs/images/kll-streaming-grafana.png new file mode 100644 index 0000000000000000000000000000000000000000..54e36d76951337bd47c324a9bbd99a2e8478eb26 GIT binary patch literal 74680 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

IB8yM-)U32Ve(IE{ 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 P["KLL tumbling panes
5 seconds each"] - P --> T["Tumbling estimates
p50 / p99"] - P --> R["Merge retained panes
60-second rolling p50 / p99"] - T --> E["OTLP/HTTP export"] - R --> E - E --> M[Prometheus] - M --> G["Grafana
refresh every 5 seconds"] + GA["generator A"] --> BA["branch A
1 CPU"] + GB["generator B"] --> BB["branch B
1 CPU"] + BA -->|"OTLP/HTTP
KLL pane or sorted run"| M["merge
1 CPU"] + BB --> M + M --> E["estimate
1 CPU
tumbling + rolling p50/p99"] + E --> V["validating backend"] + V -. "control /stats" .-> D["run-streaming.py --demo
:9465/metrics"] + D --> P[Prometheus] --> G[Grafana] ``` -## Run the persistent demo +Each branch builds one KLL sketch (`k=400`) per count-aligned window and +sends it as an ASAPv1 envelope; merge combines the two sources and estimate +answers p50/p99. Exact sends every sorted value instead. With +`--rolling-windows N`, estimate also merges the last N window sketches (exact +re-sorts the last N windows' values) for rolling p50/p99. The backend checks +every answer against the exact quantiles of the replayed corpus: exact must +match, KLL must be within 5%. -From the repository root: +## Run the demo -```sh -docker compose -f demos/kll-grafana/compose.yaml up -d -cargo run --manifest-path asap-precompute-rs/Cargo.toml \ - --features otap-engine --bin asap-kll-stream-demo -``` - -Open . The default lookback is 60 seconds, -with a five-second pane/emission interval. The synthetic input changes its -latency distribution every ten seconds; tumbling and rolling estimates follow -that input at different rates. It generates about 2,000 observations per -second. Values are synthetic milliseconds, not measurements of this machine. - -To compute a five-minute rolling quantile every five seconds: +Linux with Docker and Docker Compose. From the repository root: ```sh -cargo run --manifest-path asap-precompute-rs/Cargo.toml \ - --features otap-engine --bin asap-kll-stream-demo -- \ - --window-seconds 300 --slide-seconds 5 -``` - -Use `--prometheus-otlp-endpoint URL` for another Prometheus instance and -`--run-seconds 60` for a bounded run. Without `--run-seconds`, the process stays -running until Ctrl+C. Shutdown does not publish incomplete panes or invent a -future window timestamp. HTTP/OTLP export failures terminate the demo. - -The dashboard time picker controls displayed history; it does not change the -computed lookback. Change `--window-seconds` to change the rolling lookback. -The dashboard queries estimates that OTAP has already computed: - -```promql -request_duration_estimate{quantile=~"0.5|0.99"} -request_duration_rolling_estimate{quantile=~"0.5|0.99"} +demos/kll-grafana/run-demo.sh # Ctrl+C stops it +demos/kll-grafana/run-demo.sh --demo-rate 100000 # signals/s per source ``` -Each emission updates the same series with a new window-end timestamp. -`sketch.window_start_ms` and `sketch.window_end_ms` are removed from exported -point attributes because treating them as Prometheus labels would create new -series for every window. Series attributes, including `quantile`, are copied -from OTAP scope attributes onto points. Prometheus stores estimates; it does -not store the retained KLL panes or perform their merges. - -![Live tumbling and rolling quantiles in Grafana](images/kll-streaming-grafana.png) - -The screenshot captures the running demo with a six-second lookback and -one-second panes, showing both modes receiving repeated samples. +The script builds `asap-stream-bench`, the benchmark image, and the +Prometheus/Grafana stack, then runs both pipelines with 65,536-observation +windows, six-window rolling results, and two generator CPUs per source. Each +pipeline needs 2 + 4 + 1 CPUs. Extra arguments go to +`benchmarks/run-streaming.py`. Open +. + +The dashboard shows, per scenario: + +- backend-validated throughput, and processor CPU-seconds per million signals + (branches + merge + estimate); +- CPU cores, data-network egress and resident memory of each pinned process; +- tumbling and rolling p50/p99 against the exact reference, and their + relative error. + +Rates are averaged over the last 30 seconds; windows complete in bursts. Every +window replays the same deterministic corpus, so the quantile lines are flat +by design: the moving signals are throughput and resource use. + +![KLL vs exact multi-process streaming dashboard](images/kll-streaming-grafana.png) + +The screenshot is from a 56-core x86 server at 50,000 +signals/s per source. KLL keeps up with the offered 100,000 signals/s using +0.96 processor CPU-seconds per million signals. Exact uses 23 and is +back-pressured to about 68,000 signals/s although no exact process exceeds +0.8 CPU cores, consistent with every value crossing merge in 1,024-value +requests with one request in flight per hop. See +[benchmark results](#benchmark-results). + +## Benchmark results + +`benchmarks/run-streaming.py --scenarios raw exact kll --window-points 65536 +--repetitions 3` on a 56-core x86 server (Ubuntu 22.04), four generator +CPUs per source, one dedicated CPU per processor. Median backend-validated +signals/s over three runs (both sources combined): + +| Offered | Raw | Exact | KLL | +| ---: | ---: | ---: | ---: | +| 20,000 | 21,825 | 21,797 | 21,800 | +| 50,000 | 48,025 | 47,962 | 47,992 | +| 100,000 | 100,281 | 61,038 | 100,249 | +| 200,000 | 200,542 | 61,033 | 200,486 | +| 400,000 | 296,472 | 61,042 | 396,609 | +| 600,000 | 300,830 | 52,322 | 601,453 | +| 800,000 | 305,168 | 47,961 | 797,614 | + +(At 20,000 offered, a run's 30-second interval rounds to whole windows.) + +![Validated throughput vs offered load](images/kll-streaming-throughput.png) + +Exact plateaus near 61,000 signals/s; KLL follows the offered load to the +highest rate tested, and raw forwarding saturates near 300,000. By the +[capacity criteria](../benchmarks/CAPACITY_DESIGN.md) (delivery, backlog and +p99 window latency), the largest sustainable offered rate per source is 10,000 +for exact, 100,000 for raw and at least 400,000 for KLL. Exact already +misses the latency bound at 25,000 per source (p99 6.0 s). + +Summed over branch A, branch B, merge and estimate, at the same offered load: + +| Offered per source | Exact CPU cores | KLL CPU cores | Exact egress | KLL egress | +| ---: | ---: | ---: | ---: | ---: | +| 10,000 | 0.63 | 0.031 | 36.7 Mbit/s | 0.1 Mbit/s | +| 25,000 | 1.41 | 0.063 | 84.4 Mbit/s | 0.2 Mbit/s | +| 50,000 | 1.69 (back-pressured) | 0.117 | 101.6 Mbit/s | 0.4 Mbit/s | + +KLL answers stayed within the backend's 5% tolerance in every window +(p50 0.5%, p99 1.6% relative error); exact answers matched exactly. + +The Compose stack uses host networking so Prometheus, Grafana and the metrics +endpoint listen only on `127.0.0.1` (ports 9090, 3000 and 9465; +`PROMETHEUS_PORT` and `GRAFANA_PORT` change the first two). The finite +`asap-otap-demo` export described in the [demo guide](./demo-guide.md) still +pushes to the same Prometheus over OTLP. ## Configure an OTAP rolling estimator @@ -153,17 +196,17 @@ of all original observations in the selected panes. ## Verification -Start the Compose backend and build the persistent binary, then run: +With the image built and the Compose stack up (`run-demo.sh` does both): ```sh -python3 demos/kll-grafana/verify-streaming.py \ - asap-precompute-rs/target/debug/asap-kll-stream-demo +python3 demos/kll-grafana/verify-streaming.py ``` -This runs a 16-second demo with a six-second lookback and one-second panes. -It verifies repeated writes for both quantiles in both modes, stable series -labels, changing rolling values, and matching queries through Grafana's -provisioned datasource. Alternative URLs use `--prometheus` and `--grafana`. +This runs both pipelines for 60 seconds and checks per-process throughput and +CPU series for all four processors, tumbling and rolling results within +tolerance (exact: zero error), and that Grafana's datasource and the +provisioned dashboard return the same series. Pass `--docker-command +'sudo -n docker'` when Docker needs sudo. The runtime tests exercise aligned range merging, compacted unequal-size pane weights, series identity, expiration, idle gaps, late data, invalid ranges, @@ -172,3 +215,10 @@ upstream completion timing, and configuration changes: ```sh cargo test --manifest-path asap-precompute-rs/Cargo.toml --test kll_windows ``` + +The benchmark model tests cover rolling estimates over retained windows: + +```sh +cargo test --manifest-path asap-precompute-rs/Cargo.toml \ + --features stream-benchmark --bin asap-stream-bench +```

IB8yM-)U32Ve(IE{ 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 P["KLL tumbling panes
5 seconds each"] + P --> T["Tumbling estimates
p50 / p99"] + P --> R["Merge retained panes
60-second rolling p50 / p99"] + T --> E["OTLP/HTTP export"] + R --> E + E --> M[Prometheus] + M --> G["Grafana
refresh every 5 seconds"] +``` + +## Run the persistent demo + +From the repository root: + +```sh +docker compose -f demos/kll-grafana/compose.yaml up -d +cargo run --manifest-path asap-precompute-rs/Cargo.toml \ + --features otap-engine --bin asap-kll-stream-demo +``` + +Open . The default lookback is 60 seconds, +with a five-second pane/emission interval. The synthetic input changes its +latency distribution every ten seconds; tumbling and rolling estimates follow +that input at different rates. It generates about 2,000 observations per +second. Values are synthetic milliseconds, not measurements of this machine. + +To compute a five-minute rolling quantile every five seconds: + +```sh +cargo run --manifest-path asap-precompute-rs/Cargo.toml \ + --features otap-engine --bin asap-kll-stream-demo -- \ + --window-seconds 300 --slide-seconds 5 +``` + +Use `--prometheus-otlp-endpoint URL` for another Prometheus instance and +`--run-seconds 60` for a bounded run. Without `--run-seconds`, the process stays +running until Ctrl+C. Shutdown does not publish incomplete panes or invent a +future window timestamp. HTTP/OTLP export failures terminate the demo. + +The dashboard time picker controls displayed history; it does not change the +computed lookback. Change `--window-seconds` to change the rolling lookback. +The dashboard queries estimates that OTAP has already computed: + +```promql +request_duration_estimate{quantile=~"0.5|0.99"} +request_duration_rolling_estimate{quantile=~"0.5|0.99"} +``` + +Each emission updates the same series with a new window-end timestamp. +`sketch.window_start_ms` and `sketch.window_end_ms` are removed from exported +point attributes because treating them as Prometheus labels would create new +series for every window. Series attributes, including `quantile`, are copied +from OTAP scope attributes onto points. Prometheus stores estimates; it does +not store the retained KLL panes or perform their merges. + +![Live tumbling and rolling quantiles in Grafana](images/kll-streaming-grafana.png) + +The screenshot captures the running demo with a six-second lookback and +one-second panes, showing both modes receiving repeated samples. + +## Configure an OTAP rolling estimator + +This processor consumes scalar observations directly, or a stream of complete +ASAPv1 KLL panes of `window_slide` width: + +```yaml +type: urn:asap:processor:asap_sketches +config: + sketch_type: kll + encoding: Msgpack + window_size: 300s + window_slide: 5s + output_metric_name: request.duration.rolling_estimate + agg_id: 7 + sketch_params: { k: 400 } + transmit_sketch: false + quantiles: [0.5, 0.99] +``` + +An upstream pane creator uses `window_size: 5s`, `window_slide: 5s`, and +`transmit_sketch: true`. Equal size and slide produce disjoint tumbling panes +that can be merged downstream. Overlapping sliding windows only emit scalar +estimates, preventing their overlapping sketches from being counted twice. +Omitting `window_slide` retains the original tumbling runtime behavior. + +Pane boundaries align to Unix time and are half-open `[start, end)`. The +lookback must be an integer multiple of the pane width, and both durations +must be whole milliseconds. Sliding is currently KLL-only with full Msgpack +encoding, no delta transmission, and no late scalar updates to closed panes. +The first results use the observations available during warmup; a complete +lookback becomes available after the process has run for that duration. + +For upstream sketch input, the estimator waits for a complete pane rather than +letting a wall-clock timer race ahead of delivery. An upstream producer must +provide each complete pane once. If several producers contribute to a pane, +merge their contributions before publishing that complete pane to the sliding +processor; this change does not introduce a distributed completeness barrier +or duplicate-delivery detection. A delayed pane within retained history can be +merged, but a previously emitted range is not retroactively republished. + +## Query retained tumbling panes in Rust + +The host-neutral `KllWindowStore` supports raw observations and merging full +upstream panes, plus reusable aligned range queries: + +```rust +use std::time::Duration; +use asap_precompute_rs::{Encoding, PrecomputeConfig, SketchType}; +use asap_precompute_rs::kll_windows::KllWindowStore; + +let config = PrecomputeConfig { + sketch_type: SketchType::KLLSketch, + encoding: Encoding::Msgpack, + quantiles: vec![0.5, 0.99], + ..Default::default() +}; +let mut panes = KllWindowStore::new( + config, Duration::from_secs(5), Duration::from_secs(300), +)?; +// panes.observe(&observation)?; +// panes.merge_pane(&upstream_full_pane)?; +panes.advance(300_000); +let merged_sketches = panes.query(0, 300_000)?; +let quantile_gauges = panes.quantile_over_time(0, 300_000, &[0.5, 0.95, 0.99])?; +``` + +`query` returns one full merged KLL envelope per series; `quantile_over_time` +merges first and estimates the requested quantiles, which may vary per query. +Neither query consumes stored panes. Bounds must align to pane boundaries and +exclude open or expired panes. Unaligned ranges are rejected: a compacted +sketch cannot split a partially overlapping pane into exact observations. +Quantile accuracy remains approximate according to KLL's rank error, even +when temporal selection is exact at pane boundaries. + +The store retains at most `retention / pane_width` completed panes plus the +active pane. Idle `advance` calls expire old state, and a configured +`max_series` cap applies across retained panes (new series are rejected at the +cap). Retained state is in memory; restarts discard it. The ASAPv1 KLL wrapper +retains compacted items without a raw-observation replay history. + +This differs from applying PromQL `quantile_over_time` to an exported p99 +series: that would compute a quantile of earlier p99 estimates. Here the KLLs +are merged with their compaction weights, so the result estimates the quantile +of all original observations in the selected panes. + +## Verification + +Start the Compose backend and build the persistent binary, then run: + +```sh +python3 demos/kll-grafana/verify-streaming.py \ + asap-precompute-rs/target/debug/asap-kll-stream-demo +``` + +This runs a 16-second demo with a six-second lookback and one-second panes. +It verifies repeated writes for both quantiles in both modes, stable series +labels, changing rolling values, and matching queries through Grafana's +provisioned datasource. Alternative URLs use `--prometheus` and `--grafana`. + +The runtime tests exercise aligned range merging, compacted unequal-size pane +weights, series identity, expiration, idle gaps, late data, invalid ranges, +upstream completion timing, and configuration changes: + +```sh +cargo test --manifest-path asap-precompute-rs/Cargo.toml --test kll_windows +``` From a0466dfd1a67159cefd666cdda3a7f68741b64a1 Mon Sep 17 00:00:00 2001 From: Zeying Zhu <50204836+zzylol@users.noreply.github.com> Date: Mon, 12 Oct 2026 16:00:12 +0000 Subject: [PATCH 4/4] Run the KLL demo as pinned multi-process pipelines next to exact The demo now uses the streaming benchmark topology: branch A/B, merge and estimate are separate processes, each pinned to one CPU and connected by OTLP/HTTP over TCP. `run-streaming.py --demo` runs the exact and KLL pipelines side by side until Ctrl+C (or SIGTERM) and serves per-process throughput, CPU, egress, RSS and validated answers to Prometheus; a new Grafana dashboard shows them. Estimate can also merge the last N windows for rolling p50/p99 (`--rolling-windows`, default off for capacity runs). Replaces the single-process asap-kll-stream-demo. The Grafana stack uses host networking bound to 127.0.0.1. Docs include sweep results from a 56-core x86 server. --- README.md | 5 +- asap-precompute-rs/Cargo.toml | 7 +- .../src/bin/asap_kll_stream_demo.rs | 478 ------------------ .../src/bin/asap_stream_bench.rs | 19 +- .../src/bin/stream_bench/model.rs | 221 +++++--- benchmarks/STREAMING.md | 12 + benchmarks/run-streaming.py | 123 ++++- demos/kll-grafana/compose.yaml | 13 +- .../grafana/dashboards/kll-stream.json | 260 ++++++++++ demos/kll-grafana/grafana/dashboards/kll.json | 78 +-- .../provisioning/datasources/prometheus.yaml | 2 +- demos/kll-grafana/prometheus.yml | 9 +- demos/kll-grafana/run-demo.sh | 21 + demos/kll-grafana/verify-streaming.py | 113 +++-- docs/demo-guide.md | 5 +- docs/images/kll-streaming-grafana.png | Bin 74680 -> 108243 bytes docs/images/kll-streaming-throughput.png | Bin 0 -> 89525 bytes docs/kll-windows.md | 174 ++++--- 18 files changed, 790 insertions(+), 750 deletions(-) delete mode 100644 asap-precompute-rs/src/bin/asap_kll_stream_demo.rs create mode 100644 demos/kll-grafana/grafana/dashboards/kll-stream.json create mode 100755 demos/kll-grafana/run-demo.sh create mode 100644 docs/images/kll-streaming-throughput.png diff --git a/README.md b/README.md index 14e46e7..0f8431b 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,9 @@ For a presentation-ready walkthrough of the real YAML pipeline integration, see the [live OTAP pipeline demo guide](./docs/demo-guide.md). The guide also includes a [Prometheus + Grafana setup](./docs/demo-guide.md#write-kll-estimates-to-prometheus-and-view-them-in-grafana) that writes the KLL p50/p99 estimates to Prometheus and displays them in a -provisioned Grafana dashboard. For continuous computation from retained -tumbling panes, see the [persistent rolling KLL demo](./docs/kll-windows.md). +provisioned Grafana dashboard. For a continuous KLL vs exact comparison with +every processor in its own pinned process, see the +[multi-process streaming KLL demo](./docs/kll-windows.md). ```sh cd asap-precompute-rs diff --git a/asap-precompute-rs/Cargo.toml b/asap-precompute-rs/Cargo.toml index 3c9fe4b..71e7512 100644 --- a/asap-precompute-rs/Cargo.toml +++ b/asap-precompute-rs/Cargo.toml @@ -51,7 +51,7 @@ async-trait = { version = "0.1", optional = true } humantime-serde = { version = "1", optional = true } serde_json = { version = "1", optional = true } libc = { version = "0.2", optional = true } -tokio = { version = "1", features = ["sync", "rt", "time", "net", "macros", "signal"], optional = true } +tokio = { version = "1", features = ["sync", "rt", "time", "net"], optional = true } [dev-dependencies] proptest = "1" @@ -104,11 +104,6 @@ name = "asap-otap-demo" path = "src/bin/asap_otap_demo.rs" required-features = ["otap-engine"] -[[bin]] -name = "asap-kll-stream-demo" -path = "src/bin/asap_kll_stream_demo.rs" -required-features = ["otap-engine"] - [[bin]] name = "asap-stream-bench" path = "src/bin/asap_stream_bench.rs" diff --git a/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs b/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs deleted file mode 100644 index 3b9f05f..0000000 --- a/asap-precompute-rs/src/bin/asap_kll_stream_demo.rs +++ /dev/null @@ -1,478 +0,0 @@ -//! Persistent real OTAP pipeline: synthetic scalars -> disjoint KLL panes -> -//! tumbling and rolling estimates -> Prometheus OTLP/HTTP. -#[path = "demo/prometheus_export.rs"] -#[allow(dead_code)] // The shared file also supplies the finite demo's file export. -mod prometheus_export; - -use asap_precompute_rs::envelope::{Encoding, SketchEnvelope, SketchType}; -use asap_precompute_rs::observation::KeyValue; -use asap_precompute_rs::otap::codec::{decode_pdata_to_observations, encode_envelopes_to_pdata}; -use async_trait::async_trait; -use linkme::distributed_slice; -use otel_arrow_dfe_config::{ - node::NodeUserConfig, - observed_state::{ObservedStateSettings, SendPolicy}, - pipeline::PipelineConfig, - policy::{ChannelCapacityPolicy, TelemetryPolicy}, - DeployedPipelineKey, PipelineGroupId, PipelineId, -}; -use otel_arrow_dfe_core_nodes as _; -use otel_arrow_dfe_engine::{ - capability::registry::Capabilities, - config::{ExporterConfig, ProcessorConfig, ReceiverConfig}, - context::{ControllerContext, PipelineContext}, - control::{ - pipeline_completion_msg_channel, runtime_ctrl_msg_channel, NodeControlMsg, - RuntimeControlMsg, - }, - error::{Error, ExporterErrorKind}, - exporter::ExporterWrapper, - local::{exporter, processor, receiver}, - message::{ExporterInbox, Message}, - node::NodeId, - processor::ProcessorWrapper, - receiver::ReceiverWrapper, - terminal_state::TerminalState, - ExporterFactory, MessageSourceLocalEffectHandlerExtension, ProcessorFactory, ReceiverFactory, -}; -use otel_arrow_dfe_otap::{ - pdata::OtapPdata, OTAP_EXPORTER_FACTORIES, OTAP_PIPELINE_FACTORY, OTAP_PROCESSOR_FACTORIES, - OTAP_RECEIVER_FACTORIES, -}; -use otel_arrow_dfe_pdata::{OtlpProtoBytes, TryIntoWithOptions}; -use otel_arrow_dfe_state::store::ObservedStateStore; -use otel_arrow_dfe_telemetry::InternalTelemetrySystem; -use std::{ - env, - sync::{Arc, Mutex, OnceLock}, - time::{Duration, Instant, SystemTime, UNIX_EPOCH}, -}; - -const SOURCE: &str = "urn:asap:receiver:kll_demo_traffic"; -const FORK: &str = "urn:asap:processor:kll_demo_fork"; -const SINK: &str = "urn:asap:exporter:kll_demo_prometheus"; -static OPTIONS: OnceLock = OnceLock::new(); -static FAILURE: Mutex> = Mutex::new(None); - -#[derive(Clone)] -struct Options { - endpoint: String, - window_seconds: u64, - slide_seconds: u64, - run_seconds: Option, -} -impl Options { - fn read() -> Result { - let mut options = Self { - endpoint: "http://localhost:9090/api/v1/otlp/v1/metrics".into(), - window_seconds: 60, - slide_seconds: 5, - run_seconds: None, - }; - let args: Vec = env::args().skip(1).collect(); - if args.iter().any(|a| a == "--help") { - println!("asap-kll-stream-demo [--prometheus-otlp-endpoint URL] [--window-seconds 60] [--slide-seconds 5] [--run-seconds N]\nRuns until Ctrl+C by default. Window must be a multiple of slide."); - std::process::exit(0); - } - for pair in args.chunks(2) { - if pair.len() != 2 { - return Err(format!("missing value for {}", pair[0])); - } - if pair[0] == "--prometheus-otlp-endpoint" { - options.endpoint = pair[1].clone(); - continue; - } - let value: u64 = pair[1] - .parse() - .map_err(|_| "duration must be a positive integer number of seconds")?; - if value == 0 { - return Err("duration must be positive".into()); - } - match pair[0].as_str() { - "--window-seconds" => options.window_seconds = value, - "--slide-seconds" => options.slide_seconds = value, - "--run-seconds" => options.run_seconds = Some(value), - other => return Err(format!("unknown option {other}")), - } - } - if options.window_seconds < options.slide_seconds - || !options.window_seconds.is_multiple_of(options.slide_seconds) - { - return Err("window must be a positive multiple of slide".into()); - } - if !(options.endpoint.starts_with("http://") || options.endpoint.starts_with("https://")) { - return Err("endpoint must be an HTTP(S) URL".into()); - } - Ok(options) - } -} -fn now_ms() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("wall clock") - .as_millis() as u64 -} - -fn traffic(sequence: u64, timestamp: u64) -> OtapPdata { - let envelopes: Vec<_> = (0..200) - .map(|offset| { - let index = sequence * 200 + offset; - let phase = ((timestamp / 10_000) % 3) as f64; - let value = if index.is_multiple_of(100) { - 300.0 + 200.0 * phase - } else { - 10.0 + 20.0 * phase + (index % 97) as f64 * 0.1 - }; - SketchEnvelope { - schema_version: 1, - sketch_type: SketchType::Unspecified, - agg_id: 0, - resource_labels: vec![KeyValue::new("service.name", "checkout")], - labels: vec![ - KeyValue::new("http.request.method", "GET"), - KeyValue::new("http.route", "/checkout"), - KeyValue::new("http.response.status_code", "200"), - ], - window_start_ms: timestamp, - window_end_ms: timestamp, - encoding: Encoding::Unspecified, - payload: vec![], - hash_spec: None, - metric_name: "request.duration".into(), - count: 0, - aggregation_temporality: 0, - value, - } - }) - .collect(); - encode_envelopes_to_pdata(&envelopes).expect("encode generated metrics") -} -struct TrafficReceiver; -#[async_trait(?Send)] -impl receiver::Receiver for TrafficReceiver { - async fn start( - self: Box, - mut ctrl: receiver::ControlChannel, - effects: receiver::EffectHandler, - ) -> Result { - let mut interval = tokio::time::interval(Duration::from_millis(100)); - interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - let mut sequence = 0; - loop { - tokio::select! { - message=ctrl.recv() => match message { Ok(NodeControlMsg::Shutdown {..}) | Err(_) => break, _ => {} }, - _=interval.tick() => { - effects.send_message_with_source_node(traffic(sequence,now_ms())).await?; - sequence+=1; - } - } - } - Ok(TerminalState::default()) - } -} -fn create_source( - _ctx: PipelineContext, - node: NodeId, - config: Arc, - runtime: &ReceiverConfig, - _caps: &Capabilities, -) -> Result, otel_arrow_dfe_config::error::Error> { - Ok(ReceiverWrapper::local( - TrafficReceiver, - node, - config, - runtime, - )) -} -#[distributed_slice(OTAP_RECEIVER_FACTORIES)] -static SOURCE_FACTORY: ReceiverFactory = ReceiverFactory { - name: SOURCE, - create: create_source, - wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, - validate_config: otel_arrow_dfe_config::validation::no_config, -}; - -// The pinned engine routes one destination per output port. Explicitly -// duplicate complete panes to two named ports for the comparison demo. -struct PaneFork; -#[async_trait(?Send)] -impl processor::Processor for PaneFork { - async fn process( - &mut self, - message: Message, - effects: &mut processor::EffectHandler, - ) -> Result<(), Error> { - if let Message::PData(pdata) = message { - effects - .send_message_with_source_node_to("tumbling", pdata.clone()) - .await?; - effects - .send_message_with_source_node_to("rolling", pdata) - .await?; - } - Ok(()) - } -} -fn create_fork( - _ctx: PipelineContext, - node: NodeId, - config: Arc, - runtime: &ProcessorConfig, - _caps: &Capabilities, -) -> Result, otel_arrow_dfe_config::error::Error> { - Ok(ProcessorWrapper::local(PaneFork, node, config, runtime)) -} -#[distributed_slice(OTAP_PROCESSOR_FACTORIES)] -static FORK_FACTORY: ProcessorFactory = ProcessorFactory { - name: FORK, - create: create_fork, - wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, - validate_config: otel_arrow_dfe_config::validation::no_config, -}; - -struct PrometheusExporter { - node: NodeId, -} -#[async_trait(?Send)] -impl exporter::Exporter for PrometheusExporter { - async fn start( - self: Box, - mut inbox: ExporterInbox, - _effects: exporter::EffectHandler, - ) -> Result { - let endpoint = OPTIONS.get().expect("options").endpoint.clone(); - loop { - match inbox.recv().await? { - Message::PData(pdata) => { - let error = |message: String| { - *FAILURE.lock().expect("export failure lock") = Some(message.clone()); - Error::ExporterError { - exporter: self.node.clone(), - kind: ExporterErrorKind::Transport, - error: message, - source_detail: String::new(), - } - }; - let observations = decode_pdata_to_observations(pdata.clone()) - .map_err(|e| error(e.to_string()))? - .observations; - let (_, payload) = pdata.into_parts(); - let encoded = - <_ as TryIntoWithOptions>::try_into_with_default(payload) - .map_err(|e| error(e.to_string()))?; - let OtlpProtoBytes::ExportMetricsRequest(bytes) = encoded else { - return Err(error("expected metric gauges".into())); - }; - let url = endpoint.clone(); - // Curl may block on network I/O; keep it off the local - // OTAP executor so ingestion and timers can continue. - let result = tokio::task::spawn_blocking(move || { - prometheus_export::export_bytes(&bytes, &url, None) - }) - .await - .map_err(|e| error(e.to_string()))?; - result.map_err(error)?; - for o in observations { - let quantile = o - .labels - .iter() - .find(|l| l.key == "quantile") - .map_or("?", |l| l.value.as_str()); - println!( - "exported window_end_ms={} metric={} quantile={} value={:.3}", - o.timestamp_ms, o.metric, quantile, o.value.float - ); - } - } - Message::Control(NodeControlMsg::Shutdown { .. }) => break, - Message::Control(_) => {} - } - } - Ok(TerminalState::default()) - } -} -fn create_sink( - _ctx: PipelineContext, - node: NodeId, - config: Arc, - runtime: &ExporterConfig, - _caps: &Capabilities, -) -> Result, otel_arrow_dfe_config::error::Error> { - Ok(ExporterWrapper::local( - PrometheusExporter { node: node.clone() }, - node, - config, - runtime, - )) -} -#[distributed_slice(OTAP_EXPORTER_FACTORIES)] -static SINK_FACTORY: ExporterFactory = ExporterFactory { - name: SINK, - create: create_sink, - wiring_contract: otel_arrow_dfe_engine::wiring_contract::WiringContract::UNRESTRICTED, - validate_config: otel_arrow_dfe_config::validation::no_config, -}; - -fn pipeline_yaml(options: &Options) -> String { - let pane = options.slide_seconds; - let window = options.window_seconds; - format!( - r#"nodes: - source: - type: {SOURCE} - panes: - type: urn:asap:processor:asap_sketches - config: - sketch_type: kll - window_size: {pane}s - window_slide: {pane}s - output_metric_name: request.duration.pane - agg_id: 7 - sketch_params: {{ k: 400 }} - transmit_sketch: true - fork: - type: {FORK} - tumbling: - type: urn:asap:processor:asap_sketches - config: - sketch_type: kll - window_size: {pane}s - window_slide: {pane}s - output_metric_name: request.duration.estimate - agg_id: 7 - sketch_params: {{ k: 400 }} - transmit_sketch: false - quantiles: [0.5, 0.99] - rolling: - type: urn:asap:processor:asap_sketches - config: - sketch_type: kll - window_size: {window}s - window_slide: {pane}s - output_metric_name: request.duration.rolling_estimate - agg_id: 7 - sketch_params: {{ k: 400 }} - transmit_sketch: false - quantiles: [0.5, 0.99] - sink: - type: {SINK} -connections: - - {{ from: source, to: panes }} - - {{ from: panes, to: fork }} - - {{ from: 'fork["tumbling"]', to: tumbling }} - - {{ from: 'fork["rolling"]', to: rolling }} - - {{ from: tumbling, to: sink }} - - {{ from: rolling, to: sink }} -"# - ) -} -fn run(options: Options) -> Result<(), String> { - println!( - "Persistent OTAP KLL demo: {}s tumbling panes, {}s rolling lookback, {}s emission interval", - options.slide_seconds, options.window_seconds, options.slide_seconds - ); - println!( - "Prometheus endpoint: {}; stop with Ctrl+C", - options.endpoint - ); - OPTIONS - .set(options.clone()) - .map_err(|_| "options already set")?; - let config = PipelineConfig::from_yaml( - "asap-kll-stream".into(), - "demo".into(), - &pipeline_yaml(&options), - ) - .map_err(|e| e.to_string())?; - let telemetry = InternalTelemetrySystem::default(); - let ctx = ControllerContext::new(telemetry.registry()).pipeline_context_with( - PipelineGroupId::from("asap-kll-stream"), - PipelineId::from("demo"), - 0, - 1, - 0, - ); - let entity = ctx.register_pipeline_entity(); - let policy = ChannelCapacityPolicy::default(); - let runtime = OTAP_PIPELINE_FACTORY - .build( - ctx.clone(), - config, - policy.clone(), - TelemetryPolicy::default(), - None, - Default::default(), - None, - None, - ) - .map_err(|e| e.to_string())?; - let (runtime_tx, runtime_rx) = runtime_ctrl_msg_channel(policy.control.pipeline); - let (completion_tx, completion_rx) = pipeline_completion_msg_channel(policy.control.completion); - let observed = ObservedStateStore::new(&ObservedStateSettings::default(), telemetry.registry()); - let shutdown_tx = runtime_tx.clone(); - std::thread::spawn(move || { - let signal_runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("signal runtime"); - signal_runtime.block_on(async { - let lifetime = async { - if let Some(seconds) = options.run_seconds { tokio::time::sleep(Duration::from_secs(seconds)).await; } - else { std::future::pending::<()>().await; } - }; - let failed = async { - loop { - if FAILURE.lock().expect("export failure lock").is_some() { break; } - tokio::time::sleep(Duration::from_millis(100)).await; - } - }; - tokio::select! { - _=failed => {}, - signal=tokio::signal::ctrl_c() => { if let Err(e)=signal { eprintln!("Ctrl+C listener: {e}"); } }, - _=lifetime => {}, - } - }); - let _ = shutdown_tx.try_send(RuntimeControlMsg::Shutdown { - deadline: Instant::now() + Duration::from_secs(5), - reason: "streaming demo stopped".into(), - }); - }); - let key = DeployedPipelineKey { - pipeline_group_id: ctx.pipeline_group_id(), - pipeline_id: ctx.pipeline_id(), - core_id: 0, - deployment_generation: 0, - }; - let (_, pressure_rx) = tokio::sync::watch::channel( - otel_arrow_dfe_engine::memory_limiter::MemoryPressureChanged::initial(), - ); - let _guard = otel_arrow_dfe_engine::entity_context::set_pipeline_entity_key( - ctx.metrics_registry(), - entity, - ); - runtime - .run_forever( - key, - ctx, - observed.reporter(SendPolicy::default()), - telemetry.reporter(), - Duration::from_secs(1), - pressure_rx, - runtime_tx, - runtime_rx, - completion_tx, - completion_rx, - ) - .map_err(|e| e.to_string())?; - if let Some(error) = FAILURE.lock().expect("export failure lock").take() { - return Err(error); - } - println!("streaming demo stopped"); - Ok(()) -} -fn main() { - if let Err(error) = Options::read().and_then(run) { - eprintln!("{error}"); - std::process::exit(1); - } -} diff --git a/asap-precompute-rs/src/bin/asap_stream_bench.rs b/asap-precompute-rs/src/bin/asap_stream_bench.rs index ad25e9f..892eda4 100644 --- a/asap-precompute-rs/src/bin/asap_stream_bench.rs +++ b/asap-precompute-rs/src/bin/asap_stream_bench.rs @@ -66,6 +66,7 @@ struct Options { endpoint: String, generator_workers: usize, signals_per_second: usize, + rolling_windows: usize, } impl Options { fn read() -> Result { @@ -86,6 +87,7 @@ impl Options { endpoint: get("ASAP_ENDPOINT", "http://merge:4318"), generator_workers: number("ASAP_GENERATOR_WORKERS", "1")?, signals_per_second: number("ASAP_SIGNALS_PER_SECOND", "100000")?, + rolling_windows: number("ASAP_ROLLING_WINDOWS", "1")?, }; if !["raw", "exact", "kll"].contains(&o.scenario.as_str()) || !["generator", "branch", "merge", "estimate", "backend"].contains(&o.role.as_str()) @@ -95,6 +97,7 @@ impl Options { || o.source > 1 || o.generator_workers == 0 || o.signals_per_second == 0 + || o.rolling_windows == 0 { return Err("invalid role/scenario/window/batch/source configuration".into()); } @@ -113,6 +116,7 @@ struct Stats { output_send_wall_ns: u64, output_messages: u64, window_latency_ms: BTreeMap, + latest_results: Vec, } struct Shared { stats: Mutex, @@ -280,7 +284,13 @@ fn create_processor( let o = OPTIONS.get().unwrap(); Ok(ProcessorWrapper::local( StreamProcessor { - processor: model::Processor::new(&o.scenario, &o.role, o.points, o.batch), + processor: model::Processor::new( + &o.scenario, + &o.role, + o.points, + o.batch, + o.rolling_windows, + ), normalizer: (o.role == "branch") .then(|| model::InputNormalizer::new(o.source, o.points, o.batch)), }, @@ -317,6 +327,7 @@ impl exporter::Exporter for ValidatingBackend { stats.received_signals += count; if let Some((window, start)) = completed { assert_eq!(window, stats.completed_windows, "backend window gap"); + stats.latest_results.clone_from(&self.0.latest); stats.completed_windows += 1; let elapsed_ms = now_ns().saturating_sub(start) / 1_000_000; *stats.window_latency_ms.entry(elapsed_ms).or_default() += 1; @@ -340,7 +351,11 @@ fn create_backend( ) -> Result, otel_arrow_dfe_config::error::Error> { let o = OPTIONS.get().unwrap(); Ok(ExporterWrapper::local( - ValidatingBackend(model::Backend::new(&o.scenario, o.points)), + ValidatingBackend(model::Backend::new( + &o.scenario, + o.points, + o.rolling_windows, + )), node, config, runtime, diff --git a/asap-precompute-rs/src/bin/stream_bench/model.rs b/asap-precompute-rs/src/bin/stream_bench/model.rs index 4219619..0e03090 100644 --- a/asap-precompute-rs/src/bin/stream_bench/model.rs +++ b/asap-precompute-rs/src/bin/stream_bench/model.rs @@ -8,7 +8,8 @@ use asap_precompute_rs::{ sketches::KLLWrapper, }; use otel_arrow_dfe_otap::pdata::OtapPdata; -use std::collections::BTreeMap; +use serde::Serialize; +use std::collections::{BTreeMap, VecDeque}; // Independent official generators can drift under high load. Keep the skew // explicitly bounded while allowing short scheduler/exporter bursts. @@ -111,16 +112,25 @@ fn decode_sketch(o: &Observation, count: usize) -> Result { .map_err(|e| e.to_string())?; Ok(sketch) } -fn quantiles_pdata(values: [f64; 2], meta: Meta) -> Result { +const QUANTILES: [&str; 2] = ["0.5", "0.99"]; +/// Tumbling quantiles, plus rolling quantiles when the estimate retains windows. +fn quantiles_pdata( + tumbling: [f64; 2], + rolling: Option<[f64; 2]>, + meta: Meta, +) -> Result { let _cpu = profile::scope(Category::PdataCodec); - let envelopes = ["0.5", "0.99"] + let envelopes = [("tumbling", Some(tumbling)), ("rolling", rolling)] .into_iter() - .zip(values) - .map(|(q, value)| { - let mut env = meta.envelope(value); - env.metric_name = "http.server.request.duration.estimate".into(); - env.labels.push(KeyValue::new("quantile", q)); - env + .filter_map(|(kind, values)| Some((kind, values?))) + .flat_map(|(kind, values)| { + QUANTILES.into_iter().zip(values).map(move |(q, value)| { + let mut env = meta.envelope(value); + env.metric_name = "http.server.request.duration.estimate".into(); + env.labels.push(KeyValue::new("quantile", q)); + env.labels.push(KeyValue::new("window_kind", kind)); + env + }) }) .collect::>(); encode_envelopes_to_pdata(&envelopes).map_err(|e| e.to_string()) @@ -128,10 +138,9 @@ fn quantiles_pdata(values: [f64; 2], meta: Meta) -> Result { pub fn exact(values: &[f64]) -> [f64; 2] { [0.5, 0.99].map(|q| values[((values.len() - 1) as f64 * q).round() as usize]) } -pub fn reference(points: usize) -> [f64; 2] { - let mut values = (1..=points as u64 * 2).map(value).collect::>(); - values.sort_by(f64::total_cmp); - exact(&values) +/// Exact quantiles of `copies` concatenated copies of one sorted window. +fn exact_repeated(sorted: &[f64], copies: usize) -> [f64; 2] { + [0.5, 0.99].map(|q| sorted[((sorted.len() * copies - 1) as f64 * q).round() as usize / copies]) } pub struct InputNormalizer { @@ -209,9 +218,13 @@ pub struct Processor { pub batch: usize, windows: BTreeMap, next: [u64; 3], + /// Completed windows merged into each rolling estimate; 1 disables rolling. + rolling: usize, + kll_history: VecDeque, + exact_history: VecDeque>, } impl Processor { - pub fn new(scenario: &str, role: &str, points: usize, batch: usize) -> Self { + pub fn new(scenario: &str, role: &str, points: usize, batch: usize, rolling: usize) -> Self { Self { scenario: scenario.into(), role: role.into(), @@ -219,7 +232,43 @@ impl Processor { batch, windows: BTreeMap::new(), next: [0; 3], + rolling, + kll_history: VecDeque::new(), + exact_history: VecDeque::new(), + } + } + /// Merge the last `rolling` window sketches; quantiles of their union. + fn rolling_kll(&mut self, sketch: KLLWrapper) -> Result, String> { + if self.rolling <= 1 { + return Ok(None); + } + self.kll_history.push_back(sketch); + if self.kll_history.len() > self.rolling { + self.kll_history.pop_front(); + } + let mut merged = new_sketch(5); + for sketch in &self.kll_history { + merged.merge(sketch).map_err(|e| e.to_string())?; + } + Ok(Some([merged.quantile(0.5), merged.quantile(0.99)])) + } + /// Exact rolling quantiles must retain and re-sort every value in the range. + fn rolling_exact(&mut self, values: Vec) -> Option<[f64; 2]> { + if self.rolling <= 1 { + return None; + } + self.exact_history.push_back(values); + if self.exact_history.len() > self.rolling { + self.exact_history.pop_front(); } + let mut all = self + .exact_history + .iter() + .flatten() + .copied() + .collect::>(); + all.sort_unstable_by(f64::total_cmp); + Some(exact(&all)) } pub fn process(&mut self, pdata: OtapPdata) -> Result, String> { let _cpu = profile::scope(Category::ProcessorBookkeeping); @@ -308,13 +357,12 @@ impl Processor { }; if self.scenario == "kll" { return Ok(vec![if estimate { - quantiles_pdata( - { - let _cpu = profile::scope(Category::Computation); - [w.sketch.quantile(0.5), w.sketch.quantile(0.99)] - }, - out_meta, - )? + let (tumbling, rolling) = { + let _cpu = profile::scope(Category::Computation); + let tumbling = [w.sketch.quantile(0.5), w.sketch.quantile(0.99)]; + (tumbling, self.rolling_kll(w.sketch)?) + }; + quantiles_pdata(tumbling, rolling, out_meta)? } else { sketch_pdata( &w.sketch, @@ -350,11 +398,12 @@ impl Processor { } }; if estimate { - let quantiles = { + let (tumbling, rolling) = { let _cpu = profile::scope(Category::Computation); - exact(&values) + let tumbling = exact(&values); + (tumbling, self.rolling_exact(values)) }; - return Ok(vec![quantiles_pdata(quantiles, out_meta)?]); + return Ok(vec![quantiles_pdata(tumbling, rolling, out_meta)?]); } values .chunks(self.batch) @@ -445,23 +494,39 @@ impl Processor { } } +/// One validated result and its exact reference, reported for dashboards. +#[derive(Serialize, Clone, Debug, Default)] +pub struct ResultPoint { + pub window_kind: String, + pub quantile: String, + pub value: f64, + pub reference: f64, +} pub struct Backend { scenario: String, points: usize, - expected: [f64; 2], + rolling: usize, + /// The sorted two-source corpus; every window replays it. + sorted: Vec, windows: BTreeMap, next: [u64; 2], next_quantile: u64, + /// Results of the most recently completed window. + pub latest: Vec, } impl Backend { - pub fn new(scenario: &str, points: usize) -> Self { + pub fn new(scenario: &str, points: usize, rolling: usize) -> Self { + let mut sorted = (1..=points as u64 * 2).map(value).collect::>(); + sorted.sort_by(f64::total_cmp); Self { scenario: scenario.into(), points, - expected: reference(points), + rolling, + sorted, windows: BTreeMap::new(), next: [0; 2], next_quantile: 0, + latest: Vec::new(), } } /// Return completed input signals and optional (window id, start timestamp). @@ -509,36 +574,56 @@ impl Backend { } return Ok((obs.len() as u64, completed)); } - if meta.window != self.next_quantile || meta.source != 2 || obs.len() != 2 { + let mut kinds = vec![("tumbling", exact(&self.sorted))]; + if self.rolling > 1 { + let copies = (meta.window as usize + 1).min(self.rolling); + kinds.push(("rolling", exact_repeated(&self.sorted, copies))); + } + if meta.window != self.next_quantile || meta.source != 2 || obs.len() != kinds.len() * 2 { return Err("quantile window missing/duplicated".into()); } - for (q, expected) in ["0.5", "0.99"].into_iter().zip(self.expected) { - let matching = obs + let label = |o: &Observation, key: &str| { + o.labels .iter() - .filter(|o| { - o.labels - .iter() - .any(|kv| kv.key == "quantile" && kv.value == q) - }) - .collect::>(); - if matching.len() != 1 { - return Err("missing/duplicate quantile".into()); - } - let o = matching[0]; - let other = Meta::read(o)?; - let tolerance = if self.scenario == "exact" { - 0.0 - } else { - (expected.abs() * 0.05).max(0.001) - }; - if other.window != meta.window - || other.source != 2 - || !o.value.float.is_finite() - || (o.value.float - expected).abs() > tolerance - { - return Err(format!("{q}: {} != {expected}", o.value.float)); + .find(|kv| kv.key == key) + .map(|kv| kv.value.clone()) + }; + let mut latest = Vec::with_capacity(obs.len()); + for (kind, expected) in kinds { + for (q, expected) in QUANTILES.into_iter().zip(expected) { + let matching = obs + .iter() + .filter(|o| { + label(o, "quantile").as_deref() == Some(q) + && label(o, "window_kind").as_deref() == Some(kind) + }) + .collect::>(); + if matching.len() != 1 { + return Err("missing/duplicate quantile".into()); + } + let o = matching[0]; + let other = Meta::read(o)?; + let tolerance = if self.scenario == "exact" { + 0.0 + } else { + (expected.abs() * 0.05).max(0.001) + }; + if other.window != meta.window + || other.source != 2 + || !o.value.float.is_finite() + || (o.value.float - expected).abs() > tolerance + { + return Err(format!("{kind} {q}: {} != {expected}", o.value.float)); + } + latest.push(ResultPoint { + window_kind: kind.into(), + quantile: q.into(), + value: o.value.float, + reference: expected, + }); } } + self.latest = latest; self.next_quantile += 1; Ok(( (self.points * 2) as u64, @@ -550,15 +635,15 @@ impl Backend { #[cfg(test)] mod tests { use super::*; - fn exercise(scenario: &str) { + fn exercise(scenario: &str, rolling: usize) { let (n, batch) = (1024, 127); let mut branches = [ - Processor::new(scenario, "branch", n, batch), - Processor::new(scenario, "branch", n, batch), + Processor::new(scenario, "branch", n, batch, rolling), + Processor::new(scenario, "branch", n, batch, rolling), ]; - let mut merge = Processor::new(scenario, "merge", n, batch); - let mut estimate = Processor::new(scenario, "estimate", n, batch); - let mut backend = Backend::new(scenario, n); + let mut merge = Processor::new(scenario, "merge", n, batch, rolling); + let mut estimate = Processor::new(scenario, "estimate", n, batch, rolling); + let mut backend = Backend::new(scenario, n, rolling); let (mut received, mut completed) = (0, 0); for window in 0..3 { for offset in (0..n).step_by(batch) { @@ -588,11 +673,25 @@ mod tests { } assert_eq!(received, 6 * n as u64); assert_eq!(completed, 3); + if scenario != "raw" { + let rolling_points = backend + .latest + .iter() + .filter(|p| p.window_kind == "rolling") + .count(); + assert_eq!(rolling_points, if rolling > 1 { 2 } else { 0 }); + } } #[test] fn streaming_windows_survive_batch_boundaries() { for scenario in ["raw", "exact", "kll"] { - exercise(scenario); + exercise(scenario, 1); + } + } + #[test] + fn rolling_estimates_merge_retained_windows() { + for scenario in ["exact", "kll"] { + exercise(scenario, 2); } } #[test] @@ -604,10 +703,10 @@ mod tests { started_ns: 1, }; let input = || values_pdata(&[value(1)], meta).unwrap(); - let mut backend = Backend::new("raw", 10); + let mut backend = Backend::new("raw", 10, 1); backend.receive(input()).unwrap(); assert!(backend.receive(input()).is_err()); - let mut processor = Processor::new("kll", "branch", 10, 2); + let mut processor = Processor::new("kll", "branch", 10, 2, 1); assert!(processor .process(values_pdata(&[value(1)], Meta { offset: 1, ..meta }).unwrap()) .is_err()); diff --git a/benchmarks/STREAMING.md b/benchmarks/STREAMING.md index 0638520..059e266 100644 --- a/benchmarks/STREAMING.md +++ b/benchmarks/STREAMING.md @@ -156,6 +156,18 @@ networks it creates, including on failure; it saves logs before removal. - `snapshots.json`: raw before/interval/drained counters and latency histograms. - `result.json` and seven component logs per run. +## Live demo mode + +`--demo` runs the selected scenarios side by side, each on its own CPU slice +(generators, one CPU per processor, `--demo-backend-cores` for the backend), +at `--demo-rate` signals/s per source until Ctrl+C or `--run-seconds`. It +serves per-process throughput, CPU, egress, RSS and the backend's latest +validated answers as Prometheus metrics on `--metrics-address`:`--metrics-port` +(default `127.0.0.1:9465`). `--rolling-windows N` (`ASAP_ROLLING_WINDOWS`) +makes estimate also answer over the last N completed windows; the default of +1 disables rolling answers, so capacity runs are unaffected. See +[the multi-process KLL demo](../docs/kll-windows.md). + CI runs the full 189-run matrix, checks actual network traffic, completed windows, zero loss after drain, and resource artifacts. It uploads results even on failure. The old PR's 2.43× was measured with the file-backed batch harness and is not a diff --git a/benchmarks/run-streaming.py b/benchmarks/run-streaming.py index 8cd667b..e563a31 100755 --- a/benchmarks/run-streaming.py +++ b/benchmarks/run-streaming.py @@ -3,16 +3,20 @@ import argparse import concurrent.futures import csv +import collections import http.client +import http.server import json import math import os import platform from pathlib import Path import shlex +import signal import socket import statistics import subprocess +import threading import time import urllib.request import uuid @@ -50,8 +54,10 @@ def delta_histogram(before, after): class Run: - def __init__(self, args, scenario, rate, repeat, traffic_rate, window_points): + def __init__(self, args, scenario, rate, repeat, traffic_rate, window_points, cores=None, rolling_windows=1): self.args, self.scenario, self.rate = args, scenario, rate + # Demo mode runs several pipelines at once, each on its own CPU slice. + self.cores, self.rolling_windows = cores, rolling_windows self.generator_core_count, self.traffic_rate, self.window_points = args.generator_cores, traffic_rate, window_points self.observation_seconds = max( args.duration, @@ -92,7 +98,7 @@ def wait_for(self, predicate, timeout=120): raise TimeoutError("streaming benchmark readiness/drain timeout") def setup(self): - cores = sorted(os.sched_getaffinity(0)) + cores = self.cores or sorted(os.sched_getaffinity(0)) # The backend is benchmark infrastructure, so it receives every host CPU # left after the isolated generator and processor assignments. Keep at # least one CPU available for it. Memory is intentionally uncapped for @@ -141,6 +147,7 @@ def setup(self): "ASAP_GENERATOR_WORKERS": str(self.generator_core_count), "ASAP_SIGNALS_PER_SECOND": str(self.traffic_rate), "ASAP_PROFILE_CPU": "1" if self.args.profile_cpu else "0", + "ASAP_ROLLING_WINDOWS": str(self.rolling_windows), } cmd = ["create", "--name", name, "--network", self.networks[0], "--network-alias", role, "--cpuset-cpus", ",".join(map(str, cpu_set))] @@ -458,6 +465,103 @@ def draw_resources(rows, path): path.write_text("\n".join(svg) + "\n") +def demo_metrics(runs, history): + """Prometheus text exposition over the last ~30 s of control snapshots.""" + lines = [] + def gauge(name, labels, value): + rendered = ",".join(f'{key}="{val}"' for key, val in labels.items()) + lines.append(f"{name}{{{rendered}}} {value}") + for scenario, run in runs.items(): + if len(history[scenario]) < 2: + continue + before, after = history[scenario][0], history[scenario][-1] + seconds = (after["backend"]["timestamp_ns"] - before["backend"]["timestamp_ns"]) / 1e9 + validated = after["backend"]["stats"]["received_signals"] - before["backend"]["stats"]["received_signals"] + gauge("asap_demo_validated_signals_per_second", {"scenario": scenario}, validated / seconds) + gauge("asap_demo_completed_windows", {"scenario": scenario}, after["backend"]["stats"]["completed_windows"]) + processor_cpu = 0 + for role in ROLES: + start, end = before[role], after[role] + elapsed = (end["timestamp_ns"] - start["timestamp_ns"]) / 1e9 + cpu = (end["cpu_nanoseconds"] - start["cpu_nanoseconds"]) / 1e9 + if role in PROCESSOR_ROLES: + processor_cpu += cpu + iface = run.data_ifaces[role] + tx = end["interfaces"][iface]["tx_bytes"] - start["interfaces"][iface]["tx_bytes"] + received = end["stats"]["received_signals"] - start["stats"]["received_signals"] + labels = {"scenario": scenario, "component": role} + gauge("asap_demo_cpu_cores", labels, cpu / elapsed) + gauge("asap_demo_data_tx_mbit_per_second", labels, tx * 8 / elapsed / 1e6) + gauge("asap_demo_rss_mib", labels, end["rss_kib"] / 1024) + if role.startswith("branch"): + gauge("asap_demo_ingested_signals_per_second", labels, received / elapsed) + if validated: + gauge("asap_demo_processor_cpu_seconds_per_million_signals", {"scenario": scenario}, + processor_cpu / validated * 1e6) + for point in after["backend"]["stats"].get("latest_results", []): + labels = {"scenario": scenario, "window_kind": point["window_kind"], "quantile": point["quantile"]} + gauge("asap_demo_estimate", labels, point["value"]) + gauge("asap_demo_reference", labels, point["reference"]) + gauge("asap_demo_relative_error", labels, + abs(point["value"] - point["reference"]) / abs(point["reference"]) if point["reference"] else 0) + return "\n".join(lines) + "\n" + + +def demo(args): + """Run every scenario's pipeline concurrently at one offered rate until Ctrl+C.""" + cores = sorted(os.sched_getaffinity(0)) + per_pipeline = args.generator_cores + len(PROCESSOR_ROLES) + args.demo_backend_cores + if len(cores) < per_pipeline * len(args.scenarios): + raise SystemExit(f"demo needs {per_pipeline} CPUs per scenario ({args.generator_cores} generator, " + f"{len(PROCESSOR_ROLES)} processors, {args.demo_backend_cores} backend); " + f"only {len(cores)} are available") + def stop(*_): + raise KeyboardInterrupt + # Background jobs ignore SIGINT; SIGTERM stops the demo with the same cleanup. + signal.signal(signal.SIGTERM, stop) + runs, history, body = {}, {}, {"text": ""} + class Metrics(http.server.BaseHTTPRequestHandler): + def do_GET(self): + payload = body["text"].encode() + self.send_response(200 if self.path == "/metrics" else 404) + self.send_header("Content-Type", "text/plain; version=0.0.4") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + def log_message(self, *_): + pass + server = http.server.ThreadingHTTPServer((args.metrics_address, args.metrics_port), Metrics) + threading.Thread(target=server.serve_forever, daemon=True).start() + try: + for index, scenario in enumerate(args.scenarios): + run = Run(args, scenario, 0, "demo", args.demo_rate, args.window_points[0], + cores=cores[index * per_pipeline:(index + 1) * per_pipeline], + rolling_windows=args.rolling_windows) + runs[scenario] = run + run.setup() + # Windows complete in bursts; rates over ~30 s keep the gauges readable. + history[scenario] = collections.deque(maxlen=max(2, round(30 / args.sample_interval) + 1)) + for run in runs.values(): + for role in ("generator_a", "generator_b"): + request(run.urls[role], "/run", "POST") + print(f"demo: {', '.join(args.scenarios)} at {args.demo_rate:,} signals/s/source, " + f"window {args.window_points[0]:,}, rolling {args.rolling_windows}; " + f"metrics on http://{args.metrics_address}:{args.metrics_port}/metrics; Ctrl+C stops", flush=True) + deadline = time.monotonic() + args.run_seconds if args.run_seconds else None + while deadline is None or time.monotonic() < deadline: + time.sleep(args.sample_interval) + for scenario, run in runs.items(): + run.healthy() + history[scenario].append(run.statuses()) + body["text"] = demo_metrics(runs, history) + except KeyboardInterrupt: + print("demo: stopping", flush=True) + finally: + for run in runs.values(): + run.close() + server.shutdown() + + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--image", default="asap-stream-benchmark:local") @@ -487,7 +591,22 @@ def main(): parser.add_argument("--sustainable-max-backlog-growth-windows", type=float, default=1.0) parser.add_argument("--sustainable-max-p99-ms", type=float, default=5000) parser.add_argument("--resume", action="store_true", help="reuse completed runs from output/runs.json") + parser.add_argument("--demo", action="store_true", + help="run the selected scenarios side by side at --demo-rate until Ctrl+C and serve Prometheus metrics") + parser.add_argument("--demo-rate", type=int, default=100000, help="demo offered signals/s per source") + parser.add_argument("--demo-backend-cores", type=int, default=1, help="demo backend CPUs per scenario") + parser.add_argument("--rolling-windows", type=int, default=1, + help="completed windows merged into each rolling estimate; 1 disables rolling results") + parser.add_argument("--run-seconds", type=float, default=0, help="demo duration; 0 runs until Ctrl+C") + parser.add_argument("--metrics-address", default="127.0.0.1") + parser.add_argument("--metrics-port", type=int, default=9465) args = parser.parse_args() + if args.demo: + if args.demo_rate < 1 or args.rolling_windows < 1 or args.demo_backend_cores < 1 or args.run_seconds < 0: + parser.error("invalid demo rate, rolling windows, backend cores, or duration") + args.output.mkdir(parents=True, exist_ok=True) + demo(args) + return if any(points < 1 for points in args.window_points) or args.batch_size < 1 or any(args.batch_size > points for points in args.window_points) or args.generator_cores < 1 or any(rate < 1 for rate in args.traffic_rates) or not all(math.isfinite(t) for t in (args.warmup, args.duration, args.sample_interval)) or args.warmup < 0 or args.duration <= 0 or args.minimum_observed_windows < 2 or args.sample_interval <= 0 or args.repetitions < 1 or any(not math.isfinite(r) or r < 0 for r in args.rates_mbit) or not 0 < args.sustainable_min_delivery <= 1 or args.sustainable_max_backlog_growth_windows < 0 or args.sustainable_max_p99_ms <= 0: parser.error("invalid benchmark sizes, times, repetitions, or rates") args.output.mkdir(parents=True, exist_ok=True) diff --git a/demos/kll-grafana/compose.yaml b/demos/kll-grafana/compose.yaml index 87353e5..52246e0 100644 --- a/demos/kll-grafana/compose.yaml +++ b/demos/kll-grafana/compose.yaml @@ -1,21 +1,26 @@ +# Host networking keeps Prometheus, Grafana and the demo metrics endpoint on +# localhost only (Linux). Prometheus scrapes run-streaming.py --demo on :9465 +# and still accepts OTLP pushes from the finite asap-otap-demo export. services: prometheus: image: prom/prometheus:v3.5.0 + network_mode: host command: - --config.file=/etc/prometheus/prometheus.yml - --web.enable-otlp-receiver - ports: - - "127.0.0.1:${PROMETHEUS_PORT:-9090}:9090" + - --web.listen-address=127.0.0.1:${PROMETHEUS_PORT:-9090} volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus-data:/prometheus grafana: image: grafana/grafana:12.1.0 - ports: - - "127.0.0.1:${GRAFANA_PORT:-3000}:3000" + network_mode: host environment: + GF_SERVER_HTTP_ADDR: 127.0.0.1 + GF_SERVER_HTTP_PORT: ${GRAFANA_PORT:-3000} GF_AUTH_ANONYMOUS_ENABLED: "true" GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer + PROMETHEUS_PORT: ${PROMETHEUS_PORT:-9090} volumes: - ./grafana/provisioning:/etc/grafana/provisioning:ro - ./grafana/dashboards:/var/lib/grafana/dashboards:ro diff --git a/demos/kll-grafana/grafana/dashboards/kll-stream.json b/demos/kll-grafana/grafana/dashboards/kll-stream.json new file mode 100644 index 0000000..7dacd60 --- /dev/null +++ b/demos/kll-grafana/grafana/dashboards/kll-stream.json @@ -0,0 +1,260 @@ +{ + "uid": "asap-kll-stream", + "title": "ASAP KLL vs exact: multi-process streaming", + "schemaVersion": 39, + "version": 1, + "refresh": "5s", + "time": { + "from": "now-15m", + "to": "now" + }, + "panels": [ + { + "id": 1, + "type": "timeseries", + "title": "Backend-validated throughput", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_validated_signals_per_second", + "legendFormat": "{{scenario}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "min": 0 + }, + "overrides": [] + } + }, + { + "id": 2, + "type": "bargauge", + "title": "Processor CPU-seconds per million signals (branches + merge + estimate)", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_processor_cpu_seconds_per_million_signals", + "legendFormat": "{{scenario}}", + "instant": true + } + ], + "fieldConfig": { + "defaults": { + "decimals": 2 + }, + "overrides": [] + }, + "options": { + "orientation": "horizontal", + "displayMode": "basic", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + } + } + }, + { + "id": 3, + "type": "timeseries", + "title": "CPU cores per pinned processor", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_cpu_cores{component=~\"branch_a|branch_b|merge|estimate\"}", + "legendFormat": "{{scenario}} {{component}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + }, + { + "id": 4, + "type": "timeseries", + "title": "Data-network egress per process", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_data_tx_mbit_per_second{component=~\"branch_a|branch_b|merge|estimate\"}", + "legendFormat": "{{scenario}} {{component}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "Mbits" + }, + "overrides": [] + } + }, + { + "id": 5, + "type": "timeseries", + "title": "Tumbling p50/p99 vs exact reference", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_estimate{window_kind=\"tumbling\"}", + "legendFormat": "{{scenario}} p{{quantile}}" + }, + { + "refId": "B", + "expr": "asap_demo_reference{window_kind=\"tumbling\",scenario=\"kll\"}", + "legendFormat": "reference p{{quantile}}" + } + ], + "fieldConfig": { + "defaults": { + "decimals": 4 + }, + "overrides": [] + } + }, + { + "id": 6, + "type": "timeseries", + "title": "Rolling p50/p99 vs exact reference", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_estimate{window_kind=\"rolling\"}", + "legendFormat": "{{scenario}} p{{quantile}}" + }, + { + "refId": "B", + "expr": "asap_demo_reference{window_kind=\"rolling\",scenario=\"kll\"}", + "legendFormat": "reference p{{quantile}}" + } + ], + "fieldConfig": { + "defaults": { + "decimals": 4 + }, + "overrides": [] + } + }, + { + "id": 7, + "type": "timeseries", + "title": "Relative error vs exact", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_relative_error", + "legendFormat": "{{scenario}} {{window_kind}} p{{quantile}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percentunit" + }, + "overrides": [] + } + }, + { + "id": 8, + "type": "timeseries", + "title": "Resident memory per process", + "datasource": { + "type": "prometheus", + "uid": "asap-prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "targets": [ + { + "refId": "A", + "expr": "asap_demo_rss_mib{component=~\"branch_a|branch_b|merge|estimate\"}", + "legendFormat": "{{scenario}} {{component}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "decmbytes" + }, + "overrides": [] + } + } + ] +} diff --git a/demos/kll-grafana/grafana/dashboards/kll.json b/demos/kll-grafana/grafana/dashboards/kll.json index 1a0ca71..a78a6da 100644 --- a/demos/kll-grafana/grafana/dashboards/kll.json +++ b/demos/kll-grafana/grafana/dashboards/kll.json @@ -1,8 +1,8 @@ { "uid": "asap-kll", - "title": "ASAP KLL tumbling and rolling estimates", + "title": "ASAP KLL estimates", "schemaVersion": 39, - "version": 2, + "version": 1, "refresh": "5s", "time": { "from": "now-15m", @@ -12,14 +12,14 @@ { "id": 1, "type": "stat", - "title": "Latest tumbling KLL estimates", + "title": "Latest KLL estimates", "datasource": { "type": "prometheus", "uid": "asap-prometheus" }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 0 }, @@ -50,7 +50,7 @@ { "id": 2, "type": "timeseries", - "title": "Tumbling KLL estimates over time", + "title": "KLL estimates over time", "datasource": { "type": "prometheus", "uid": "asap-prometheus" @@ -76,74 +76,6 @@ "overrides": [] }, "options": {} - }, - { - "id": 3, - "type": "stat", - "title": "Latest rolling KLL estimates", - "datasource": { - "type": "prometheus", - "uid": "asap-prometheus" - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 0 - }, - "targets": [ - { - "refId": "A", - "expr": "request_duration_rolling_estimate{quantile=~\"0.5|0.99\"}", - "legendFormat": "quantile {{quantile}}", - "instant": true - } - ], - "fieldConfig": { - "defaults": { - "decimals": 3 - }, - "overrides": [] - }, - "options": { - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - } - } - }, - { - "id": 4, - "type": "timeseries", - "title": "Rolling KLL estimates over time", - "datasource": { - "type": "prometheus", - "uid": "asap-prometheus" - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 16 - }, - "targets": [ - { - "refId": "A", - "expr": "request_duration_rolling_estimate{quantile=~\"0.5|0.99\"}", - "legendFormat": "quantile {{quantile}}", - "instant": false - } - ], - "fieldConfig": { - "defaults": { - "decimals": 3 - }, - "overrides": [] - }, - "options": {} } ] } diff --git a/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml b/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml index e23f52d..1dfc28d 100644 --- a/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml +++ b/demos/kll-grafana/grafana/provisioning/datasources/prometheus.yaml @@ -4,6 +4,6 @@ datasources: uid: asap-prometheus type: prometheus access: proxy - url: http://prometheus:9090 + url: http://127.0.0.1:${PROMETHEUS_PORT} isDefault: true editable: false diff --git a/demos/kll-grafana/prometheus.yml b/demos/kll-grafana/prometheus.yml index d8b4a57..760af13 100644 --- a/demos/kll-grafana/prometheus.yml +++ b/demos/kll-grafana/prometheus.yml @@ -1,4 +1,9 @@ global: scrape_interval: 15s -# Estimated gauges arrive through the OTLP HTTP receiver; no scrape target needed. -scrape_configs: [] +scrape_configs: + # benchmarks/run-streaming.py --demo (default --metrics-port 9465). + - job_name: asap-demo + scrape_interval: 2s + static_configs: + - targets: ["127.0.0.1:9465"] +# The finite demo's estimates arrive through the OTLP HTTP receiver instead. diff --git a/demos/kll-grafana/run-demo.sh b/demos/kll-grafana/run-demo.sh new file mode 100755 index 0000000..fa2271b --- /dev/null +++ b/demos/kll-grafana/run-demo.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Multi-process streaming demo: every processor of every scenario's pipeline is +# its own container pinned to one CPU, connected by OTLP/HTTP over TCP. Builds +# the benchmark image, starts Prometheus/Grafana, then runs until Ctrl+C. +# Extra arguments go to benchmarks/run-streaming.py (e.g. --demo-rate 200000). +set -euo pipefail +repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +cd "$repo_root" +cargo_target_dir=${CARGO_TARGET_DIR:-"$repo_root/asap-precompute-rs/target"} +read -r -a docker_command <<< "${DOCKER_COMMAND:-docker}" +cargo build --manifest-path asap-precompute-rs/Cargo.toml \ + --release --features stream-benchmark --bin asap-stream-bench +context=$(mktemp -d) +trap 'rm -rf "$context"' EXIT +cp "$cargo_target_dir/release/asap-stream-bench" "$context/" +strip --strip-debug "$context/asap-stream-bench" +"${docker_command[@]}" build -q -f benchmarks/stream.Dockerfile -t asap-stream-benchmark:local "$context" +"${docker_command[@]}" compose -f demos/kll-grafana/compose.yaml up -d +python3 benchmarks/run-streaming.py --demo --docker-command "${DOCKER_COMMAND:-docker}" \ + --output benchmark-results/demo --scenarios exact kll --window-points 65536 \ + --rolling-windows 6 --generator-cores 2 "$@" diff --git a/demos/kll-grafana/verify-streaming.py b/demos/kll-grafana/verify-streaming.py index 8f4d358..2940c2f 100644 --- a/demos/kll-grafana/verify-streaming.py +++ b/demos/kll-grafana/verify-streaming.py @@ -1,13 +1,20 @@ #!/usr/bin/env python3 -"""Verify new tumbling/rolling samples continuously reach Prometheus and Grafana.""" +"""Run the multi-process demo briefly and verify its metrics in Prometheus and Grafana. + +Requires the asap-stream-benchmark:local image (built by run-demo.sh) and the +compose stack. Extra arguments are passed to benchmarks/run-streaming.py. +""" import argparse import json -import os import subprocess -import tempfile +import sys import time import urllib.parse import urllib.request +from pathlib import Path + +REPO = Path(__file__).resolve().parents[2] +PROCESSORS = ('branch_a', 'branch_b', 'merge', 'estimate') def query(base, expression, grafana=False): @@ -20,64 +27,60 @@ def query(base, expression, grafana=False): return payload['data']['result'] -def counts(base, metric): - return {row['metric']['quantile']: int(float(row['value'][1])) for row in query( - base, 'count_over_time(' + metric + '{quantile=~"0.5|0.99"}[5m])')} +def values(base, expression, keys, grafana=False): + return {tuple(row['metric'].get(k, '') for k in keys): float(row['value'][1]) + for row in query(base, expression, grafana)} def main(): parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('binary', help='path to asap-kll-stream-demo') parser.add_argument('--prometheus', default='http://localhost:9090') parser.add_argument('--grafana', default='http://localhost:3000') - args = parser.parse_args() - metrics = ['request_duration_estimate', 'request_duration_rolling_estimate'] - initial = {metric: counts(args.prometheus, metric) for metric in metrics} - observed = [] - with tempfile.TemporaryFile(mode='w+') as trace: - process = subprocess.Popen([ - os.path.abspath(args.binary), '--window-seconds', '6', '--slide-seconds', '1', - '--run-seconds', '16', '--prometheus-otlp-endpoint', - args.prometheus.rstrip('/') + '/api/v1/otlp/v1/metrics', - ], stdout=trace, stderr=subprocess.STDOUT) - try: - deadline = time.monotonic() + 40 - while process.poll() is None: - assert time.monotonic() < deadline, 'streaming demo failed to stop' - for metric in metrics: - rows = query(args.prometheus, metric + '{quantile=~"0.5|0.99"}') - if not rows: - continue - assert len(rows) == 2, ('expected stable series, not new window labels', rows) - assert {row['metric']['quantile'] for row in rows} == {'0.5', '0.99'} - assert all('sketch_window_start_ms' not in row['metric'] and - 'sketch_window_end_ms' not in row['metric'] for row in rows) - if metric.endswith('rolling_estimate'): - observed.append(float(next(row['value'][1] for row in rows - if row['metric']['quantile'] == '0.5'))) - time.sleep(1) - assert process.returncode == 0, 'streaming demo returned an error' - finally: - if process.poll() is None: - process.terminate() - try: - process.wait(timeout=5) - except subprocess.TimeoutExpired: - process.kill() - process.wait() - trace.seek(0) - print(trace.read(), end='') - for metric in metrics: - after = counts(args.prometheus, metric) - assert all(after.get(q, 0) >= initial[metric].get(q, 0) + 6 for q in ['0.5', '0.99']), (initial, after) - expression = metric + '{quantile=~"0.5|0.99"}' - prometheus = {row['metric']['quantile']: float(row['value'][1]) - for row in query(args.prometheus, expression)} - grafana = {row['metric']['quantile']: float(row['value'][1]) - for row in query(args.grafana, expression, grafana=True)} - assert prometheus == grafana, (prometheus, grafana) - assert max(observed) - min(observed) > 5, 'rolling median did not follow the changing input' - print('Verified repeated tumbling/rolling writes, stable series, changing rolling values, and matching Grafana queries.') + parser.add_argument('--docker-command', default='docker') + parser.add_argument('--scenarios', nargs='+', default=['exact', 'kll']) + parser.add_argument('--tolerance', type=float, default=0.05, + help='maximum relative error for sketch scenarios') + args, extra = parser.parse_known_args() + demo = subprocess.Popen([ + sys.executable, str(REPO / 'benchmarks/run-streaming.py'), '--demo', + '--docker-command', args.docker_command, '--output', str(REPO / 'benchmark-results/demo-verify'), + '--scenarios', *args.scenarios, '--window-points', '65536', '--rolling-windows', '3', + '--generator-cores', '1', '--demo-rate', '50000', '--run-seconds', '60', *extra]) + try: + deadline = time.monotonic() + 240 + while True: + assert demo.poll() is None, 'demo exited before metrics were verified' + assert time.monotonic() < deadline, 'demo metrics did not appear' + windows = values(args.prometheus, 'asap_demo_completed_windows', ['scenario']) + rolling = values(args.prometheus, 'asap_demo_estimate{window_kind="rolling"}', ['scenario']) + if all(windows.get((s,), 0) >= 4 for s in args.scenarios) and len(rolling) == len(args.scenarios): + break + time.sleep(2) + throughput = values(args.prometheus, 'asap_demo_validated_signals_per_second', ['scenario']) + assert all(throughput[(s,)] > 0 for s in args.scenarios), throughput + cpu = values(args.prometheus, 'asap_demo_cpu_cores', ['scenario', 'component']) + assert all((s, c) in cpu for s in args.scenarios for c in PROCESSORS), cpu + errors = values(args.prometheus, 'asap_demo_relative_error', + ['scenario', 'window_kind', 'quantile']) + assert {(s, k, q) for s in args.scenarios for k in ('tumbling', 'rolling') + for q in ('0.5', '0.99')} <= set(errors), errors + for (scenario, _, _), error in errors.items(): + assert error <= (0.0 if scenario == 'exact' else args.tolerance), errors + expression = 'asap_demo_estimate' + keys = ['scenario', 'window_kind', 'quantile'] + assert set(values(args.prometheus, expression, keys)) == set( + values(args.grafana, expression, keys, grafana=True)) + with urllib.request.urlopen(args.grafana.rstrip('/') + '/api/dashboards/uid/asap-kll-stream', + timeout=10) as response: + dashboard = json.load(response)['dashboard'] + assert any('asap_demo_validated_signals_per_second' in t['expr'] + for p in dashboard['panels'] for t in p['targets']) + print('throughput (signals/s):', {k[0]: round(v) for k, v in throughput.items()}) + print('relative error:', {'/'.join(k): round(v, 5) for k, v in sorted(errors.items())}) + print('Verified per-process throughput/CPU, tumbling and rolling accuracy, and Grafana queries.') + finally: + demo.wait(timeout=180) + assert demo.returncode == 0, 'demo returned an error' if __name__ == '__main__': diff --git a/docs/demo-guide.md b/docs/demo-guide.md index 6c96188..ef48d22 100644 --- a/docs/demo-guide.md +++ b/docs/demo-guide.md @@ -69,8 +69,9 @@ cargo test --features otap-engine --test otap_pipeline_e2e The runnable binary additionally asserts that the final output contains p50 and p99 after the four child processes finish successfully. -For a persistent stream with mergeable tumbling panes and rolling quantiles, -see [the continuous KLL demo](./kll-windows.md). +For a continuous stream with one pinned process per processor, rolling +quantiles, and a live KLL vs exact comparison, see +[the multi-process streaming KLL demo](./kll-windows.md). ## Write KLL estimates to Prometheus and view them in Grafana diff --git a/docs/images/kll-streaming-grafana.png b/docs/images/kll-streaming-grafana.png index 54e36d76951337bd47c324a9bbd99a2e8478eb26..3bb9747ac902d77f436a3fa0d8ce89a8cc8623cf 100644 GIT binary patch literal 108243 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 z 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