Unverified Commit 280df2a1 authored by Yan Ru Pei's avatar Yan Ru Pei Committed by GitHub
Browse files

test(kv-router): add active sequences trace replay check (#8581)


Signed-off-by: default avatarPeaBrane <yanrpei@gmail.com>
parent 88478b4b
......@@ -2313,7 +2313,6 @@ name = "dynamo-bench"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
"clap 4.6.0",
"dynamo-kv-router",
"dynamo-mocker",
......@@ -2326,8 +2325,10 @@ dependencies = [
"reqwest 0.12.24",
"serde",
"serde_json",
"tempfile",
"tokio",
"tokio-util",
"tracing",
"tracing-subscriber",
"uuid",
]
......
......@@ -56,5 +56,6 @@ For basic model registration without KV routing, use `--router-mode round-robin`
- **[Disaggregated Serving](router-disaggregated-serving.md)**: Prefill and decode routing setups
- **[Router Operations](router-operations.md)**: Replicas, persistence, and recovery
- **[Router Examples](router-examples.md)**: Python API usage, K8s examples, and custom routing patterns
- **[Router Testing](router-testing.md)**: Test layers from Rust unit tests to fixture-backed replay and full process E2E
- **[Standalone Indexer](standalone-indexer.md)**: Run the KV indexer as a separate service for independent scaling
- **[Router Design](../../design-docs/router-design.md)**: Architecture details, algorithms, and event transport modes
......@@ -217,5 +217,6 @@ You can also run the KV router as a standalone service (without the Dynamo front
- **[Disaggregated Serving](router-disaggregated-serving.md)**: Prefill and decode routing setups
- **[Router Operations](router-operations.md)**: Replicas, remote indexers, persistence, and recovery
- **[Router Examples](router-examples.md)**: Python API usage, K8s examples, and custom routing patterns
- **[Router Testing](router-testing.md)**: Recommended test layers for non-trivial router changes
- **[Standalone Indexer](standalone-indexer.md)**: Run the KV indexer as a separate service
- **[KV Event Replay — Dynamo vs vLLM](kv-event-replay-comparison.md)**: Gap detection and replay behavior
---
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
title: Router Testing
subtitle: Test layers for router changes
---
## Overview
The router has three useful test layers. When you add a non-trivial or potentially breaking feature, do not stop at the smallest local test by default. Consider extending the relevant layer or layers below so the change is covered at the same level where it can fail.
## 1. Rust Unit and Integration Tests
Use Rust tests in `lib/kv-router` and `lib/llm` for local correctness:
- cost-model math
- indexer behavior
- event application
- recovery and persistence logic
- sequence-tracking invariants
- remote-indexer query behavior
These tests should be the first line of defense for narrowly scoped logic. They are the right place to pin exact edge cases and regressions close to the implementation.
Examples:
- `lib/kv-router/src/indexer/tests.rs`
- `lib/kv-router/src/sequences/*`
- `lib/llm/src/kv_router/indexer/worker_query.rs`
Typical commands:
```bash
cargo test -p dynamo-kv-router
cargo test -p dynamo-llm --no-default-features
```
## 2. Bench-Backed E2E Invariant Tests
Use the fixture-backed tests in `lib/bench/tests` when you want a realistic replay path without launching the full router stack. These tests share the same replay machinery as the Mooncake and active-sequences benches, but run in the Rust test profile and assert invariants instead of reporting benchmark numbers.
Current coverage uses the checked-in 1000-line Mooncake trace fixture:
- [active_sequences_trace.rs](../../../lib/bench/tests/active_sequences_trace.rs)
- [mooncake_trace.rs](../../../lib/bench/tests/mooncake_trace.rs)
- [mooncake_trace_1000.jsonl](../../../lib/bench/testdata/mooncake_trace_1000.jsonl)
These tests are useful for catching regressions such as:
- state not draining at the end of replay
- unexpected `WARN` or `ERROR` logs on hot paths
- duplicate-store or similar warning metrics
- indexer-specific replay behavior differences across implementations
Typical command:
```bash
cargo test --package dynamo-bench --all-targets
```
Use this layer when a feature changes router behavior over time, depends on realistic event orderings, or should hold across multiple indexer implementations.
## 3. Full Router E2E Process Tests
Use the Python tests in `tests/router` when you need the full request plane and event plane in play. These tests launch router and mocker or backend processes and exercise cross-process behavior that bench-backed replay cannot cover.
Current entry points include:
- [test_router_e2e_with_mockers.py](../../../tests/router/test_router_e2e_with_mockers.py)
- [test_router_e2e_with_vllm.py](../../../tests/router/test_router_e2e_with_vllm.py)
- [test_router_e2e_with_trtllm.py](../../../tests/router/test_router_e2e_with_trtllm.py)
- [test_router_e2e_with_sglang.py](../../../tests/router/test_router_e2e_with_sglang.py)
Use this layer for changes involving:
- process boundaries
- request routing through the Dynamo frontend or router service
- worker registration and discovery
- event-plane transport and delivery
- backend integration behavior
- startup, recovery, or lifecycle flows
Typical command:
```bash
.venv/bin/python -m pytest tests/router/test_router_e2e_with_mockers.py
```
## Recommended Usage
When a router change is non-trivial or potentially breaking, consider the following default progression:
- Add or update Rust unit tests for the local logic.
- Add or update a bench-backed invariant test if the change affects replay ordering, indexer behavior, cache-event handling, or state-drain assumptions.
- Add or update a full `tests/router` E2E test if the change depends on real processes, transport, registration, or backend interaction.
Not every change needs all three layers. But if a change can break behavior outside a single module boundary, it usually deserves more than a unit test.
......@@ -21,11 +21,6 @@ name = "offline_replay_bench"
path = "offline_replay_bench.rs"
harness = false
[[bench]]
name = "kv_indexer_bench"
path = "kv_router/kv_indexer_bench.rs"
harness = false
[[bench]]
name = "mooncake_bench"
path = "kv_router/mooncake_bench.rs"
......@@ -49,12 +44,13 @@ tokio = { workspace = true }
dynamo-mocker = { workspace = true }
[dev-dependencies]
async-trait = { workspace = true }
dynamo-kv-router = { workspace = true, features = ["bench", "shard-metrics"] }
dynamo-kv-router = { workspace = true, features = ["bench", "metrics", "shard-metrics"] }
dynamo-tokens = { workspace = true }
minstant = "0.1.7"
plotters = { version = "0.3", default-features = false, features = ["svg_backend", "line_series", "point_series", "full_palette"] }
tokio = { workspace = true, features = ["rt", "macros", "time"] }
tokio-util = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
tempfile = { workspace = true }
uuid = { workspace = true }
......@@ -5,15 +5,11 @@
mod common;
use common::*;
#[path = "active_sequences_shared.rs"]
mod active_sequences_shared;
use active_sequences_shared::{generate_sequence_events, run_benchmark};
use clap::Parser;
use common::NoopSequencePublisher;
use dynamo_kv_router::protocols::{PrefillLoadHint, WorkerWithDpRank};
use dynamo_kv_router::{ActiveSequencesMultiWorker, SequenceRequest};
use dynamo_mocker::loadgen::Trace;
use dynamo_tokens::SequenceHash;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::time::{Duration, Instant};
#[derive(Parser, Debug)]
#[clap(
......@@ -29,483 +25,15 @@ struct Args {
sweep_output: String,
}
/// Pre-computed metadata for a request, stored before submission so the
/// output signal can look it up by UUID.
struct RequestMetadata {
block_hashes: Vec<SequenceHash>,
isl: usize,
output_length: u64,
}
/// A single timestamped entry in a worker's sequence trace.
#[derive(Clone)]
enum SequenceTraceEntry {
Add {
request_id: String,
block_hashes: Vec<SequenceHash>,
isl: usize,
output_length: u64,
},
PrefillComplete {
request_id: String,
},
Free {
request_id: String,
},
}
/// A timestamped sequence trace entry for benchmark replay.
#[derive(Clone)]
struct SequenceTrace {
entry: SequenceTraceEntry,
timestamp_us: u64,
}
/// Run requests through the mocker to produce sequence lifecycle events
/// (add / prefill_complete / free) with realistic timing.
///
/// For each worker we:
/// 1. Create a Scheduler with an output_tx channel (no KvCacheEventSink needed)
/// 2. Pre-compute block hashes for each request
/// 3. Drain OutputSignal: first signal per UUID → Add + PrefillComplete,
/// completed=true → Free
/// 4. Collect timestamps for later replay
async fn generate_sequence_events(
traces: &[Trace],
num_gpu_blocks: usize,
block_size: u32,
trace_simulation_duration_ms: u64,
) -> anyhow::Result<Vec<Vec<SequenceTrace>>> {
println!("Generating sequence events...");
let artifacts = generate_replay_artifacts(
traces,
num_gpu_blocks,
block_size,
trace_simulation_duration_ms,
)
.await?;
let mut all_traces = Vec::with_capacity(artifacts.len());
for artifact in artifacts {
let metadata = artifact
.requests
.iter()
.map(|request| {
(
request.uuid,
RequestMetadata {
block_hashes: request.replay_hashes.sequence_hashes.clone(),
isl: request.input_length,
output_length: request.output_length as u64,
},
)
})
.collect::<HashMap<_, _>>();
let mut entries = Vec::new();
let mut seen = HashMap::new();
for timed_signal in artifact.output_signals {
let signal = timed_signal.signal;
let request_id = signal.uuid.to_string();
if let std::collections::hash_map::Entry::Vacant(entry) = seen.entry(signal.uuid) {
entry.insert(());
if let Some(meta) = metadata.get(&signal.uuid) {
entries.push(SequenceTrace {
entry: SequenceTraceEntry::Add {
request_id: request_id.clone(),
block_hashes: meta.block_hashes.clone(),
isl: meta.isl,
output_length: meta.output_length,
},
timestamp_us: timed_signal.timestamp_us,
});
entries.push(SequenceTrace {
entry: SequenceTraceEntry::PrefillComplete {
request_id: request_id.clone(),
},
timestamp_us: timed_signal.timestamp_us,
});
}
}
if signal.completed {
entries.push(SequenceTrace {
entry: SequenceTraceEntry::Free { request_id },
timestamp_us: timed_signal.timestamp_us,
});
}
}
all_traces.push(entries);
}
let total_adds = all_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Add { .. }))
.count();
let total_frees = all_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Free { .. }))
.count();
println!("Add events: {}, Free events: {}", total_adds, total_frees);
Ok(all_traces)
}
/// Rescale sequence trace timestamps into the benchmark duration.
fn rescale_traces(
traces: &[Vec<SequenceTrace>],
benchmark_duration_ms: u64,
) -> Vec<Vec<SequenceTrace>> {
traces
.iter()
.map(|worker_trace| {
if worker_trace.is_empty() {
return Vec::new();
}
let max_ts = worker_trace
.last()
.map(|e| e.timestamp_us)
.unwrap_or(1)
.max(1);
let target_us = benchmark_duration_ms * 1000;
worker_trace
.iter()
.map(|entry| SequenceTrace {
entry: entry.entry.clone(),
timestamp_us: entry.timestamp_us * target_us / max_ts,
})
.collect()
})
.collect()
}
/// Run the benchmark: replay sequence trace entries against a shared
/// ActiveSequencesMultiWorker, measuring potential_blocks_and_tokens /
/// add_request / mark_prefill_completed / free latency.
async fn run_benchmark(
traces: &[Vec<SequenceTrace>],
block_size: u32,
benchmark_duration_ms: u64,
inference_worker_duplication_factor: usize,
) -> anyhow::Result<BenchmarkResults> {
let scaled = rescale_traces(traces, benchmark_duration_ms);
let num_trace_workers = scaled.len();
// Total bench workers = trace workers × duplication factor.
// Each gets a unique WorkerWithDpRank in the shared multi-worker.
let total_workers = num_trace_workers * inference_worker_duplication_factor;
let dp_range: HashMap<u64, (u32, u32)> =
(0..total_workers as u64).map(|id| (id, (0, 1))).collect();
let multi = Arc::new(ActiveSequencesMultiWorker::new(
NoopSequencePublisher,
block_size as usize,
dp_range,
false,
0,
"bench",
));
let total_entries: u64 = scaled.iter().map(|t| t.len() as u64).sum::<u64>()
* inference_worker_duplication_factor as u64;
// Count blocks before consuming traces
let total_blocks: usize = scaled
.iter()
.flat_map(|t| t.iter())
.map(|entry| match &entry.entry {
SequenceTraceEntry::Add { block_hashes, .. } => block_hashes.len(),
_ => 0,
})
.sum::<usize>()
* inference_worker_duplication_factor;
let progress = make_progress_bar(Some(total_entries));
let mut tasks = Vec::new();
for replica in 0..inference_worker_duplication_factor {
for (trace_idx, worker_trace) in scaled.iter().enumerate() {
let worker_id = (replica * num_trace_workers + trace_idx) as u64;
let worker = WorkerWithDpRank::from_worker_id(worker_id);
// Make request IDs unique per worker so the shared map has no conflicts
let trace = make_unique_trace(worker_trace, worker_id);
let progress = progress.clone();
let multi = Arc::clone(&multi);
tasks.push(tokio::spawn(async move {
let capacity = trace.len();
let mut latencies: Vec<u64> = Vec::with_capacity(capacity);
let mut target = Instant::now();
let mut iter = trace.into_iter().peekable();
let mut local_count: u64 = 0;
while let Some(entry) = iter.next() {
let entry_ts = entry.timestamp_us;
let start = minstant::Instant::now();
apply_entry(&multi, worker, entry.entry).await;
latencies.push(start.elapsed().as_nanos() as u64);
local_count += 1;
// Process all entries at the same timestamp
while iter.peek().is_some_and(|e| e.timestamp_us == entry_ts) {
let e = iter.next().unwrap();
let start = minstant::Instant::now();
apply_entry(&multi, worker, e.entry).await;
latencies.push(start.elapsed().as_nanos() as u64);
local_count += 1;
}
if let Some(next) = iter.peek() {
target += Duration::from_micros(next.timestamp_us - entry_ts);
}
if target > Instant::now() {
tokio::time::sleep_until(target).await;
}
if local_count > 100 {
progress.inc(local_count);
local_count = 0;
}
}
progress.inc(local_count);
Ok::<_, anyhow::Error>(latencies)
}));
}
}
let mut all_latencies = Vec::new();
for task in tasks {
all_latencies.extend(task.await??);
}
// Keep the post-run drain check out of the measured benchmark interval.
let total_duration = progress.elapsed();
multi.assert_completely_drained(Instant::now());
if total_duration > Duration::from_millis(benchmark_duration_ms * 11 / 10) {
eprintln!(
"WARNING: Benchmarker could not keep up. Rerun with a larger --benchmark-duration-ms."
);
}
let total_ops = all_latencies.len();
let offered_ops_throughput = total_ops as f32 / benchmark_duration_ms as f32 * 1000.0;
let ops_throughput = total_ops as f32 / total_duration.as_millis() as f32 * 1000.0;
let offered_block_throughput = total_blocks as f32 / benchmark_duration_ms as f32 * 1000.0;
let block_throughput = total_blocks as f32 / total_duration.as_millis() as f32 * 1000.0;
all_latencies.sort_unstable();
let latency_p99_us = if all_latencies.is_empty() {
0.0
} else {
all_latencies[all_latencies.len() * 99 / 100] as f32 / 1000.0
};
println!(
"Ops Throughput: offered={} ops/s achieved={} ops/s (potential_blocks_and_tokens + add + prefill_complete + free)",
offered_ops_throughput, ops_throughput
);
println!(
"Block Throughput: offered={} block ops/s achieved={} block ops/s",
offered_block_throughput, block_throughput
);
println!("Latency p99: {}us", latency_p99_us);
Ok(BenchmarkResults {
offered_ops_throughput,
ops_throughput,
offered_block_throughput,
block_throughput,
latency_p99_us,
})
}
/// Make request IDs unique by prefixing with the worker ID, so the shared
/// request_to_worker map has no conflicts when traces are duplicated.
fn make_unique_trace(trace: &[SequenceTrace], worker_id: u64) -> Vec<SequenceTrace> {
trace
.iter()
.map(|entry| {
let new_entry = match &entry.entry {
SequenceTraceEntry::Add {
request_id,
block_hashes,
isl,
output_length,
} => SequenceTraceEntry::Add {
request_id: format!("{worker_id}:{request_id}"),
block_hashes: block_hashes.clone(),
isl: *isl,
output_length: *output_length,
},
SequenceTraceEntry::PrefillComplete { request_id } => {
SequenceTraceEntry::PrefillComplete {
request_id: format!("{worker_id}:{request_id}"),
}
}
SequenceTraceEntry::Free { request_id } => SequenceTraceEntry::Free {
request_id: format!("{worker_id}:{request_id}"),
},
};
SequenceTrace {
entry: new_entry,
timestamp_us: entry.timestamp_us,
}
})
.collect()
}
async fn apply_entry(
multi: &ActiveSequencesMultiWorker<NoopSequencePublisher>,
worker: WorkerWithDpRank,
entry: SequenceTraceEntry,
) {
let decay_now = tokio::time::Instant::now();
match entry {
SequenceTraceEntry::Add {
request_id,
block_hashes,
isl,
output_length,
} => {
let _ = multi.potential_blocks_and_tokens(Some(&block_hashes), isl, HashMap::new());
let _ = multi.add_request(
SequenceRequest {
request_id,
token_sequence: Some(block_hashes),
track_prefill_tokens: true,
expected_output_tokens: Some(output_length as u32),
prefill_load_hint: Some(PrefillLoadHint {
initial_effective_prefill_tokens: isl,
expected_prefill_duration: None,
}),
worker,
lora_name: None,
},
decay_now,
);
}
SequenceTraceEntry::PrefillComplete { request_id } => {
let _ = multi.mark_prefill_completed(&request_id, decay_now);
}
SequenceTraceEntry::Free { request_id } => {
let _ = multi.free(&request_id, decay_now);
}
}
}
async fn run_tests() -> anyhow::Result<()> {
use std::fs::File;
use std::io::Write;
let path = std::env::temp_dir().join(format!(
"active_seq_bench_test_{}.jsonl",
std::process::id()
));
{
let mut f = File::create(&path)?;
writeln!(
f,
"{}",
serde_json::json!({
"session_id": "session-a",
"timestamp": 0,
"input_length": 4,
"hash_ids": [0u64, 1, 2, 3],
"output_length": 10u64,
})
)?;
writeln!(
f,
"{}",
serde_json::json!({
"session_id": "session-a",
"delay": 5.0,
"input_length": 4,
"hash_ids": [4u64, 5, 6, 7],
"output_length": 10u64,
})
)?;
}
let traces = process_mooncake_trace(path.to_str().unwrap(), 512, 1, 1, 1, 42)?;
std::fs::remove_file(&path).ok();
println!(
"Loaded {} workers, {} total requests",
traces.len(),
traces
.iter()
.map(|trace| trace
.sessions
.iter()
.map(|session| session.turns.len())
.sum::<usize>())
.sum::<usize>()
);
let seq_traces = generate_sequence_events(&traces, 1048576, 512, 100).await?;
let total_adds = seq_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Add { .. }))
.count();
let total_frees = seq_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Free { .. }))
.count();
assert!(total_adds > 0, "expected at least one Add event");
assert!(total_frees > 0, "expected at least one Free event");
assert_eq!(total_adds, total_frees, "adds and frees should match");
for trace in &seq_traces {
assert!(
trace
.windows(2)
.all(|window| window[1].timestamp_us >= window[0].timestamp_us)
);
}
let first_free_us = seq_traces[0]
.iter()
.find_map(|entry| match entry.entry {
SequenceTraceEntry::Free { .. } => Some(entry.timestamp_us),
_ => None,
})
.unwrap();
let second_add_us = seq_traces[0]
.iter()
.filter_map(|entry| match entry.entry {
SequenceTraceEntry::Add { .. } => Some(entry.timestamp_us),
_ => None,
})
.nth(1)
.unwrap();
assert!(second_add_us >= first_free_us);
println!("All tests passed.");
Ok(())
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
init_sequence_logging(args.common.sequence_logs);
if args.common.test {
return run_tests().await;
anyhow::bail!(
"active_sequences_bench no longer supports --test; run `cargo test --package dynamo-bench --test active_sequences_trace` instead"
);
}
let path = match args.common.mooncake_trace_path.as_deref() {
......@@ -542,14 +70,19 @@ async fn main() -> anyhow::Result<()> {
let mut results: Vec<(u64, BenchmarkResults)> = Vec::new();
for &dur_ms in &durations {
println!("\n=== Sweep: benchmark_duration_ms = {} ===", dur_ms);
let result = run_benchmark(
let run = run_benchmark(
&seq_traces,
args.common.block_size,
dur_ms,
args.common.inference_worker_duplication_factor,
)
.await?;
results.push((dur_ms, result));
if !run.kept_up {
eprintln!(
"WARNING: Benchmarker could not keep up. Rerun with a larger --benchmark-duration-ms."
);
}
results.push((dur_ms, run.results));
}
print_sweep_summary("active-sequences", &results);
......@@ -557,13 +90,18 @@ async fn main() -> anyhow::Result<()> {
let all_results = vec![("active-sequences", results)];
plot_sweep(&all_results, &args.sweep_output)?;
} else {
run_benchmark(
let run = run_benchmark(
&seq_traces,
args.common.block_size,
args.common.benchmark_duration_ms,
args.common.inference_worker_duplication_factor,
)
.await?;
if !run.kept_up {
eprintln!(
"WARNING: Benchmarker could not keep up. Rerun with a larger --benchmark-duration-ms."
);
}
}
Ok(())
......
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use std::collections::HashMap;
use std::sync::Arc;
use dynamo_kv_router::protocols::{PrefillLoadHint, WorkerWithDpRank};
use dynamo_kv_router::{ActiveSequencesMultiWorker, SequenceRequest};
use dynamo_mocker::loadgen::Trace;
use dynamo_tokens::SequenceHash;
use tokio::time::{Duration, Instant};
use crate::common::{
BenchmarkRun, NoopSequencePublisher, compute_benchmark_run, generate_replay_artifacts,
make_progress_bar, rescale_trace_timestamps,
};
/// A single timestamped entry in a worker's sequence trace.
#[derive(Clone)]
pub enum SequenceTraceEntry {
Add {
request_id: String,
block_hashes: Vec<SequenceHash>,
isl: usize,
output_length: u64,
},
PrefillComplete {
request_id: String,
},
Free {
request_id: String,
},
}
/// A timestamped sequence trace entry for benchmark replay.
#[derive(Clone)]
pub struct SequenceTrace {
pub entry: SequenceTraceEntry,
pub timestamp_us: u64,
}
/// Pre-computed metadata for a request, stored before submission so the
/// output signal can look it up by UUID.
struct RequestMetadata {
block_hashes: Vec<SequenceHash>,
isl: usize,
output_length: u64,
}
/// Run requests through the mocker to produce sequence lifecycle events
/// (add / prefill_complete / free) with realistic timing.
pub async fn generate_sequence_events(
traces: &[Trace],
num_gpu_blocks: usize,
block_size: u32,
trace_simulation_duration_ms: Option<u64>,
) -> anyhow::Result<Vec<Vec<SequenceTrace>>> {
println!("Generating sequence events...");
let artifacts = generate_replay_artifacts(
traces,
num_gpu_blocks,
block_size,
trace_simulation_duration_ms,
)
.await?;
let mut all_traces = Vec::with_capacity(artifacts.len());
for artifact in artifacts {
let metadata = artifact
.requests
.iter()
.map(|request| {
(
request.uuid,
RequestMetadata {
block_hashes: request.replay_hashes.sequence_hashes.clone(),
isl: request.input_length,
output_length: request.output_length as u64,
},
)
})
.collect::<HashMap<_, _>>();
let mut entries = Vec::new();
let mut seen = HashMap::new();
for timed_signal in artifact.output_signals {
let signal = timed_signal.signal;
let request_id = signal.uuid.to_string();
if let std::collections::hash_map::Entry::Vacant(entry) = seen.entry(signal.uuid) {
entry.insert(());
if let Some(meta) = metadata.get(&signal.uuid) {
entries.push(SequenceTrace {
entry: SequenceTraceEntry::Add {
request_id: request_id.clone(),
block_hashes: meta.block_hashes.clone(),
isl: meta.isl,
output_length: meta.output_length,
},
timestamp_us: timed_signal.timestamp_us,
});
entries.push(SequenceTrace {
entry: SequenceTraceEntry::PrefillComplete {
request_id: request_id.clone(),
},
timestamp_us: timed_signal.timestamp_us,
});
}
}
if signal.completed {
entries.push(SequenceTrace {
entry: SequenceTraceEntry::Free { request_id },
timestamp_us: timed_signal.timestamp_us,
});
}
}
all_traces.push(entries);
}
let total_adds = all_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Add { .. }))
.count();
let total_frees = all_traces
.iter()
.flatten()
.filter(|e| matches!(e.entry, SequenceTraceEntry::Free { .. }))
.count();
println!("Add events: {}, Free events: {}", total_adds, total_frees);
Ok(all_traces)
}
/// Run the benchmark: replay sequence trace entries against a shared
/// ActiveSequencesMultiWorker, measuring potential_blocks_and_tokens /
/// add_request / mark_prefill_completed / free latency.
pub async fn run_benchmark(
traces: &[Vec<SequenceTrace>],
block_size: u32,
benchmark_duration_ms: u64,
inference_worker_duplication_factor: usize,
) -> anyhow::Result<BenchmarkRun> {
let scaled = rescale_trace_timestamps(
traces,
benchmark_duration_ms,
|entry| entry.timestamp_us,
|entry, timestamp_us| SequenceTrace {
entry: entry.entry.clone(),
timestamp_us,
},
);
let num_trace_workers = scaled.len();
let total_workers = num_trace_workers * inference_worker_duplication_factor;
let dp_range: HashMap<u64, (u32, u32)> =
(0..total_workers as u64).map(|id| (id, (0, 1))).collect();
let multi = Arc::new(ActiveSequencesMultiWorker::new(
NoopSequencePublisher,
block_size as usize,
dp_range,
false,
0,
"bench",
));
let total_entries: u64 = scaled.iter().map(|t| t.len() as u64).sum::<u64>()
* inference_worker_duplication_factor as u64;
let total_blocks: usize = scaled
.iter()
.flat_map(|t| t.iter())
.map(|entry| match &entry.entry {
SequenceTraceEntry::Add { block_hashes, .. } => block_hashes.len(),
_ => 0,
})
.sum::<usize>()
* inference_worker_duplication_factor;
let progress = make_progress_bar(Some(total_entries));
let mut tasks = Vec::new();
for replica in 0..inference_worker_duplication_factor {
for (trace_idx, worker_trace) in scaled.iter().enumerate() {
let worker_id = (replica * num_trace_workers + trace_idx) as u64;
let worker = WorkerWithDpRank::from_worker_id(worker_id);
let trace = make_unique_trace(worker_trace, worker_id);
let progress = progress.clone();
let multi = Arc::clone(&multi);
tasks.push(tokio::spawn(async move {
let capacity = trace.len();
let mut latencies: Vec<u64> = Vec::with_capacity(capacity);
let mut target = Instant::now();
let mut iter = trace.into_iter().peekable();
let mut local_count: u64 = 0;
while let Some(entry) = iter.next() {
let entry_ts = entry.timestamp_us;
let start = minstant::Instant::now();
apply_entry(&multi, worker, entry.entry).await;
latencies.push(start.elapsed().as_nanos() as u64);
local_count += 1;
while iter.peek().is_some_and(|e| e.timestamp_us == entry_ts) {
let e = iter.next().unwrap();
let start = minstant::Instant::now();
apply_entry(&multi, worker, e.entry).await;
latencies.push(start.elapsed().as_nanos() as u64);
local_count += 1;
}
if let Some(next) = iter.peek() {
target += Duration::from_micros(next.timestamp_us - entry_ts);
}
if target > Instant::now() {
tokio::time::sleep_until(target).await;
}
if local_count > 100 {
progress.inc(local_count);
local_count = 0;
}
}
progress.inc(local_count);
Ok::<_, anyhow::Error>(latencies)
}));
}
}
let mut all_latencies = Vec::new();
for task in tasks {
all_latencies.extend(task.await??);
}
let total_duration = progress.elapsed();
multi.assert_completely_drained(Instant::now());
let run = compute_benchmark_run(
all_latencies.len(),
total_blocks,
benchmark_duration_ms,
total_duration,
all_latencies,
);
println!(
"Ops Throughput: offered={} ops/s achieved={} ops/s (potential_blocks_and_tokens + add + prefill_complete + free)",
run.results.offered_ops_throughput, run.results.ops_throughput
);
println!(
"Block Throughput: offered={} block ops/s achieved={} block ops/s",
run.results.offered_block_throughput, run.results.block_throughput
);
println!("Latency p99: {}us", run.results.latency_p99_us);
Ok(run)
}
fn make_unique_trace(trace: &[SequenceTrace], worker_id: u64) -> Vec<SequenceTrace> {
trace
.iter()
.map(|entry| {
let new_entry = match &entry.entry {
SequenceTraceEntry::Add {
request_id,
block_hashes,
isl,
output_length,
} => SequenceTraceEntry::Add {
request_id: format!("{worker_id}:{request_id}"),
block_hashes: block_hashes.clone(),
isl: *isl,
output_length: *output_length,
},
SequenceTraceEntry::PrefillComplete { request_id } => {
SequenceTraceEntry::PrefillComplete {
request_id: format!("{worker_id}:{request_id}"),
}
}
SequenceTraceEntry::Free { request_id } => SequenceTraceEntry::Free {
request_id: format!("{worker_id}:{request_id}"),
},
};
SequenceTrace {
entry: new_entry,
timestamp_us: entry.timestamp_us,
}
})
.collect()
}
async fn apply_entry(
multi: &ActiveSequencesMultiWorker<NoopSequencePublisher>,
worker: WorkerWithDpRank,
entry: SequenceTraceEntry,
) {
let decay_now = tokio::time::Instant::now();
match entry {
SequenceTraceEntry::Add {
request_id,
block_hashes,
isl,
output_length,
} => {
let _ = multi.potential_blocks_and_tokens(Some(&block_hashes), isl, HashMap::new());
let _ = multi.add_request(
SequenceRequest {
request_id,
token_sequence: Some(block_hashes),
track_prefill_tokens: true,
expected_output_tokens: Some(output_length as u32),
prefill_load_hint: Some(PrefillLoadHint {
initial_effective_prefill_tokens: isl,
expected_prefill_duration: None,
}),
worker,
lora_name: None,
},
decay_now,
);
}
SequenceTraceEntry::PrefillComplete { request_id } => {
let _ = multi.mark_prefill_completed(&request_id, decay_now);
}
SequenceTraceEntry::Free { request_id } => {
let _ = multi.free(&request_id, decay_now);
}
}
}
......@@ -5,39 +5,35 @@
use std::time::Duration;
#[path = "shared.rs"]
mod shared;
use dynamo_kv_router::LocalBlockHash;
use dynamo_kv_router::protocols::{
ExternalSequenceBlockHash, KvCacheEvent, KvCacheEventData, KvCacheRemoveData, KvCacheStoreData,
KvCacheStoredBlockData, RouterEvent, WorkerId, XXH3_SEED, compute_seq_hash_for_block,
};
pub use dynamo_kv_router::test_utils::{NoopSequencePublisher, SimpleWorkerConfig};
use dynamo_mocker::common::protocols::MockEngineArgs;
use dynamo_mocker::loadgen::{
ArrivalSpec, DelaySpec, LengthSpec, ReplayRequestHashes, RouterSequence, SequenceHashMode,
SessionPartitionSpec, SyntheticTraceSpec, Trace,
};
pub use dynamo_mocker::replay::{
ReplayTimedKvEvent as TimedKvEvent, ReplayTimedOutputSignal as TimedOutputSignal,
ReplayTimedRequest as TimedReplayRequest, ReplayWorkerArtifacts as WorkerReplayArtifacts,
};
use dynamo_kv_router::protocols::XXH3_SEED;
use dynamo_mocker::loadgen::{ReplayRequestHashes, Trace};
use dynamo_tokens::compute_hash_v2;
use indicatif::{ProgressBar, ProgressStyle};
use plotters::prelude::*;
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{BufRead, BufReader};
use tokio::task::JoinHandle;
use tracing_subscriber::EnvFilter;
use uuid::Uuid;
pub use shared::{
BenchmarkResults, BenchmarkRun, NoopSequencePublisher, WorkerReplayArtifacts,
compute_benchmark_run, default_mock_engine_args, generate_replay_artifacts, make_progress_bar,
process_mooncake_trace, rescale_trace_timestamps,
};
/// Shared CLI arguments for trace-based benchmarks.
#[derive(clap::Args, Debug)]
pub struct CommonArgs {
/// Path to a JSONL mooncake trace file.
pub mooncake_trace_path: Option<String>,
/// Run built-in self-tests instead of the benchmark.
/// Deprecated compatibility flag. Use `cargo test --package dynamo-bench --test ...`
/// for the fixture-backed integration tests instead.
#[clap(long)]
pub test: bool,
......@@ -49,9 +45,10 @@ pub struct CommonArgs {
#[clap(long, default_value = "128")]
pub block_size: u32,
/// Wall-clock duration (ms) over which the trace is replayed during event generation.
#[clap(long, default_value = "30000")]
pub trace_simulation_duration_ms: u64,
/// Optional wall-clock duration (ms) used to rescale the trace during event generation.
/// Omit to preserve the original Mooncake timestamps.
#[clap(long)]
pub trace_simulation_duration_ms: Option<u64>,
/// Wall-clock duration (ms) over which the benchmark replays operations.
#[clap(long, default_value = "60000")]
......@@ -313,171 +310,6 @@ pub fn local_block_hash_from_id(hash_id: u64, block_size: u32) -> LocalBlockHash
LocalBlockHash(compute_hash_v2(bytes, XXH3_SEED))
}
/// Create a styled progress bar, optionally with a known total length.
pub fn make_progress_bar(total: Option<u64>) -> ProgressBar {
let progress = match total {
Some(total) => ProgressBar::new(total),
None => ProgressBar::no_length(),
};
progress.set_style(
ProgressStyle::with_template(
"[{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} ({eta}) {msg}",
)
.unwrap()
.progress_chars("#>-"),
);
progress
}
/// Results from a single benchmark run.
#[derive(Serialize)]
pub struct BenchmarkResults {
pub offered_ops_throughput: f32,
pub ops_throughput: f32,
pub offered_block_throughput: f32,
pub block_throughput: f32,
pub latency_p99_us: f32,
}
/// Load, transform, and partition the mooncake trace into per-worker request lists.
pub fn process_mooncake_trace(
path: &str,
block_size: u32,
trace_length_factor: usize,
trace_duplication_factor: usize,
num_workers: usize,
seed: u64,
) -> anyhow::Result<Vec<Trace>> {
let trace = Trace::from_mooncake(std::path::Path::new(path), block_size as usize)?
.expand_hash_prefix_depth(trace_length_factor)
.duplicate_hash_space(trace_duplication_factor);
Ok(trace.partition_by_session(SessionPartitionSpec::Random {
num_partitions: num_workers,
seed,
}))
}
/// Build default MockEngineArgs suitable for event generation.
pub fn default_mock_engine_args(
num_gpu_blocks: usize,
block_size: usize,
) -> anyhow::Result<MockEngineArgs> {
Ok(MockEngineArgs::builder()
.num_gpu_blocks(num_gpu_blocks)
.block_size(block_size)
.speedup_ratio(10.0)
.enable_prefix_caching(true)
.max_num_batched_tokens(None)
.max_num_seqs(None)
.build()?)
}
fn replay_worker_trace(
trace: Trace,
sched_args: MockEngineArgs,
trace_simulation_duration_ms: u64,
progress: ProgressBar,
) -> anyhow::Result<WorkerReplayArtifacts> {
let total_turns = trace
.sessions
.iter()
.map(|session| session.turns.len())
.sum::<usize>();
let artifacts = dynamo_mocker::replay::generate_trace_worker_artifacts_offline(
sched_args,
trace.rescale_ready_span(trace_simulation_duration_ms)?,
)?;
progress.inc(total_turns as u64);
Ok(artifacts)
}
pub async fn generate_replay_artifacts(
traces: &[Trace],
num_gpu_blocks: usize,
block_size: u32,
trace_simulation_duration_ms: u64,
) -> anyhow::Result<Vec<WorkerReplayArtifacts>> {
println!("Generating events...");
let sched_args = default_mock_engine_args(num_gpu_blocks, block_size as usize)?;
let progress = make_progress_bar(Some(
traces
.iter()
.map(|trace| {
trace
.sessions
.iter()
.map(|session| session.turns.len() as u64)
.sum::<u64>()
})
.sum::<u64>(),
));
let mut tasks: Vec<JoinHandle<anyhow::Result<WorkerReplayArtifacts>>> = Vec::new();
for trace in traces.iter().cloned() {
let sched_args = sched_args.clone();
let progress = progress.clone();
tasks.push(tokio::task::spawn_blocking(move || {
replay_worker_trace(trace, sched_args, trace_simulation_duration_ms, progress)
}));
}
let mut artifacts = Vec::new();
for task in tasks {
artifacts.push(task.await??);
}
for worker_events in artifacts.iter().map(|artifact| &artifact.kv_events) {
for i in 1..worker_events.len() {
assert!(worker_events[i].timestamp_us >= worker_events[i - 1].timestamp_us);
}
}
println!(
"Generated {} events. Processing...",
artifacts
.iter()
.map(|artifact| artifact.kv_events.len())
.sum::<usize>()
);
let mut num_stored_events = 0;
let mut num_removed_events = 0;
for event in artifacts
.iter()
.flat_map(|artifact| artifact.kv_events.iter())
{
match event.event.data {
KvCacheEventData::Stored(_) => num_stored_events += 1,
KvCacheEventData::Removed(_) => num_removed_events += 1,
_ => (),
}
}
println!("Store events: {}", num_stored_events);
println!("Remove events: {}", num_removed_events);
Ok(artifacts)
}
pub async fn generate_kv_events(
traces: &[Trace],
num_gpu_blocks: usize,
block_size: u32,
trace_simulation_duration_ms: u64,
) -> anyhow::Result<Vec<Vec<TimedKvEvent>>> {
Ok(generate_replay_artifacts(
traces,
num_gpu_blocks,
block_size,
trace_simulation_duration_ms,
)
.await?
.into_iter()
.map(|artifact| artifact.kv_events)
.collect())
}
pub fn plot_sweep(
all_results: &[(&str, Vec<(u64, BenchmarkResults)>)],
output_path: &str,
......@@ -611,153 +443,6 @@ pub fn print_sweep_summary(name: &str, results: &[(u64, BenchmarkResults)]) {
}
}
// ---------------------------------------------------------------------------
// Sequence data generation (moved from src/bench_utils.rs)
// ---------------------------------------------------------------------------
/// Pre-generated sequence data for benchmarking.
#[derive(Clone)]
pub struct SequenceData {
pub worker_id: WorkerId,
pub local_hashes: Vec<LocalBlockHash>,
pub external_hashes: Vec<ExternalSequenceBlockHash>,
}
impl From<RouterSequence> for SequenceData {
fn from(sequence: RouterSequence) -> Self {
Self {
worker_id: sequence.worker_id,
local_hashes: sequence.local_hashes,
external_hashes: sequence.external_hashes,
}
}
}
impl SequenceData {
/// Create a new sequence with synthetic hashes based on sequence ID.
pub fn new(seq_id: u64, worker_id: WorkerId, depth: usize) -> Self {
let local_hashes: Vec<LocalBlockHash> = (0..depth)
.map(|block_idx| LocalBlockHash((seq_id << 32) | (block_idx as u64)))
.collect();
let external_hashes: Vec<ExternalSequenceBlockHash> = (0..depth)
.map(|block_idx| ExternalSequenceBlockHash((seq_id << 32) | (block_idx as u64)))
.collect();
Self {
worker_id,
local_hashes,
external_hashes,
}
}
/// Create a sequence from local hashes, computing external hashes using cumulative hash.
pub fn from_local_hashes(worker_id: WorkerId, local_hashes: Vec<LocalBlockHash>) -> Self {
let seq_hashes = compute_seq_hash_for_block(&local_hashes);
let external_hashes = seq_hashes
.into_iter()
.map(ExternalSequenceBlockHash)
.collect();
Self {
worker_id,
local_hashes,
external_hashes,
}
}
/// Convert to a store event.
pub fn to_store_event(&self, event_id: u64) -> RouterEvent {
RouterEvent::new(
self.worker_id,
KvCacheEvent {
event_id,
data: KvCacheEventData::Stored(KvCacheStoreData {
parent_hash: None,
start_position: None,
blocks: self
.local_hashes
.iter()
.zip(self.external_hashes.iter())
.map(|(local, ext)| KvCacheStoredBlockData {
tokens_hash: *local,
block_hash: *ext,
mm_extra_info: None,
})
.collect(),
}),
dp_rank: 0,
},
)
}
/// Convert to a remove event.
pub fn to_remove_event(&self, event_id: u64) -> RouterEvent {
RouterEvent::new(
self.worker_id,
KvCacheEvent {
event_id,
data: KvCacheEventData::Removed(KvCacheRemoveData {
block_hashes: self.external_hashes.clone(),
}),
dp_rank: 0,
},
)
}
}
/// Generate sequences with shared prefix prompts.
pub fn generate_sequences(
num_sequences: usize,
depth: usize,
num_workers: usize,
prefix_ratio: f64,
num_prefix_groups: usize,
seed: u64,
use_cumulative_hash: bool,
) -> Vec<SequenceData> {
let trace = Trace::synthetic(SyntheticTraceSpec {
block_size: 1,
num_sessions: num_sequences,
turns_per_session: 1,
input_tokens: LengthSpec {
mean: depth,
stddev: 0.0,
},
output_tokens: LengthSpec {
mean: 1,
stddev: 0.0,
},
shared_prefix_ratio: prefix_ratio,
num_prefix_groups,
first_turn_arrivals: ArrivalSpec::Burst,
inter_turn_delays: DelaySpec::None,
seed,
})
.expect("sequence generation spec must be valid");
let hash_mode = if use_cumulative_hash {
SequenceHashMode::Cumulative
} else {
SequenceHashMode::Raw
};
trace
.partition_by_session(SessionPartitionSpec::RoundRobin {
num_partitions: num_workers,
})
.into_iter()
.enumerate()
.flat_map(|(worker_idx, partition)| {
partition
.to_router_sequences(worker_idx as WorkerId, hash_mode)
.expect("synthetic trace conversion must succeed")
.into_iter()
.map(SequenceData::from)
.collect::<Vec<_>>()
})
.collect()
}
/// Compute median of durations.
pub fn median(durations: &[Duration]) -> Duration {
if durations.is_empty() {
......@@ -767,60 +452,3 @@ pub fn median(durations: &[Duration]) -> Duration {
sorted.sort();
sorted[sorted.len() / 2]
}
#[cfg(test)]
mod tests {
use super::*;
fn multiturn_trace() -> Trace {
Trace {
block_size: 2,
sessions: vec![dynamo_mocker::loadgen::SessionTrace {
session_id: "session-a".to_string(),
first_arrival_timestamp_ms: Some(0.0),
turns: vec![
dynamo_mocker::loadgen::TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![1, 2],
delay_after_previous_ms: 0.0,
},
dynamo_mocker::loadgen::TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![3, 4],
delay_after_previous_ms: 5.0,
},
],
}],
}
}
#[tokio::test]
async fn test_replay_worker_trace_releases_follow_up_turn_after_completion_delay() {
let artifacts = replay_worker_trace(
multiturn_trace(),
default_mock_engine_args(1024, 2).unwrap(),
5,
make_progress_bar(Some(2)),
)
.await
.unwrap();
assert_eq!(artifacts.requests.len(), 2);
let first_uuid = artifacts.requests[0].uuid;
let first_completion_ms = artifacts
.output_signals
.iter()
.find(|signal| signal.signal.uuid == first_uuid && signal.signal.completed)
.unwrap()
.timestamp_us as f64
/ 1000.0;
assert!(
artifacts.requests[1].scheduled_ready_at_ms + 0.1 >= first_completion_ms + 5.0,
"expected follow-up turn to wait for completion plus delay, got ready_at={} completion_at={}",
artifacts.requests[1].scheduled_ready_at_ms,
first_completion_ms
);
}
}
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use dynamo_kv_router::protocols::KvCacheEventData;
#[allow(unused_imports)]
pub use dynamo_kv_router::test_utils::NoopSequencePublisher;
use dynamo_mocker::common::protocols::MockEngineArgs;
use dynamo_mocker::loadgen::{SessionPartitionSpec, Trace};
pub use dynamo_mocker::replay::ReplayWorkerArtifacts as WorkerReplayArtifacts;
use indicatif::{ProgressBar, ProgressStyle};
use serde::Serialize;
use std::time::Duration;
/// Create a styled progress bar, optionally with a known total length.
pub fn make_progress_bar(total: Option<u64>) -> ProgressBar {
let progress = match total {
Some(total) => ProgressBar::new(total),
None => ProgressBar::no_length(),
};
progress.set_style(
ProgressStyle::with_template(
"[{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} ({eta}) {msg}",
)
.unwrap()
.progress_chars("#>-"),
);
progress
}
/// Results from a single benchmark run.
#[derive(Clone, Copy, Serialize)]
pub struct BenchmarkResults {
pub offered_ops_throughput: f32,
pub ops_throughput: f32,
pub offered_block_throughput: f32,
pub block_throughput: f32,
pub latency_p99_us: f32,
}
#[derive(Clone, Copy)]
pub struct BenchmarkRun {
pub results: BenchmarkResults,
pub kept_up: bool,
}
/// Load, transform, and partition the mooncake trace into per-worker request lists.
pub fn process_mooncake_trace(
path: &str,
block_size: u32,
trace_length_factor: usize,
trace_duplication_factor: usize,
num_workers: usize,
seed: u64,
) -> anyhow::Result<Vec<Trace>> {
let trace = Trace::from_mooncake(std::path::Path::new(path), block_size as usize)?
.expand_hash_prefix_depth(trace_length_factor)
.duplicate_hash_space(trace_duplication_factor);
Ok(trace.partition_by_session(SessionPartitionSpec::Random {
num_partitions: num_workers,
seed,
}))
}
pub fn maybe_rescale_ready_span(
trace: Trace,
trace_simulation_duration_ms: Option<u64>,
) -> anyhow::Result<Trace> {
match trace_simulation_duration_ms {
Some(duration_ms) => trace.rescale_ready_span(duration_ms),
None => Ok(trace),
}
}
pub fn rescale_trace_timestamps<T, GetTimestamp, WithTimestamp>(
traces: &[Vec<T>],
benchmark_duration_ms: u64,
timestamp_of: GetTimestamp,
with_timestamp: WithTimestamp,
) -> Vec<Vec<T>>
where
GetTimestamp: Fn(&T) -> u64 + Copy,
WithTimestamp: Fn(&T, u64) -> T + Copy,
{
let target_us = u128::from(benchmark_duration_ms) * 1000;
traces
.iter()
.map(|worker_trace| {
if worker_trace.is_empty() {
return Vec::new();
}
let max_timestamp_us = worker_trace.last().map(timestamp_of).unwrap_or(1).max(1);
worker_trace
.iter()
.map(|entry| {
let scaled_timestamp =
u128::from(timestamp_of(entry)) * target_us / u128::from(max_timestamp_us);
with_timestamp(entry, scaled_timestamp.min(u128::from(u64::MAX)) as u64)
})
.collect()
})
.collect()
}
pub fn compute_benchmark_run(
total_ops: usize,
total_blocks: usize,
benchmark_duration_ms: u64,
total_duration: Duration,
mut latencies_ns: Vec<u64>,
) -> BenchmarkRun {
let kept_up = total_duration <= Duration::from_millis(benchmark_duration_ms * 11 / 10);
let benchmark_duration_secs = (benchmark_duration_ms as f32 / 1000.0).max(1e-6);
let total_duration_secs = total_duration.as_secs_f32().max(1e-6);
let offered_ops_throughput = total_ops as f32 / benchmark_duration_secs;
let ops_throughput = total_ops as f32 / total_duration_secs;
let offered_block_throughput = total_blocks as f32 / benchmark_duration_secs;
let block_throughput = total_blocks as f32 / total_duration_secs;
latencies_ns.sort_unstable();
let latency_p99_us = if latencies_ns.is_empty() {
0.0
} else {
let p99_idx = latencies_ns.len().saturating_sub(1) * 99 / 100;
latencies_ns[p99_idx] as f32 / 1000.0
};
BenchmarkRun {
results: BenchmarkResults {
offered_ops_throughput,
ops_throughput,
offered_block_throughput,
block_throughput,
latency_p99_us,
},
kept_up,
}
}
/// Build default MockEngineArgs suitable for event generation.
pub fn default_mock_engine_args(
num_gpu_blocks: usize,
block_size: usize,
) -> anyhow::Result<MockEngineArgs> {
Ok(MockEngineArgs::builder()
.num_gpu_blocks(num_gpu_blocks)
.block_size(block_size)
.speedup_ratio(10.0)
.enable_prefix_caching(true)
.max_num_batched_tokens(None)
.max_num_seqs(None)
.build()?)
}
fn replay_worker_trace(
trace: Trace,
sched_args: MockEngineArgs,
trace_simulation_duration_ms: Option<u64>,
progress: ProgressBar,
) -> anyhow::Result<WorkerReplayArtifacts> {
let total_turns = trace
.sessions
.iter()
.map(|session| session.turns.len())
.sum::<usize>();
let artifacts = dynamo_mocker::replay::generate_trace_worker_artifacts_offline(
sched_args,
maybe_rescale_ready_span(trace, trace_simulation_duration_ms)?,
)?;
progress.inc(total_turns as u64);
Ok(artifacts)
}
pub async fn generate_replay_artifacts(
traces: &[Trace],
num_gpu_blocks: usize,
block_size: u32,
trace_simulation_duration_ms: Option<u64>,
) -> anyhow::Result<Vec<WorkerReplayArtifacts>> {
println!("Generating events...");
let sched_args = default_mock_engine_args(num_gpu_blocks, block_size as usize)?;
let progress = make_progress_bar(Some(
traces
.iter()
.map(|trace| {
trace
.sessions
.iter()
.map(|session| session.turns.len() as u64)
.sum::<u64>()
})
.sum::<u64>(),
));
let mut tasks = Vec::new();
for trace in traces.iter().cloned() {
let sched_args = sched_args.clone();
let progress = progress.clone();
tasks.push(tokio::task::spawn_blocking(move || {
replay_worker_trace(trace, sched_args, trace_simulation_duration_ms, progress)
}));
}
let mut artifacts = Vec::new();
for task in tasks {
artifacts.push(task.await??);
}
for (worker_idx, worker_events) in artifacts
.iter()
.enumerate()
.map(|(worker_idx, artifact)| (worker_idx, &artifact.kv_events))
{
for i in 1..worker_events.len() {
assert!(
worker_events[i].timestamp_us >= worker_events[i - 1].timestamp_us,
"worker {worker_idx} non-monotonic kv_events at idx {i}: prev={}, curr={}",
worker_events[i - 1].timestamp_us,
worker_events[i].timestamp_us
);
}
}
println!(
"Generated {} events. Processing...",
artifacts
.iter()
.map(|artifact| artifact.kv_events.len())
.sum::<usize>()
);
let mut num_stored_events = 0;
let mut num_removed_events = 0;
for event in artifacts
.iter()
.flat_map(|artifact| artifact.kv_events.iter())
{
match event.event.data {
KvCacheEventData::Stored(_) => num_stored_events += 1,
KvCacheEventData::Removed(_) => num_removed_events += 1,
_ => (),
}
}
println!("Store events: {}", num_stored_events);
println!("Remove events: {}", num_removed_events);
Ok(artifacts)
}
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//! Combined benchmark for KvIndexer, PositionalIndexer (nested), and ConcurrentRadixTree.
//!
//! Provides two modes:
//! - `microbench`: Per-operation latency benchmarks comparing indexer implementations
//! - `stress`: Queue saturation stress test under load
//!
//! Supported indexer types: single, nested, concurrent, all
//!
//! Run with:
//! cargo bench --package dynamo-bench --bench kv_indexer_bench -- microbench --help
//! cargo bench --package dynamo-bench --bench kv_indexer_bench -- stress --help
#[path = "common/mod.rs"]
mod common;
use common::{SequenceData, generate_sequences};
use clap::{Args, Parser, Subcommand, ValueEnum};
use dynamo_bench::common::LatencyStats;
use dynamo_kv_router::{
ConcurrentRadixTree,
indexer::{KvIndexer, KvIndexerInterface, KvIndexerMetrics, ThreadPoolIndexer},
nested_map::PositionalIndexer,
protocols::{LocalBlockHash, RouterEvent},
};
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
use tokio::time::interval;
use tokio_util::sync::CancellationToken;
// ============================================================================
// CLI Definitions
// ============================================================================
#[derive(Parser)]
#[command(name = "kv_indexer_bench")]
#[command(about = "Combined benchmark for KvIndexer, PositionalIndexer, and ConcurrentRadixTree")]
struct Cli {
#[command(subcommand)]
command: Command,
/// Ignored - passed by cargo bench harness
#[arg(long, hide = true, global = true)]
bench: bool,
}
#[derive(Subcommand)]
enum Command {
/// Per-operation latency benchmarks comparing indexer implementations
Microbench(MicrobenchArgs),
/// Queue saturation stress test under load
Stress(StressArgs),
}
/// Indexer type to benchmark
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
enum IndexerType {
/// Non-sharded KvIndexer (single background thread)
Single,
/// Nested PositionalIndexer (position-based HashMap with jump search)
Nested,
/// Concurrent radix tree (lock-per-node with DashMap lookup)
Concurrent,
/// Run all indexer types and compare
All,
}
/// Common arguments shared between subcommands
#[derive(Args, Debug, Clone)]
struct CommonArgs {
/// Target tree size in total (worker, block) pairs
#[arg(long, default_value = "100000")]
size: usize,
/// Sequence depth in blocks (blocks per sequence)
#[arg(long, default_value = "64")]
depth: usize,
/// Number of workers to distribute blocks across
#[arg(long, default_value = "4")]
num_workers: usize,
/// KV block size in tokens
#[arg(long, default_value = "16")]
block_size: u32,
/// Random seed for reproducibility
#[arg(long, default_value = "42")]
seed: u64,
/// Verbose output
#[arg(short, long)]
verbose: bool,
}
#[derive(Args, Debug)]
struct MicrobenchArgs {
#[command(flatten)]
common: CommonArgs,
/// Number of iterations per operation for timing
#[arg(long, default_value = "1000")]
iterations: usize,
/// Prefix prompt ratio (0.0 to 1.0)
#[arg(long, default_value = "0.25")]
prefix_prompt_ratio: f64,
/// Number of unique prefix prompt groups
#[arg(long, default_value = "4")]
num_prefix_prompts: usize,
/// Indexer type to benchmark
#[arg(long, value_enum, default_value = "all")]
indexer_type: IndexerType,
/// Number of event worker threads for nested/concurrent indexers
#[arg(long, default_value = "4")]
num_event_workers: usize,
/// Jump size for nested/positional indexer
#[arg(long, default_value = "32")]
jump_size: usize,
/// Run only specific benchmark (store, find_matches, remove, or all)
#[arg(long, default_value = "all")]
benchmark_type: String,
/// Output format: "table" or "csv"
#[arg(long, default_value = "table")]
format: String,
}
#[derive(Args, Debug)]
struct StressArgs {
#[command(flatten)]
common: CommonArgs,
/// Prefix sharing ratio (0.0 to 1.0) - fraction of sequences sharing a common prefix
#[arg(long, default_value = "0.5")]
prefix_share_ratio: f64,
/// Requests per second to submit
#[arg(long, default_value = "20.0")]
arrival_rate: f64,
/// Test duration in seconds
#[arg(long, default_value = "10")]
duration: u64,
/// Seconds to wait for in-flight requests after test
#[arg(long, default_value = "5")]
in_flight_timeout: u64,
/// Indexer type to stress test
#[arg(long, value_enum, default_value = "single")]
indexer_type: IndexerType,
/// Number of event worker threads for nested/concurrent indexers
#[arg(long, default_value = "4")]
num_event_workers: usize,
/// Jump size for nested/positional indexer
#[arg(long, default_value = "32")]
jump_size: usize,
}
// ============================================================================
// Benchable Indexer Trait
// ============================================================================
/// Trait for abstracting over benchmarked indexers
#[async_trait::async_trait]
trait BenchableIndexer: Send + Sync {
async fn apply_event(&mut self, event: RouterEvent);
async fn find_matches(
&self,
sequence: Vec<LocalBlockHash>,
) -> Result<(), dynamo_kv_router::indexer::KvRouterError>;
fn name(&self) -> &str;
}
#[async_trait::async_trait]
impl BenchableIndexer for KvIndexer {
async fn apply_event(&mut self, event: RouterEvent) {
KvIndexerInterface::apply_event(self, event).await;
}
async fn find_matches(
&self,
sequence: Vec<LocalBlockHash>,
) -> Result<(), dynamo_kv_router::indexer::KvRouterError> {
KvIndexerInterface::find_matches(self, sequence).await?;
Ok(())
}
fn name(&self) -> &str {
"KvIndexer (single)"
}
}
#[async_trait::async_trait]
impl BenchableIndexer for ThreadPoolIndexer<PositionalIndexer> {
async fn apply_event(&mut self, event: RouterEvent) {
KvIndexerInterface::apply_event(self, event).await;
}
async fn find_matches(
&self,
sequence: Vec<LocalBlockHash>,
) -> Result<(), dynamo_kv_router::indexer::KvRouterError> {
KvIndexerInterface::find_matches(self, sequence).await?;
Ok(())
}
fn name(&self) -> &str {
"PositionalIndexer (nested)"
}
}
#[async_trait::async_trait]
impl BenchableIndexer for ThreadPoolIndexer<ConcurrentRadixTree> {
async fn apply_event(&mut self, event: RouterEvent) {
KvIndexerInterface::apply_event(self, event).await;
}
async fn find_matches(
&self,
sequence: Vec<LocalBlockHash>,
) -> Result<(), dynamo_kv_router::indexer::KvRouterError> {
KvIndexerInterface::find_matches(self, sequence).await?;
Ok(())
}
fn name(&self) -> &str {
"ConcurrentRadixTree"
}
}
// ============================================================================
// Microbench Mode
// ============================================================================
/// Results for a single indexer benchmark
#[derive(Debug)]
struct MicrobenchResults {
indexer_name: String,
construction_time: Duration,
construction_events: usize,
store_stats: Option<LatencyStats>,
find_matches_hit_stats: Option<LatencyStats>,
find_matches_miss_stats: Option<LatencyStats>,
remove_stats: Option<LatencyStats>,
}
impl MicrobenchResults {
fn print(&self, depth: usize) {
println!("\n========================================");
println!("Results for: {}", self.indexer_name);
println!("========================================");
println!("\nConstruction:");
println!(" Time: {:?}", self.construction_time);
println!(" Events: {}", self.construction_events);
println!(
" Throughput: {:.0} events/sec",
self.construction_events as f64 / self.construction_time.as_secs_f64()
);
if let Some(ref stats) = self.store_stats {
stats.print("APPLY_EVENT (store)", depth);
}
if let Some(ref stats) = self.find_matches_hit_stats {
stats.print("FIND_MATCHES (hit)", depth);
}
if let Some(ref stats) = self.find_matches_miss_stats {
stats.print("FIND_MATCHES (miss)", depth);
}
if let Some(ref stats) = self.remove_stats {
stats.print("APPLY_EVENT (remove)", depth);
}
}
fn print_csv_header() {
println!(
"indexer,construction_ms,construction_events,construction_throughput,\
store_avg_us,store_p50_us,store_p99_us,store_throughput,\
find_hit_avg_us,find_hit_p50_us,find_hit_p99_us,find_hit_throughput,\
find_miss_avg_us,find_miss_p50_us,find_miss_p99_us,find_miss_throughput,\
remove_avg_us,remove_p50_us,remove_p99_us,remove_throughput"
);
}
fn print_csv_row(&self) {
let construction_throughput =
self.construction_events as f64 / self.construction_time.as_secs_f64();
let store = self.store_stats.as_ref();
let find_hit = self.find_matches_hit_stats.as_ref();
let find_miss = self.find_matches_miss_stats.as_ref();
let remove = self.remove_stats.as_ref();
println!(
"{},{:.3},{},{:.0},{},{},{},{:.0},{},{},{},{:.0},{},{},{},{:.0},{},{},{},{:.0}",
self.indexer_name,
self.construction_time.as_secs_f64() * 1000.0,
self.construction_events,
construction_throughput,
store.map(|s| s.avg.as_micros()).unwrap_or(0),
store.map(|s| s.p50.as_micros()).unwrap_or(0),
store.map(|s| s.p99.as_micros()).unwrap_or(0),
store.map(|s| s.throughput_ops_sec).unwrap_or(0.0),
find_hit.map(|s| s.avg.as_micros()).unwrap_or(0),
find_hit.map(|s| s.p50.as_micros()).unwrap_or(0),
find_hit.map(|s| s.p99.as_micros()).unwrap_or(0),
find_hit.map(|s| s.throughput_ops_sec).unwrap_or(0.0),
find_miss.map(|s| s.avg.as_micros()).unwrap_or(0),
find_miss.map(|s| s.p50.as_micros()).unwrap_or(0),
find_miss.map(|s| s.p99.as_micros()).unwrap_or(0),
find_miss.map(|s| s.throughput_ops_sec).unwrap_or(0.0),
remove.map(|s| s.avg.as_micros()).unwrap_or(0),
remove.map(|s| s.p50.as_micros()).unwrap_or(0),
remove.map(|s| s.p99.as_micros()).unwrap_or(0),
remove.map(|s| s.throughput_ops_sec).unwrap_or(0.0),
);
}
}
/// Build a pre-populated indexer
async fn build_indexer<I: BenchableIndexer>(
indexer: &mut I,
sequences: &[SequenceData],
verbose: bool,
) -> Duration {
let num_blocks: usize = sequences.iter().map(|s| s.local_hashes.len()).sum();
print!(
" Building {} with {} sequences ({} blocks)... ",
indexer.name(),
sequences.len(),
num_blocks
);
std::io::Write::flush(&mut std::io::stdout()).unwrap();
let start = Instant::now();
for (event_id, seq) in sequences.iter().enumerate() {
let event = seq.to_store_event(event_id as u64);
indexer.apply_event(event).await;
if verbose && (event_id + 1) % 1000 == 0 {
print!(".");
std::io::Write::flush(&mut std::io::stdout()).unwrap();
}
}
let elapsed = start.elapsed();
// Allow background processing to complete
tokio::time::sleep(Duration::from_millis(50)).await;
println!(
"done in {:.2?} ({:.2} events/sec)",
elapsed,
sequences.len() as f64 / elapsed.as_secs_f64()
);
elapsed
}
/// Benchmark apply_event (store) operation
async fn bench_store<I: BenchableIndexer>(
indexer: &mut I,
extra_sequences: &[SequenceData],
iterations: usize,
verbose: bool,
) -> LatencyStats {
println!("\n Benchmarking APPLY_EVENT (store)...");
let mut durations = Vec::with_capacity(iterations);
for (i, seq) in extra_sequences.iter().enumerate().take(iterations) {
let event = seq.to_store_event((1_000_000 + i) as u64);
let start = Instant::now();
indexer.apply_event(event).await;
durations.push(start.elapsed());
// Remove to restore state (untimed)
let remove_event = seq.to_remove_event((2_000_000 + i) as u64);
indexer.apply_event(remove_event).await;
if verbose && (i + 1) % 100 == 0 {
println!(" Completed {}/{} iterations", i + 1, iterations);
}
}
LatencyStats::from_durations(&durations).unwrap()
}
/// Benchmark find_matches operation (hit case)
async fn bench_find_matches_hit<I: BenchableIndexer>(
indexer: &I,
sequences: &[SequenceData],
iterations: usize,
verbose: bool,
) -> LatencyStats {
println!("\n Benchmarking FIND_MATCHES (hit)...");
let mut durations = Vec::with_capacity(iterations);
for i in 0..iterations {
let seq = &sequences[i % sequences.len()];
let hashes = seq.local_hashes.clone();
let start = Instant::now();
let _ = indexer.find_matches(hashes).await;
durations.push(start.elapsed());
if verbose && (i + 1) % 100 == 0 {
println!(" Completed {}/{} iterations", i + 1, iterations);
}
}
LatencyStats::from_durations(&durations).unwrap()
}
/// Benchmark find_matches operation (miss case)
async fn bench_find_matches_miss<I: BenchableIndexer>(
indexer: &I,
depth: usize,
iterations: usize,
verbose: bool,
) -> LatencyStats {
println!("\n Benchmarking FIND_MATCHES (miss)...");
let mut durations = Vec::with_capacity(iterations);
for i in 0..iterations {
let miss_hashes: Vec<LocalBlockHash> = (0..depth)
.map(|j| LocalBlockHash(0xBAD_C0DE_0000_0000 | ((i as u64) << 16) | (j as u64)))
.collect();
let start = Instant::now();
let _ = indexer.find_matches(miss_hashes).await;
durations.push(start.elapsed());
if verbose && (i + 1) % 100 == 0 {
println!(" Completed {}/{} iterations", i + 1, iterations);
}
}
LatencyStats::from_durations(&durations).unwrap()
}
/// Benchmark apply_event (remove) operation
async fn bench_remove<I: BenchableIndexer>(
indexer: &mut I,
sequences: &[SequenceData],
iterations: usize,
verbose: bool,
) -> LatencyStats {
println!("\n Benchmarking APPLY_EVENT (remove)...");
let mut durations = Vec::with_capacity(iterations);
for i in 0..iterations {
let seq = &sequences[i % sequences.len()];
let remove_event = seq.to_remove_event((3_000_000 + i) as u64);
let start = Instant::now();
indexer.apply_event(remove_event).await;
durations.push(start.elapsed());
// Re-add to restore state (untimed)
let store_event = seq.to_store_event((4_000_000 + i) as u64);
indexer.apply_event(store_event).await;
if verbose && (i + 1) % 100 == 0 {
println!(" Completed {}/{} iterations", i + 1, iterations);
}
}
LatencyStats::from_durations(&durations).unwrap()
}
/// Run all microbenchmarks for an indexer
async fn run_microbenchmarks<I: BenchableIndexer>(
indexer: &mut I,
sequences: &[SequenceData],
extra_sequences: &[SequenceData],
args: &MicrobenchArgs,
) -> MicrobenchResults {
let indexer_name = indexer.name().to_string();
println!("\n--- Benchmarking {} ---", indexer_name);
// Build the indexer
let construction_time = build_indexer(indexer, sequences, args.common.verbose).await;
let construction_events = sequences.len();
let run_all = args.benchmark_type == "all";
let store_stats = if run_all || args.benchmark_type == "store" {
Some(
bench_store(
indexer,
extra_sequences,
args.iterations,
args.common.verbose,
)
.await,
)
} else {
None
};
let find_matches_hit_stats = if run_all || args.benchmark_type == "find_matches" {
Some(bench_find_matches_hit(indexer, sequences, args.iterations, args.common.verbose).await)
} else {
None
};
let find_matches_miss_stats = if run_all || args.benchmark_type == "find_matches" {
Some(
bench_find_matches_miss(
indexer,
args.common.depth,
args.iterations,
args.common.verbose,
)
.await,
)
} else {
None
};
let remove_stats = if run_all || args.benchmark_type == "remove" {
Some(bench_remove(indexer, sequences, args.iterations, args.common.verbose).await)
} else {
None
};
MicrobenchResults {
indexer_name,
construction_time,
construction_events,
store_stats,
find_matches_hit_stats,
find_matches_miss_stats,
remove_stats,
}
}
fn print_microbench_comparison(results: &[MicrobenchResults], _depth: usize) {
if results.len() < 2 {
return;
}
println!("\n========================================");
println!("COMPARISON SUMMARY");
println!("========================================\n");
// Build dynamic column headers
let mut header = format!("{:<30}", "Metric");
for result in results {
header.push_str(&format!(
" {:>15}",
result
.indexer_name
.split_whitespace()
.next()
.unwrap_or(&result.indexer_name)
));
}
println!("{}", header);
println!("{}", "-".repeat(30 + results.len() * 16));
// Construction time
let mut row = format!("{:<30}", "Construction time (ms)");
for result in results {
row.push_str(&format!(
" {:>15.2}",
result.construction_time.as_secs_f64() * 1000.0
));
}
println!("{}", row);
// Store p50
let mut row = format!("{:<30}", "Store p50 (us)");
for result in results {
if let Some(stats) = &result.store_stats {
row.push_str(&format!(" {:>15.2}", stats.p50.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
// Find matches hit p50
let mut row = format!("{:<30}", "Find hit p50 (us)");
for result in results {
if let Some(stats) = &result.find_matches_hit_stats {
row.push_str(&format!(" {:>15.2}", stats.p50.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
// Find matches hit p99
let mut row = format!("{:<30}", "Find hit p99 (us)");
for result in results {
if let Some(stats) = &result.find_matches_hit_stats {
row.push_str(&format!(" {:>15.2}", stats.p99.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
// Find matches miss p50
let mut row = format!("{:<30}", "Find miss p50 (us)");
for result in results {
if let Some(stats) = &result.find_matches_miss_stats {
row.push_str(&format!(" {:>15.2}", stats.p50.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
// Remove p50
let mut row = format!("{:<30}", "Remove p50 (us)");
for result in results {
if let Some(stats) = &result.remove_stats {
row.push_str(&format!(" {:>15.2}", stats.p50.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
// Throughput
println!();
let mut header = format!("{:<30}", "Throughput (ops/sec)");
for result in results {
header.push_str(&format!(
" {:>15}",
result
.indexer_name
.split_whitespace()
.next()
.unwrap_or(&result.indexer_name)
));
}
println!("{}", header);
println!("{}", "-".repeat(30 + results.len() * 16));
let mut row = format!("{:<30}", "Find matches (hit)");
for result in results {
if let Some(stats) = &result.find_matches_hit_stats {
row.push_str(&format!(" {:>15.0}", stats.throughput_ops_sec));
} else {
row.push_str(&format!(" {:>15}", "-"));
}
}
println!("{}", row);
}
async fn run_microbench_mode(args: MicrobenchArgs) {
let num_sequences = args.common.size / args.common.depth;
if num_sequences == 0 {
eprintln!("Error: size must be >= depth");
std::process::exit(1);
}
if matches!(
args.indexer_type,
IndexerType::Nested | IndexerType::Concurrent | IndexerType::All
) && args.num_event_workers == 0
{
eprintln!(
"Error: num_event_workers must be > 0 when using Nested, Concurrent, or All indexer type"
);
std::process::exit(1);
}
println!("KvIndexer Microbenchmark");
println!("========================\n");
println!("Configuration:");
println!(" Target size: {} (worker, block) pairs", args.common.size);
println!(
" Depth: {} blocks/sequence (= {} tokens with block_size={})",
args.common.depth,
args.common.depth * args.common.block_size as usize,
args.common.block_size
);
println!(" Block size: {} tokens", args.common.block_size);
println!(" Workers: {}", args.common.num_workers);
println!(" Iterations: {}", args.iterations);
println!(
" Prefix prompt ratio: {:.1}%",
args.prefix_prompt_ratio * 100.0
);
println!(" Prefix prompt groups: {}", args.num_prefix_prompts);
println!(" Event worker threads: {}", args.num_event_workers);
println!(" Indexer type: {:?}", args.indexer_type);
println!(" Benchmark type: {}", args.benchmark_type);
println!(
"\n Derived: {} sequences to reach target size",
num_sequences
);
// Generate sequences
let extra_count = args.iterations;
let all_sequences = generate_sequences(
num_sequences + extra_count,
args.common.depth,
args.common.num_workers,
args.prefix_prompt_ratio,
args.num_prefix_prompts,
args.common.seed,
false,
);
let sequences = &all_sequences[..num_sequences];
let extra_sequences = &all_sequences[num_sequences..];
let metrics = Arc::new(KvIndexerMetrics::new_unregistered());
let mut results = Vec::new();
// Benchmark single indexer
if matches!(args.indexer_type, IndexerType::Single | IndexerType::All) {
let token = CancellationToken::new();
let mut indexer = KvIndexer::new(token.clone(), args.common.block_size, metrics.clone());
let result = run_microbenchmarks(&mut indexer, sequences, extra_sequences, &args).await;
results.push(result);
token.cancel();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Benchmark nested indexer
if matches!(args.indexer_type, IndexerType::Nested | IndexerType::All) {
let mut indexer = ThreadPoolIndexer::new(
PositionalIndexer::new(args.jump_size),
args.num_event_workers,
args.common.block_size,
);
let result = run_microbenchmarks(&mut indexer, sequences, extra_sequences, &args).await;
results.push(result);
indexer.shutdown();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Benchmark concurrent radix tree indexer
if matches!(
args.indexer_type,
IndexerType::Concurrent | IndexerType::All
) {
let mut indexer = ThreadPoolIndexer::new(
ConcurrentRadixTree::new(),
args.num_event_workers,
args.common.block_size,
);
let result = run_microbenchmarks(&mut indexer, sequences, extra_sequences, &args).await;
results.push(result);
indexer.shutdown();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Print results
if args.format == "csv" {
MicrobenchResults::print_csv_header();
for result in &results {
result.print_csv_row();
}
} else {
for result in &results {
result.print(args.common.depth);
}
if results.len() >= 2 {
print_microbench_comparison(&results, args.common.depth);
}
}
println!("\nMicrobenchmark complete.");
}
// ============================================================================
// Stress Test Mode
// ============================================================================
/// Result of a single request during stress test
#[expect(dead_code)]
struct RequestResult {
request_id: u64,
submit_time: Instant,
complete_time: Instant,
success: bool,
}
/// Aggregated results from stress test
struct StressResults {
indexer_name: String,
submitted: u64,
completed: u64,
timed_out: u64,
latencies: Vec<Duration>,
max_in_flight: u64,
baseline_service_time: Duration,
construction_time: Duration,
construction_events: u64,
}
/// Run the stress test with a generic indexer
async fn run_stress_test<I: BenchableIndexer + 'static>(
indexer: Arc<I>,
sequences: &[SequenceData],
args: &StressArgs,
) -> StressResults {
let indexer_name = indexer.name().to_string();
// Phase 2: Baseline Measurement
println!("\nPhase 2: Baseline Measurement");
println!(" Running 10 sequential find_matches calls...");
let mut baseline_durations = Vec::new();
for seq in sequences.iter().take(10) {
let start = Instant::now();
let _ = indexer.find_matches(seq.local_hashes.clone()).await;
baseline_durations.push(start.elapsed());
}
let stats = LatencyStats::from_durations(&baseline_durations).unwrap();
let baseline_service_time = stats.p50;
let theoretical_max = stats.throughput_ops_sec;
println!(
" Baseline find_matches latency: {:?} (p50 of 10)",
baseline_service_time
);
println!(
" Theoretical max throughput: {:.1} req/sec",
theoretical_max
);
// Phase 3: Pre-generate Lookup Sequences
println!("\nPhase 3: Pre-generating Lookup Sequences");
let expected_requests = (args.arrival_rate * args.duration as f64).ceil() as usize + 100;
// Phase 4: Stress Test
println!("\nPhase 4: Stress Test");
println!(" Arrival rate: {:.1} req/sec", args.arrival_rate);
println!(" Duration: {}s", args.duration);
let in_flight = Arc::new(AtomicU64::new(0));
let max_in_flight = Arc::new(AtomicU64::new(0));
let (result_tx, mut result_rx) = mpsc::channel::<RequestResult>(expected_requests);
let start = Instant::now();
let mut request_id = 0u64;
let mut interval = interval(Duration::from_secs_f64(1.0 / args.arrival_rate));
while start.elapsed() < Duration::from_secs(args.duration) {
let seq = sequences[request_id as usize % sequences.len()]
.local_hashes
.clone();
// Track in-flight
let current = in_flight.fetch_add(1, Ordering::Relaxed) + 1;
max_in_flight.fetch_max(current, Ordering::Relaxed);
let indexer = Arc::clone(&indexer);
let result_tx = result_tx.clone();
let in_flight_clone = in_flight.clone();
let req_id = request_id;
let verbose = args.common.verbose;
tokio::spawn(async move {
let submit_time = Instant::now();
let result = indexer.find_matches(seq).await;
let complete_time = Instant::now();
in_flight_clone.fetch_sub(1, Ordering::Relaxed);
if verbose {
let latency = complete_time.duration_since(submit_time);
println!(" Request {} completed in {:?}", req_id, latency);
}
let _ = result_tx
.send(RequestResult {
request_id: req_id,
submit_time,
complete_time,
success: result.is_ok(),
})
.await;
});
request_id += 1;
interval.tick().await;
}
let submitted = request_id;
println!(" Submitted {} requests", submitted);
// Wait for in-flight requests with timeout
println!("\nPhase 5: Draining In-flight Requests");
let drain_start = Instant::now();
let mut last_in_flight = in_flight.load(Ordering::Relaxed);
println!(
" Waiting for {} in-flight requests (timeout: {}s)...",
last_in_flight, args.in_flight_timeout
);
while in_flight.load(Ordering::Relaxed) > 0
&& drain_start.elapsed() < Duration::from_secs(args.in_flight_timeout)
{
tokio::time::sleep(Duration::from_millis(100)).await;
let current = in_flight.load(Ordering::Relaxed);
if current != last_in_flight && args.common.verbose {
println!(" In-flight: {}", current);
last_in_flight = current;
}
}
let timed_out = in_flight.load(Ordering::Relaxed);
if timed_out > 0 {
println!(" {} requests timed out", timed_out);
} else {
println!(" All requests completed");
}
// Collect results
drop(result_tx);
if timed_out > 0 {
result_rx.close();
}
let mut results = Vec::new();
while let Some(r) = result_rx.recv().await {
results.push(r);
}
// Compute latencies
let latencies: Vec<Duration> = results
.iter()
.map(|r| r.complete_time.duration_since(r.submit_time))
.collect();
StressResults {
indexer_name,
submitted,
completed: results.len() as u64,
timed_out,
latencies,
max_in_flight: max_in_flight.load(Ordering::Relaxed),
baseline_service_time,
construction_time: Duration::ZERO, // Set by caller
construction_events: 0, // Set by caller
}
}
/// Print the final stress test results report
fn print_stress_results(args: &StressArgs, results: &StressResults) {
let num_sequences = args.common.size / args.common.depth;
println!("\n=====================");
println!("Queue Saturation Test Results: {}", results.indexer_name);
println!("=====================\n");
println!("Configuration:");
println!(
" Tree size: {} blocks ({} sequences x {} depth)",
args.common.size, num_sequences, args.common.depth
);
println!(" Workers: {}", args.common.num_workers);
println!(
" Prefix share ratio: {:.1}%",
args.prefix_share_ratio * 100.0
);
println!(" Arrival rate: {:.1} req/sec", args.arrival_rate);
println!(" Duration: {}s", args.duration);
println!();
println!("Tree Construction:");
println!(" Time: {:.2?}", results.construction_time);
println!(" Events: {}", results.construction_events);
let throughput = results.construction_events as f64 / results.construction_time.as_secs_f64();
println!(" Throughput: {:.0} events/sec", throughput);
println!();
println!("Baseline:");
println!(
" find_matches latency: {:?} (median of 10)",
results.baseline_service_time
);
let theoretical_max = 1.0 / results.baseline_service_time.as_secs_f64();
println!(
" Theoretical max throughput: {:.1} req/sec",
theoretical_max
);
println!();
println!("Saturation Test Results:");
println!(" Submitted: {} requests", results.submitted);
println!(" Completed: {} requests", results.completed);
println!(
" Timed out: {} requests (in-flight at end)",
results.timed_out
);
println!();
if !results.latencies.is_empty() {
let test_duration = args.duration as f64 + args.in_flight_timeout as f64;
let achieved_throughput = results.completed as f64 / test_duration;
println!(" Throughput:");
println!(" Requested: {:.1} req/sec", args.arrival_rate);
println!(" Achieved: {:.1} req/sec", achieved_throughput);
println!();
if let Some(stats) = LatencyStats::from_durations(&results.latencies) {
println!(" Latency (end-to-end, includes queue wait):");
println!(" min: {:>12?}", stats.min);
println!(" p50: {:>12?}", stats.p50);
println!(" p95: {:>12?}", stats.p95);
println!(" p99: {:>12?}", stats.p99);
println!(" max: {:>12?}", stats.max);
println!();
let estimated_queue_wait = if stats.p50 > results.baseline_service_time {
stats.p50 - results.baseline_service_time
} else {
Duration::ZERO
};
println!(" Queue Analysis:");
println!(
" Baseline service time: {:?}",
results.baseline_service_time
);
println!(" Estimated queue wait (p50): {:?}", estimated_queue_wait);
println!(" Max in-flight observed: {}", results.max_in_flight);
println!();
// Determine saturation status
let is_saturated = achieved_throughput < args.arrival_rate * 0.95
|| results.timed_out > 0
|| stats.p50 > results.baseline_service_time * 2;
if is_saturated {
println!(" STATUS: SATURATED");
if achieved_throughput < args.arrival_rate * 0.95 {
println!(
" - Throughput ({:.1}) < Arrival rate ({:.1})",
achieved_throughput, args.arrival_rate
);
}
if results.timed_out > 0 {
println!(" - Requests timed out: {}", results.timed_out);
}
if stats.p50 > results.baseline_service_time * 2 {
println!(
" - P50 latency ({:?}) > 2x baseline ({:?})",
stats.p50, results.baseline_service_time
);
}
} else {
println!(" STATUS: NOT SATURATED");
println!(" - Throughput matches arrival rate");
println!(" - No requests timed out");
println!(" - Latency within acceptable bounds");
}
}
}
}
fn print_stress_comparison(results: &[StressResults], args: &StressArgs) {
if results.len() < 2 {
return;
}
println!("\n========================================");
println!("STRESS TEST COMPARISON SUMMARY");
println!("========================================\n");
// Build dynamic column headers
let mut header = format!("{:<35}", "Metric");
for result in results {
let short_name = result
.indexer_name
.split_whitespace()
.next()
.unwrap_or(&result.indexer_name);
header.push_str(&format!(" {:>18}", short_name));
}
println!("{}", header);
println!("{}", "-".repeat(35 + results.len() * 19));
// Construction time
let mut row = format!("{:<35}", "Construction time (ms)");
for result in results {
row.push_str(&format!(
" {:>18.2}",
result.construction_time.as_secs_f64() * 1000.0
));
}
println!("{}", row);
// Baseline service time
let mut row = format!("{:<35}", "Baseline service time (us)");
for result in results {
row.push_str(&format!(
" {:>18.2}",
result.baseline_service_time.as_nanos() as f64 / 1000.0
));
}
println!("{}", row);
// Completed requests
let mut row = format!("{:<35}", "Completed requests");
for result in results {
row.push_str(&format!(" {:>18}", result.completed));
}
println!("{}", row);
// Max in-flight
let mut row = format!("{:<35}", "Max in-flight");
for result in results {
row.push_str(&format!(" {:>18}", result.max_in_flight));
}
println!("{}", row);
// Timed out
let mut row = format!("{:<35}", "Timed out");
for result in results {
row.push_str(&format!(" {:>18}", result.timed_out));
}
println!("{}", row);
// Latency p50
let mut row = format!("{:<35}", "Latency p50 (us)");
for result in results {
if let Some(stats) = LatencyStats::from_durations(&result.latencies) {
row.push_str(&format!(" {:>18.2}", stats.p50.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>18}", "-"));
}
}
println!("{}", row);
// Latency p99
let mut row = format!("{:<35}", "Latency p99 (us)");
for result in results {
if let Some(stats) = LatencyStats::from_durations(&result.latencies) {
row.push_str(&format!(" {:>18.2}", stats.p99.as_nanos() as f64 / 1000.0));
} else {
row.push_str(&format!(" {:>18}", "-"));
}
}
println!("{}", row);
// Achieved throughput
let test_duration = args.duration as f64 + args.in_flight_timeout as f64;
let mut row = format!("{:<35}", "Achieved throughput (req/s)");
for result in results {
let throughput = result.completed as f64 / test_duration;
row.push_str(&format!(" {:>18.1}", throughput));
}
println!("{}", row);
}
async fn run_stress_mode(args: StressArgs) {
// Validate inputs before proceeding
if args.common.depth == 0 {
eprintln!("Error: depth must be > 0");
std::process::exit(1);
}
if args.common.num_workers == 0 {
eprintln!("Error: num_workers must be > 0");
std::process::exit(1);
}
if args.common.size < args.common.depth {
eprintln!(
"Error: size ({}) must be >= depth ({})",
args.common.size, args.common.depth
);
std::process::exit(1);
}
if !(0.0..=1.0).contains(&args.prefix_share_ratio) {
eprintln!(
"Error: prefix_share_ratio ({}) must be in range 0.0..=1.0",
args.prefix_share_ratio
);
std::process::exit(1);
}
if args.arrival_rate <= 0.0 {
eprintln!("Error: arrival_rate must be > 0.0");
std::process::exit(1);
}
if matches!(
args.indexer_type,
IndexerType::Nested | IndexerType::Concurrent | IndexerType::All
) && args.num_event_workers == 0
{
eprintln!(
"Error: num_event_workers must be > 0 when using Nested, Concurrent, or All indexer type"
);
std::process::exit(1);
}
let num_sequences = args.common.size / args.common.depth;
println!("Queue Saturation Stress Test");
println!("============================\n");
println!("Configuration:");
println!(
" Tree size: {} blocks ({} sequences x {} depth)",
args.common.size, num_sequences, args.common.depth
);
println!(" Workers: {}", args.common.num_workers);
println!(" Block size: {} tokens", args.common.block_size);
println!(
" Prefix share ratio: {:.1}%",
args.prefix_share_ratio * 100.0
);
println!(" Seed: {}", args.common.seed);
println!(" Arrival rate: {:.1} req/sec", args.arrival_rate);
println!(" Duration: {}s", args.duration);
println!(" In-flight timeout: {}s", args.in_flight_timeout);
println!(" Indexer type: {:?}", args.indexer_type);
if matches!(
args.indexer_type,
IndexerType::Nested | IndexerType::Concurrent | IndexerType::All
) {
println!(" Event worker threads: {}", args.num_event_workers);
}
if matches!(args.indexer_type, IndexerType::Nested | IndexerType::All) {
println!(" Jump size (nested): {}", args.jump_size);
}
// Generate sequences
println!("\nPhase 1: Tree Construction");
println!(" Generating {} sequences...", num_sequences);
// Use prefix_share_ratio as prefix_ratio and 1 group for stress test
let sequences = generate_sequences(
num_sequences,
args.common.depth,
args.common.num_workers,
args.prefix_share_ratio,
1, // Single prefix group for stress test
args.common.seed,
false, // use_cumulative_hash
);
let metrics = Arc::new(KvIndexerMetrics::new_unregistered());
let mut all_results = Vec::new();
// Test single indexer
if matches!(args.indexer_type, IndexerType::Single | IndexerType::All) {
let token = CancellationToken::new();
let indexer = KvIndexer::new(token.clone(), args.common.block_size, metrics.clone());
println!(
"\n Applying {} store events to KvIndexer...",
sequences.len()
);
let construction_start = Instant::now();
for (event_id, seq) in sequences.iter().enumerate() {
let event = seq.to_store_event(event_id as u64);
KvIndexerInterface::apply_event(&indexer, event).await;
if args.common.verbose && (event_id + 1) % 100 == 0 {
println!(" Applied {}/{} events...", event_id + 1, sequences.len());
}
}
let construction_time = construction_start.elapsed();
let construction_events = sequences.len() as u64;
println!(" Tree construction completed in {:?}", construction_time);
println!(
" Throughput: {:.0} events/sec",
construction_events as f64 / construction_time.as_secs_f64()
);
tokio::time::sleep(Duration::from_millis(100)).await;
let mut results = run_stress_test(Arc::new(indexer), &sequences, &args).await;
results.construction_time = construction_time;
results.construction_events = construction_events;
print_stress_results(&args, &results);
all_results.push(results);
token.cancel();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Test nested indexer
if matches!(args.indexer_type, IndexerType::Nested | IndexerType::All) {
let indexer = ThreadPoolIndexer::new(
PositionalIndexer::new(args.jump_size),
args.num_event_workers,
args.common.block_size,
);
println!(
"\n Applying {} store events to PositionalIndexer...",
sequences.len()
);
let construction_start = Instant::now();
for (event_id, seq) in sequences.iter().enumerate() {
let event = seq.to_store_event(event_id as u64);
indexer.apply_event(event).await;
if args.common.verbose && (event_id + 1) % 100 == 0 {
println!(" Applied {}/{} events...", event_id + 1, sequences.len());
}
}
indexer.flush().await;
let construction_time = construction_start.elapsed();
let construction_events = sequences.len() as u64;
println!(" Tree construction completed in {:?}", construction_time);
println!(
" Throughput: {:.0} events/sec",
construction_events as f64 / construction_time.as_secs_f64()
);
tokio::time::sleep(Duration::from_millis(100)).await;
let indexer = Arc::new(indexer);
let mut results = run_stress_test(indexer.clone(), &sequences, &args).await;
results.construction_time = construction_time;
results.construction_events = construction_events;
print_stress_results(&args, &results);
all_results.push(results);
indexer.shutdown();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Test concurrent radix tree indexer
if matches!(
args.indexer_type,
IndexerType::Concurrent | IndexerType::All
) {
let indexer = ThreadPoolIndexer::new(
ConcurrentRadixTree::new(),
args.num_event_workers,
args.common.block_size,
);
println!(
"\n Applying {} store events to ConcurrentRadixTree...",
sequences.len()
);
let construction_start = Instant::now();
for (event_id, seq) in sequences.iter().enumerate() {
let event = seq.to_store_event(event_id as u64);
indexer.apply_event(event).await;
if args.common.verbose && (event_id + 1) % 100 == 0 {
println!(" Applied {}/{} events...", event_id + 1, sequences.len());
}
}
indexer.flush().await;
let construction_time = construction_start.elapsed();
let construction_events = sequences.len() as u64;
println!(" Tree construction completed in {:?}", construction_time);
println!(
" Throughput: {:.0} events/sec",
construction_events as f64 / construction_time.as_secs_f64()
);
tokio::time::sleep(Duration::from_millis(100)).await;
let indexer = Arc::new(indexer);
let mut results = run_stress_test(indexer.clone(), &sequences, &args).await;
results.construction_time = construction_time;
results.construction_events = construction_events;
print_stress_results(&args, &results);
all_results.push(results);
indexer.shutdown();
tokio::time::sleep(Duration::from_millis(50)).await;
}
// Print comparison if multiple were run
if all_results.len() >= 2 {
print_stress_comparison(&all_results, &args);
}
println!("\nStress test complete.");
}
// ============================================================================
// Main Entry Point
// ============================================================================
#[tokio::main]
async fn main() {
let cli = match Cli::try_parse() {
Ok(cli) => cli,
Err(_) => {
eprintln!("No valid arguments provided, skipping benchmark");
return;
}
};
match cli.command {
Command::Microbench(args) => run_microbench_mode(args).await,
Command::Stress(args) => run_stress_mode(args).await,
}
}
......@@ -5,22 +5,14 @@
mod common;
use common::*;
#[path = "mooncake_shared.rs"]
mod mooncake_shared;
use clap::{Parser, Subcommand};
use dynamo_kv_router::LocalBlockHash;
use dynamo_kv_router::indexer::{
KvIndexer, KvIndexerInterface, KvIndexerMetrics, ShardSizeSnapshot,
};
use dynamo_kv_router::protocols::{KvCacheEvent, KvCacheEventData, RouterEvent};
use dynamo_kv_router::{
BranchShardedIndexer, ConcurrentRadixTree, ConcurrentRadixTreeCompressed, PositionalIndexer,
ThreadPoolIndexer,
};
use dynamo_mocker::loadgen::Trace;
use dynamo_kv_router::indexer::{KvIndexerInterface, KvIndexerMetrics, ShardSizeSnapshot};
use mooncake_shared::{MooncakeBenchmarkConfig, MooncakeIndexerConfig, run_benchmark};
use serde::Serialize;
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use std::sync::Arc;
use tokio::time::{Duration, Instant};
use tokio_util::sync::CancellationToken;
......@@ -82,103 +74,30 @@ enum IndexerArgs {
}
impl IndexerArgs {
/// Construct the concrete indexer from the parsed CLI args.
fn build(self, block_size: u32) -> Arc<dyn KvIndexerInterface + Send + Sync> {
let cancel_token = CancellationToken::new();
let metrics = Arc::new(KvIndexerMetrics::new_unregistered());
fn to_config(&self) -> MooncakeIndexerConfig {
match self {
IndexerArgs::RadixTree {} => {
Arc::new(KvIndexer::new(cancel_token, block_size, metrics))
}
IndexerArgs::RadixTree {} => MooncakeIndexerConfig::radix_tree(),
IndexerArgs::NestedMap {
jump_size,
num_event_workers,
} => Arc::new(ThreadPoolIndexer::new(
PositionalIndexer::new(jump_size),
num_event_workers,
block_size,
)),
IndexerArgs::ConcurrentRadixTree { num_event_workers } => Arc::new(
ThreadPoolIndexer::new(ConcurrentRadixTree::new(), num_event_workers, block_size),
),
} => MooncakeIndexerConfig::nested_map(*jump_size, *num_event_workers),
IndexerArgs::ConcurrentRadixTree { num_event_workers } => {
MooncakeIndexerConfig::concurrent_radix_tree(*num_event_workers)
}
IndexerArgs::ConcurrentRadixTreeCompressed { num_event_workers } => {
Arc::new(ThreadPoolIndexer::new(
ConcurrentRadixTreeCompressed::new(),
num_event_workers,
block_size,
))
MooncakeIndexerConfig::concurrent_radix_tree_compressed(*num_event_workers)
}
IndexerArgs::BranchShardedCrtc {
num_shards,
num_event_workers_per_shard,
prefix_depth,
num_read_threads_per_shard: _,
} => {
let shards = (0..num_shards)
.map(|_| {
ThreadPoolIndexer::new(
ConcurrentRadixTreeCompressed::new(),
num_event_workers_per_shard,
block_size,
)
})
.collect();
Arc::new(BranchShardedIndexer::new_with_options(
shards,
prefix_depth,
block_size,
))
}
}
}
fn supports_remove(_name: &str) -> bool {
true
}
fn is_multi_threaded(name: &str) -> bool {
matches!(
name,
"nested-map"
| "concurrent-radix-tree"
| "concurrent-radix-tree-compressed"
| "branch-sharded-crtc"
)
}
/// Construct an indexer from a short name string.
fn from_name(
name: &str,
block_size: u32,
num_event_workers: usize,
) -> anyhow::Result<Arc<dyn KvIndexerInterface + Send + Sync>> {
let nw = num_event_workers;
let indexer_args = match name {
"radix-tree" => IndexerArgs::RadixTree {},
"nested-map" => IndexerArgs::NestedMap {
jump_size: 8,
num_event_workers: nw,
},
"concurrent-radix-tree" => IndexerArgs::ConcurrentRadixTree {
num_event_workers: nw,
},
"concurrent-radix-tree-compressed" => IndexerArgs::ConcurrentRadixTreeCompressed {
num_event_workers: nw,
},
"branch-sharded-crtc" => IndexerArgs::BranchShardedCrtc {
num_shards: 2,
num_event_workers_per_shard: nw,
prefix_depth: 2,
num_read_threads_per_shard: 0,
},
_ => anyhow::bail!(
"Unknown indexer '{}'. Valid names: radix-tree, radix-tree-sharded, \
nested-map, concurrent-radix-tree, concurrent-radix-tree-compressed, \
branch-sharded-crtc",
name
} => MooncakeIndexerConfig::branch_sharded_crtc(
*num_shards,
*num_event_workers_per_shard,
*prefix_depth,
),
};
Ok(indexer_args.build(block_size))
}
}
}
......@@ -235,62 +154,6 @@ impl Args {
}
}
/// A single entry in a worker's merged benchmark timeline.
#[derive(Clone)]
enum WorkerTraceEntry {
/// A find_matches request with pre-computed block hashes.
Request(Vec<LocalBlockHash>),
/// A KV cache event (store/remove/clear) to apply to the indexer.
Event(KvCacheEvent),
}
/// A timestamped entry in a worker's benchmark trace, used to replay requests
/// and events at the correct relative timing.
#[derive(Clone)]
struct WorkerTrace {
entry: WorkerTraceEntry,
timestamp_us: u64,
}
/// Merge each worker's request trace and event trace into a single
/// time-ordered sequence of `WorkerTrace` entries suitable for benchmark
/// replay.
///
/// Timestamps are rescaled from the original trace / simulation durations
/// into the benchmark duration (microseconds).
fn prepare_worker_traces(
artifacts: Vec<WorkerReplayArtifacts>,
benchmark_duration_ms: u64,
) -> Vec<Vec<WorkerTrace>> {
artifacts
.into_iter()
.map(|artifact| {
let mut merged = artifact
.requests
.into_iter()
.map(|request| WorkerTrace {
timestamp_us: request.timestamp_us,
entry: WorkerTraceEntry::Request(request.replay_hashes.local_block_hashes),
})
.chain(artifact.kv_events.into_iter().map(|event| WorkerTrace {
timestamp_us: event.timestamp_us,
entry: WorkerTraceEntry::Event(event.event),
}))
.collect::<Vec<_>>();
merged.sort_by_key(|entry| entry.timestamp_us);
let max_timestamp_us = merged.last().map(|entry| entry.timestamp_us).unwrap_or(0);
for entry in &mut merged {
entry.timestamp_us = if max_timestamp_us == 0 {
0
} else {
entry.timestamp_us * benchmark_duration_ms * 1000 / max_timestamp_us
};
}
merged
})
.collect()
}
#[derive(Serialize)]
struct SweepStepResult {
duration_ms: u64,
......@@ -485,349 +348,14 @@ fn plot_shard_metrics(rows: &[ShardSampleRow], svg_path: &str) -> anyhow::Result
Ok(())
}
/// Run the benchmark: replay each worker's merged trace against the indexer,
/// measuring find_matches latency and event processing throughput.
///
/// Workers are spawned as tokio tasks, each replaying its trace at the
/// original inter-entry timing. After all workers finish, the event queue is
/// flushed and latency percentiles / throughput stats are printed.
async fn run_benchmark(
indexer: Arc<dyn KvIndexerInterface + Send + Sync>,
artifacts: Vec<WorkerReplayArtifacts>,
args: &Args,
benchmark_duration_ms: u64,
count_events: bool,
find_matches_concurrency: usize,
) -> anyhow::Result<BenchmarkResults> {
let worker_traces = prepare_worker_traces(artifacts, benchmark_duration_ms);
let worker_traces = worker_traces.into_iter().map(Arc::new).collect::<Vec<_>>();
let progress = make_progress_bar(Some(
worker_traces
.iter()
.map(|trace| trace.len() as u64)
.sum::<u64>()
* args.common.inference_worker_duplication_factor as u64,
));
let mut tasks = Vec::new();
for replica in 0..args.common.inference_worker_duplication_factor {
for (worker_id, worker_trace) in worker_traces.iter().enumerate() {
let indexer = indexer.clone();
let trace = worker_trace.clone();
let progress = progress.clone();
let worker_id = worker_id + replica * worker_traces.len();
tasks.push(tokio::spawn(async move {
let mut request_latencies = Vec::with_capacity(trace.len());
let submit = |entry: WorkerTrace| async {
match entry.entry {
WorkerTraceEntry::Request(request) => {
let start = minstant::Instant::now();
indexer.find_matches(request).await?;
Ok::<Option<u64>, anyhow::Error>(
Some(start.elapsed().as_nanos() as u64),
)
}
WorkerTraceEntry::Event(event) => {
indexer
.apply_event(RouterEvent::new(worker_id as u64, event))
.await;
Ok(None)
}
}
};
let mut target = Instant::now();
let mut trace = trace.iter().peekable();
let mut local_count = 0;
while let Some(entry) = trace.next() {
let mut processed = 1;
let entry_timestamp_us = entry.timestamp_us;
if let Some(latency) = submit(entry.clone()).await? {
request_latencies.push(latency);
}
while let Some(next) = trace.peek() {
if next.timestamp_us == entry_timestamp_us {
if let Some(latency) = submit(trace.next().unwrap().clone()).await? {
request_latencies.push(latency);
}
processed += 1;
} else {
break;
}
}
if let Some(next) = trace.peek() {
target += Duration::from_micros(next.timestamp_us - entry_timestamp_us);
}
if target > Instant::now() {
tokio::time::sleep_until(target).await;
}
local_count += processed;
if local_count > 100 {
progress.inc(local_count);
local_count = 0;
}
}
progress.inc(local_count);
Ok::<_, anyhow::Error>(request_latencies)
}));
}
}
// Spawn additional concurrent find_matches callers if requested.
// These tasks run alongside the trace-replay workers to stress the read path.
let fm_stop = Arc::new(AtomicBool::new(false));
let mut fm_tasks = Vec::new();
if find_matches_concurrency > 0 {
// Collect all request sequences as a pool for random selection.
let seq_pool: Arc<Vec<Vec<LocalBlockHash>>> = Arc::new(
worker_traces
.iter()
.flat_map(|t| t.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Request(hashes) => Some(hashes.clone()),
_ => None,
})
.collect(),
);
if !seq_pool.is_empty() {
for task_id in 0..find_matches_concurrency {
let indexer = indexer.clone();
let pool = Arc::clone(&seq_pool);
let stop = Arc::clone(&fm_stop);
fm_tasks.push(tokio::spawn(async move {
let mut latencies = Vec::new();
let mut idx = task_id % pool.len();
while !stop.load(Ordering::Relaxed) {
let seq = pool[idx].clone();
let start = minstant::Instant::now();
let _ = indexer.find_matches(seq).await;
latencies.push(start.elapsed().as_nanos() as u64);
idx = (idx + 1) % pool.len();
}
latencies
}));
}
}
}
let mut latencies = Vec::new();
for task in tasks {
latencies.extend(task.await??);
}
// Signal concurrent find_matches callers to stop and collect their latencies.
fm_stop.store(true, Ordering::Relaxed);
for task in fm_tasks {
if let Ok(fm_latencies) = task.await {
latencies.extend(fm_latencies);
}
}
if progress.elapsed() > Duration::from_millis(benchmark_duration_ms * 11 / 10) {
eprintln!(
"WARNING: The benchmarker is unable to keep up with the request/event generation rate. Rerun with a larger --benchmark-duration-ms."
)
}
let total_duration = progress.elapsed();
let total_events = worker_traces
.iter()
.map(|trace| {
trace
.iter()
.filter(|trace| matches!(trace.entry, WorkerTraceEntry::Event(_)))
.count()
})
.sum::<usize>()
* args.common.inference_worker_duplication_factor;
let total_requests = worker_traces.iter().map(|trace| trace.len()).sum::<usize>()
* args.common.inference_worker_duplication_factor
- total_events;
let total_request_blocks: usize = worker_traces
.iter()
.flat_map(|t| t.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Request(hashes) => Some(hashes.len()),
_ => None,
})
.sum::<usize>()
* args.common.inference_worker_duplication_factor;
let total_event_blocks: usize = worker_traces
.iter()
.flat_map(|t| t.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Event(ev) => match &ev.data {
KvCacheEventData::Stored(s) => Some(s.blocks.len()),
_ => Some(0),
},
_ => None,
})
.sum::<usize>()
* args.common.inference_worker_duplication_factor;
let counted_events = if count_events { total_events } else { 0 };
let counted_event_blocks = if count_events { total_event_blocks } else { 0 };
let total_blocks = total_request_blocks + counted_event_blocks;
let total_ops = total_requests + counted_events;
let offered_ops_throughput = total_ops as f32 / benchmark_duration_ms as f32 * 1000.0;
let ops_throughput = total_ops as f32 / total_duration.as_millis() as f32 * 1000.0;
let offered_block_throughput = total_blocks as f32 / benchmark_duration_ms as f32 * 1000.0;
let block_throughput = total_blocks as f32 / total_duration.as_millis() as f32 * 1000.0;
latencies.sort_unstable();
let latency_p99_us = if latencies.is_empty() {
0.0
} else {
latencies[latencies.len() * 99 / 100] as f32 / 1000.0
};
println!(
"Offered Ops Throughput: {} ops/s | Achieved: {} ops/s (requests + events)",
offered_ops_throughput as u64, ops_throughput as u64,
);
println!(
"Offered Block Throughput: {} block ops/s | Achieved: {} block ops/s",
offered_block_throughput as u64, block_throughput as u64,
);
println!("Latency p99: {}us", latency_p99_us);
Ok(BenchmarkResults {
offered_ops_throughput,
ops_throughput,
offered_block_throughput,
block_throughput,
latency_p99_us,
})
}
async fn run_tests() -> anyhow::Result<()> {
use std::collections::HashSet;
use std::fs::File;
use std::io::Write;
let path =
std::env::temp_dir().join(format!("mooncake_bench_test_{}.jsonl", std::process::id()));
{
let mut f = File::create(&path)?;
for (i, (hash_ids, output_length)) in
[(&[0u64, 1, 2] as &[u64], 10u64), (&[0, 1, 3, 4], 10)]
.iter()
.enumerate()
{
writeln!(
f,
"{}",
serde_json::json!({
"timestamp": i as u64,
"input_length": hash_ids.len(),
"hash_ids": hash_ids,
"output_length": output_length,
})
)?;
}
}
let traces = process_mooncake_trace(path.to_str().unwrap(), 512, 2, 2, 2, 42)?;
std::fs::remove_file(&path).ok();
let mut all_hashes: Vec<Vec<u64>> = traces
.into_iter()
.flat_map(|worker| worker.sessions.into_iter())
.flat_map(|session| session.turns.into_iter().map(|turn| turn.hash_ids))
.collect();
all_hashes.sort();
// expand(2): [0,1,2] → [0,1,2,3,4,5], [0,1,3,4] → [0,1,2,3,6,7,8,9]
// duplicate(2): max=9, offset=10
let mut expected = vec![
vec![0, 1, 2, 3, 4, 5],
vec![10, 11, 12, 13, 14, 15],
vec![0, 1, 2, 3, 6, 7, 8, 9],
vec![10, 11, 12, 13, 16, 17, 18, 19],
];
expected.sort();
assert_eq!(all_hashes, expected, "hash_ids mismatch");
// Verify prefix structure within each copy.
let copy0: Vec<&Vec<u64>> = all_hashes.iter().filter(|h| h[0] == 0).collect();
let copy1: Vec<&Vec<u64>> = all_hashes.iter().filter(|h| h[0] == 10).collect();
assert_eq!(copy0.len(), 2);
assert_eq!(copy1.len(), 2);
assert_eq!(copy0[0][..4], copy0[1][..4], "copy 0 shared prefix broken");
assert_eq!(copy1[0][..4], copy1[1][..4], "copy 1 shared prefix broken");
// Verify disjointness between copies.
let set0: HashSet<u64> = copy0.iter().flat_map(|h| h.iter().copied()).collect();
let set1: HashSet<u64> = copy1.iter().flat_map(|h| h.iter().copied()).collect();
assert!(set0.is_disjoint(&set1), "copies are not hash-disjoint");
let replay_trace = Trace {
block_size: 2,
sessions: vec![dynamo_mocker::loadgen::SessionTrace {
session_id: "session-a".to_string(),
first_arrival_timestamp_ms: Some(0.0),
turns: vec![
dynamo_mocker::loadgen::TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![1, 2],
delay_after_previous_ms: 0.0,
},
dynamo_mocker::loadgen::TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![3, 4],
delay_after_previous_ms: 5.0,
},
],
}],
};
let artifacts = generate_replay_artifacts(&[replay_trace], 1024, 2, 5).await?;
assert_eq!(artifacts.len(), 1);
assert_eq!(artifacts[0].requests.len(), 2);
let first_uuid = artifacts[0].requests[0].uuid;
let first_completion_ms = artifacts[0]
.output_signals
.iter()
.find(|signal| signal.signal.uuid == first_uuid && signal.signal.completed)
.expect("first request must complete")
.timestamp_us as f64
/ 1000.0;
assert!(
artifacts[0].requests[1].scheduled_ready_at_ms + 0.1 >= first_completion_ms + 5.0,
"expected second request to wait for completion plus delay"
);
println!("All tests passed.");
Ok(())
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
if args.common.test {
return run_tests().await;
anyhow::bail!(
"mooncake_bench no longer supports --test; run `cargo test --package dynamo-bench --test mooncake_trace` instead"
);
}
let path = match args.common.mooncake_trace_path.as_deref() {
......@@ -854,14 +382,7 @@ async fn main() -> anyhow::Result<()> {
.await?;
let indexer_names: Vec<String> = if args.compare.is_empty() {
let name = match args.get_indexer() {
IndexerArgs::RadixTree {} => "radix-tree",
IndexerArgs::NestedMap { .. } => "nested-map",
IndexerArgs::ConcurrentRadixTree { .. } => "concurrent-radix-tree",
IndexerArgs::ConcurrentRadixTreeCompressed { .. } => "concurrent-radix-tree-compressed",
IndexerArgs::BranchShardedCrtc { .. } => "branch-sharded-crtc",
};
vec![name.to_string()]
vec![args.get_indexer().to_config().short_name().to_string()]
} else {
args.compare.clone()
};
......@@ -881,7 +402,13 @@ async fn main() -> anyhow::Result<()> {
println!("Benchmarking indexer: {}", name);
println!("{}", "=".repeat(60));
let multi_threaded = IndexerArgs::is_multi_threaded(name);
let config = if args.compare.is_empty() {
args.get_indexer().to_config()
} else {
MooncakeIndexerConfig::from_short_name(name, args.num_event_workers)?
};
let multi_threaded = config.is_multi_threaded();
let durations = if multi_threaded {
&durations_high_to_low
} else {
......@@ -893,21 +420,29 @@ async fn main() -> anyhow::Result<()> {
for &dur_ms in durations {
println!("\n=== Sweep: benchmark_duration_ms = {} ===", dur_ms);
let indexer = if args.compare.is_empty() {
args.get_indexer().build(args.common.block_size)
} else {
IndexerArgs::from_name(name, args.common.block_size, args.num_event_workers)?
};
let count_events = IndexerArgs::supports_remove(name);
let result = run_benchmark(
let indexer = config.build(
args.common.block_size,
Arc::new(KvIndexerMetrics::new_unregistered()),
);
let run = run_benchmark(
indexer,
artifacts.clone(),
&args,
dur_ms,
count_events,
args.find_matches_concurrency,
MooncakeBenchmarkConfig {
benchmark_duration_ms: dur_ms,
inference_worker_duplication_factor: args
.common
.inference_worker_duplication_factor,
count_events: config.supports_remove(),
find_matches_concurrency: args.find_matches_concurrency,
},
)
.await?;
if !run.kept_up {
eprintln!(
"WARNING: The benchmarker is unable to keep up with the request/event generation rate. Rerun with a larger --benchmark-duration-ms."
);
}
let result = run.results;
if multi_threaded {
if result.block_throughput >= result.offered_block_throughput * 0.95 {
......@@ -968,12 +503,15 @@ async fn main() -> anyhow::Result<()> {
for name in &indexer_names {
println!("\nBenchmarking indexer: {}", name);
let indexer = if args.compare.is_empty() {
args.get_indexer().build(args.common.block_size)
let config = if args.compare.is_empty() {
args.get_indexer().to_config()
} else {
IndexerArgs::from_name(name, args.common.block_size, args.num_event_workers)?
MooncakeIndexerConfig::from_short_name(name, args.num_event_workers)?
};
let count_events = IndexerArgs::supports_remove(name);
let indexer = config.build(
args.common.block_size,
Arc::new(KvIndexerMetrics::new_unregistered()),
);
// Start shard-size sampler if a CSV path was provided.
let shard_cancel = CancellationToken::new();
......@@ -987,15 +525,24 @@ async fn main() -> anyhow::Result<()> {
None
};
run_benchmark(
let run = run_benchmark(
indexer.clone(),
artifacts.clone(),
&args,
args.common.benchmark_duration_ms,
count_events,
args.find_matches_concurrency,
MooncakeBenchmarkConfig {
benchmark_duration_ms: args.common.benchmark_duration_ms,
inference_worker_duplication_factor: args
.common
.inference_worker_duplication_factor,
count_events: config.supports_remove(),
find_matches_concurrency: args.find_matches_concurrency,
},
)
.await?;
if !run.kept_up {
eprintln!(
"WARNING: The benchmarker is unable to keep up with the request/event generation rate. Rerun with a larger --benchmark-duration-ms."
);
}
// Stop sampler and write CSV + plot.
shard_cancel.cancel();
......
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use dynamo_kv_router::LocalBlockHash;
use dynamo_kv_router::indexer::{KvIndexer, KvIndexerInterface, KvIndexerMetrics};
use dynamo_kv_router::protocols::{KvCacheEvent, KvCacheEventData, RouterEvent};
use dynamo_kv_router::{
BranchShardedIndexer, ConcurrentRadixTree, ConcurrentRadixTreeCompressed, PositionalIndexer,
ThreadPoolIndexer,
};
use tokio::time::{Duration, Instant};
use tokio_util::sync::CancellationToken;
use crate::common::{
BenchmarkRun, WorkerReplayArtifacts, compute_benchmark_run, make_progress_bar,
rescale_trace_timestamps,
};
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MooncakeIndexerKind {
RadixTree,
NestedMap,
ConcurrentRadixTree,
ConcurrentRadixTreeCompressed,
BranchShardedCrtc,
}
#[derive(Clone, Debug)]
pub struct MooncakeIndexerConfig {
pub kind: MooncakeIndexerKind,
pub jump_size: usize,
pub num_event_workers: usize,
pub num_shards: usize,
pub num_event_workers_per_shard: usize,
pub prefix_depth: usize,
}
#[allow(dead_code)]
impl MooncakeIndexerConfig {
pub fn radix_tree() -> Self {
Self {
kind: MooncakeIndexerKind::RadixTree,
jump_size: 8,
num_event_workers: 16,
num_shards: 2,
num_event_workers_per_shard: 4,
prefix_depth: 2,
}
}
pub fn nested_map(jump_size: usize, num_event_workers: usize) -> Self {
Self {
kind: MooncakeIndexerKind::NestedMap,
jump_size,
num_event_workers,
..Self::radix_tree()
}
}
pub fn concurrent_radix_tree(num_event_workers: usize) -> Self {
Self {
kind: MooncakeIndexerKind::ConcurrentRadixTree,
num_event_workers,
..Self::radix_tree()
}
}
pub fn concurrent_radix_tree_compressed(num_event_workers: usize) -> Self {
Self {
kind: MooncakeIndexerKind::ConcurrentRadixTreeCompressed,
num_event_workers,
..Self::radix_tree()
}
}
pub fn branch_sharded_crtc(
num_shards: usize,
num_event_workers_per_shard: usize,
prefix_depth: usize,
) -> Self {
Self {
kind: MooncakeIndexerKind::BranchShardedCrtc,
num_shards,
num_event_workers_per_shard,
prefix_depth,
..Self::radix_tree()
}
}
pub fn short_name(&self) -> &'static str {
match self.kind {
MooncakeIndexerKind::RadixTree => "radix-tree",
MooncakeIndexerKind::NestedMap => "nested-map",
MooncakeIndexerKind::ConcurrentRadixTree => "concurrent-radix-tree",
MooncakeIndexerKind::ConcurrentRadixTreeCompressed => {
"concurrent-radix-tree-compressed"
}
MooncakeIndexerKind::BranchShardedCrtc => "branch-sharded-crtc",
}
}
pub fn is_multi_threaded(&self) -> bool {
matches!(
self.kind,
MooncakeIndexerKind::NestedMap
| MooncakeIndexerKind::ConcurrentRadixTree
| MooncakeIndexerKind::ConcurrentRadixTreeCompressed
| MooncakeIndexerKind::BranchShardedCrtc
)
}
pub fn supports_remove(&self) -> bool {
true
}
pub fn from_short_name(name: &str, num_event_workers: usize) -> anyhow::Result<Self> {
let config = match name {
"radix-tree" => Self::radix_tree(),
"nested-map" => Self::nested_map(8, num_event_workers),
"concurrent-radix-tree" => Self::concurrent_radix_tree(num_event_workers),
"concurrent-radix-tree-compressed" => {
Self::concurrent_radix_tree_compressed(num_event_workers)
}
"branch-sharded-crtc" => Self::branch_sharded_crtc(2, num_event_workers, 2),
_ => anyhow::bail!(
"Unknown indexer '{}'. Valid names: radix-tree, nested-map, concurrent-radix-tree, concurrent-radix-tree-compressed, branch-sharded-crtc",
name
),
};
Ok(config)
}
pub fn build(
&self,
block_size: u32,
metrics: Arc<KvIndexerMetrics>,
) -> Arc<dyn KvIndexerInterface + Send + Sync> {
match self.kind {
MooncakeIndexerKind::RadixTree => Arc::new(KvIndexer::new(
CancellationToken::new(),
block_size,
metrics,
)),
MooncakeIndexerKind::NestedMap => Arc::new(ThreadPoolIndexer::new_with_metrics(
PositionalIndexer::new(self.jump_size),
self.num_event_workers,
block_size,
Some(metrics),
)),
MooncakeIndexerKind::ConcurrentRadixTree => {
Arc::new(ThreadPoolIndexer::new_with_metrics(
ConcurrentRadixTree::new(),
self.num_event_workers,
block_size,
Some(metrics),
))
}
MooncakeIndexerKind::ConcurrentRadixTreeCompressed => {
Arc::new(ThreadPoolIndexer::new_with_metrics(
ConcurrentRadixTreeCompressed::new(),
self.num_event_workers,
block_size,
Some(metrics),
))
}
MooncakeIndexerKind::BranchShardedCrtc => {
let shards = (0..self.num_shards)
.map(|_| {
ThreadPoolIndexer::new_with_metrics(
ConcurrentRadixTreeCompressed::new(),
self.num_event_workers_per_shard,
block_size,
Some(Arc::clone(&metrics)),
)
})
.collect();
Arc::new(BranchShardedIndexer::new_with_options(
shards,
self.prefix_depth,
block_size,
))
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct MooncakeBenchmarkConfig {
pub benchmark_duration_ms: u64,
pub inference_worker_duplication_factor: usize,
pub count_events: bool,
pub find_matches_concurrency: usize,
}
/// A single entry in a worker's merged benchmark timeline.
#[derive(Clone)]
enum WorkerTraceEntry {
Request(Vec<LocalBlockHash>),
Event(KvCacheEvent),
}
/// A timestamped entry in a worker's benchmark trace, used to replay requests
/// and events at the correct relative timing.
#[derive(Clone)]
struct WorkerTrace {
entry: WorkerTraceEntry,
timestamp_us: u64,
}
fn prepare_worker_traces(
artifacts: Vec<WorkerReplayArtifacts>,
benchmark_duration_ms: u64,
) -> Vec<Vec<WorkerTrace>> {
let traces = artifacts
.into_iter()
.map(|artifact| {
let mut merged = artifact
.requests
.into_iter()
.map(|request| WorkerTrace {
timestamp_us: request.timestamp_us,
entry: WorkerTraceEntry::Request(request.replay_hashes.local_block_hashes),
})
.chain(artifact.kv_events.into_iter().map(|event| WorkerTrace {
timestamp_us: event.timestamp_us,
entry: WorkerTraceEntry::Event(event.event),
}))
.collect::<Vec<_>>();
merged.sort_by_key(|entry| entry.timestamp_us);
merged
})
.collect::<Vec<_>>();
rescale_trace_timestamps(
&traces,
benchmark_duration_ms,
|entry| entry.timestamp_us,
|entry, timestamp_us| WorkerTrace {
entry: entry.entry.clone(),
timestamp_us,
},
)
}
pub async fn run_benchmark(
indexer: Arc<dyn KvIndexerInterface + Send + Sync>,
artifacts: Vec<WorkerReplayArtifacts>,
config: MooncakeBenchmarkConfig,
) -> anyhow::Result<BenchmarkRun> {
let worker_traces = prepare_worker_traces(artifacts, config.benchmark_duration_ms);
let worker_traces = worker_traces.into_iter().map(Arc::new).collect::<Vec<_>>();
let progress = make_progress_bar(Some(
worker_traces
.iter()
.map(|trace| trace.len() as u64)
.sum::<u64>()
* config.inference_worker_duplication_factor as u64,
));
let mut tasks = Vec::new();
for replica in 0..config.inference_worker_duplication_factor {
for (worker_id, worker_trace) in worker_traces.iter().enumerate() {
let indexer = Arc::clone(&indexer);
let trace = Arc::clone(worker_trace);
let progress = progress.clone();
let worker_id = worker_id + replica * worker_traces.len();
tasks.push(tokio::spawn(async move {
let mut request_latencies = Vec::with_capacity(trace.len());
let submit = |entry: WorkerTrace| async {
match entry.entry {
WorkerTraceEntry::Request(request) => {
let start = minstant::Instant::now();
indexer.find_matches(request).await?;
Ok::<Option<u64>, anyhow::Error>(
Some(start.elapsed().as_nanos() as u64),
)
}
WorkerTraceEntry::Event(event) => {
indexer
.apply_event(RouterEvent::new(worker_id as u64, event))
.await;
Ok(None)
}
}
};
let mut target = Instant::now();
let mut trace = trace.iter().peekable();
let mut local_count = 0;
while let Some(entry) = trace.next() {
let mut processed = 1;
let entry_timestamp_us = entry.timestamp_us;
if let Some(latency) = submit(entry.clone()).await? {
request_latencies.push(latency);
}
while let Some(next) = trace.peek() {
if next.timestamp_us == entry_timestamp_us {
if let Some(latency) = submit(trace.next().unwrap().clone()).await? {
request_latencies.push(latency);
}
processed += 1;
} else {
break;
}
}
if let Some(next) = trace.peek() {
target += Duration::from_micros(next.timestamp_us - entry_timestamp_us);
}
if target > Instant::now() {
tokio::time::sleep_until(target).await;
}
local_count += processed;
if local_count > 100 {
progress.inc(local_count);
local_count = 0;
}
}
progress.inc(local_count);
Ok::<_, anyhow::Error>(request_latencies)
}));
}
}
let fm_stop = Arc::new(AtomicBool::new(false));
let mut fm_tasks = Vec::new();
if config.find_matches_concurrency > 0 {
let seq_pool: Arc<Vec<Vec<LocalBlockHash>>> = Arc::new(
worker_traces
.iter()
.flat_map(|trace| trace.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Request(hashes) => Some(hashes.clone()),
WorkerTraceEntry::Event(_) => None,
})
.collect(),
);
if !seq_pool.is_empty() {
for task_id in 0..config.find_matches_concurrency {
let indexer = Arc::clone(&indexer);
let pool = Arc::clone(&seq_pool);
let stop = Arc::clone(&fm_stop);
fm_tasks.push(tokio::spawn(async move {
let mut latencies = Vec::new();
let mut idx = task_id % pool.len();
while !stop.load(Ordering::Relaxed) {
let seq = pool[idx].clone();
let start = minstant::Instant::now();
let _ = indexer.find_matches(seq).await;
latencies.push(start.elapsed().as_nanos() as u64);
idx = (idx + 1) % pool.len();
}
latencies
}));
}
}
}
let mut latencies = Vec::new();
for task in tasks {
latencies.extend(task.await??);
}
fm_stop.store(true, Ordering::Relaxed);
for task in fm_tasks {
if let Ok(fm_latencies) = task.await {
latencies.extend(fm_latencies);
}
}
let total_duration = progress.elapsed();
let total_events = worker_traces
.iter()
.map(|trace| {
trace
.iter()
.filter(|entry| matches!(entry.entry, WorkerTraceEntry::Event(_)))
.count()
})
.sum::<usize>()
* config.inference_worker_duplication_factor;
let total_requests = worker_traces.iter().map(|trace| trace.len()).sum::<usize>()
* config.inference_worker_duplication_factor
- total_events;
let total_request_blocks = worker_traces
.iter()
.flat_map(|trace| trace.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Request(hashes) => Some(hashes.len()),
WorkerTraceEntry::Event(_) => None,
})
.sum::<usize>()
* config.inference_worker_duplication_factor;
let total_event_blocks = worker_traces
.iter()
.flat_map(|trace| trace.iter())
.filter_map(|entry| match &entry.entry {
WorkerTraceEntry::Event(event) => match &event.data {
KvCacheEventData::Stored(store) => Some(store.blocks.len()),
_ => Some(0),
},
WorkerTraceEntry::Request(_) => None,
})
.sum::<usize>()
* config.inference_worker_duplication_factor;
let counted_events = if config.count_events { total_events } else { 0 };
let counted_event_blocks = if config.count_events {
total_event_blocks
} else {
0
};
let run = compute_benchmark_run(
total_requests + counted_events,
total_request_blocks + counted_event_blocks,
config.benchmark_duration_ms,
total_duration,
latencies,
);
println!(
"Offered Ops Throughput: {} ops/s | Achieved: {} ops/s (requests + events)",
run.results.offered_ops_throughput as u64, run.results.ops_throughput as u64,
);
println!(
"Offered Block Throughput: {} block ops/s | Achieved: {} block ops/s",
run.results.offered_block_throughput as u64, run.results.block_throughput as u64,
);
println!("Latency p99: {}us", run.results.latency_p99_us);
Ok(run)
}
{"timestamp": 0, "input_length": 6755, "output_length": 500, "hash_ids": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]}
{"timestamp": 0, "input_length": 7319, "output_length": 490, "hash_ids": [0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]}
{"timestamp": 0, "input_length": 7234, "output_length": 794, "hash_ids": [0, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41]}
{"timestamp": 0, "input_length": 2287, "output_length": 316, "hash_ids": [0, 42, 43, 44, 45]}
{"timestamp": 0, "input_length": 9013, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]}
{"timestamp": 0, "input_length": 6506, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 64]}
{"timestamp": 0, "input_length": 4824, "output_length": 173, "hash_ids": [0, 65, 66, 67, 68, 69, 70, 71, 72, 73]}
{"timestamp": 0, "input_length": 3119, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 79, 80]}
{"timestamp": 0, "input_length": 23090, "output_length": 453, "hash_ids": [0, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125]}
{"timestamp": 0, "input_length": 3135, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 126, 127]}
{"timestamp": 0, "input_length": 26874, "output_length": 458, "hash_ids": [0, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179]}
{"timestamp": 0, "input_length": 10487, "output_length": 402, "hash_ids": [0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199]}
{"timestamp": 0, "input_length": 17448, "output_length": 610, "hash_ids": [0, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233]}
{"timestamp": 0, "input_length": 6253, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 234]}
{"timestamp": 0, "input_length": 6725, "output_length": 32, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 235, 236]}
{"timestamp": 3052, "input_length": 13538, "output_length": 71, "hash_ids": [0, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262]}
{"timestamp": 3052, "input_length": 87162, "output_length": 402, "hash_ids": [0, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432]}
{"timestamp": 3052, "input_length": 6166, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 433]}
{"timestamp": 3052, "input_length": 6320, "output_length": 548, "hash_ids": [0, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445]}
{"timestamp": 3052, "input_length": 2007, "output_length": 354, "hash_ids": [0, 446, 447, 448]}
{"timestamp": 3052, "input_length": 3174, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 449, 450]}
{"timestamp": 3052, "input_length": 3131, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 451, 452]}
{"timestamp": 3052, "input_length": 3159, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 453, 454]}
{"timestamp": 3052, "input_length": 6820, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 455, 456]}
{"timestamp": 3052, "input_length": 3154, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 457, 458]}
{"timestamp": 3052, "input_length": 9416, "output_length": 145, "hash_ids": [0, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476]}
{"timestamp": 3052, "input_length": 7460, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 720, 721, 722]}
{"timestamp": 3052, "input_length": 913, "output_length": 355, "hash_ids": [0, 723]}
{"timestamp": 3052, "input_length": 12833, "output_length": 466, "hash_ids": [0, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748]}
{"timestamp": 3052, "input_length": 20504, "output_length": 929, "hash_ids": [0, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788]}
{"timestamp": 3052, "input_length": 16600, "output_length": 349, "hash_ids": [0, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820]}
{"timestamp": 3052, "input_length": 26337, "output_length": 370, "hash_ids": [0, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871]}
{"timestamp": 3052, "input_length": 6043, "output_length": 475, "hash_ids": [0, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882]}
{"timestamp": 3052, "input_length": 5951, "output_length": 420, "hash_ids": [0, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893]}
{"timestamp": 3052, "input_length": 11333, "output_length": 848, "hash_ids": [0, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915]}
{"timestamp": 3052, "input_length": 15155, "output_length": 80, "hash_ids": [0, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944]}
{"timestamp": 3052, "input_length": 45918, "output_length": 265, "hash_ids": [0, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033]}
{"timestamp": 6105, "input_length": 6355, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1034]}
{"timestamp": 6105, "input_length": 7111, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1035, 1036]}
{"timestamp": 6105, "input_length": 6198, "output_length": 39, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1037]}
{"timestamp": 6105, "input_length": 6166, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1038]}
{"timestamp": 6105, "input_length": 1048, "output_length": 26, "hash_ids": [0, 1039, 1040]}
{"timestamp": 6105, "input_length": 3066, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1041]}
{"timestamp": 6105, "input_length": 4184, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 1042, 1043, 1044, 1045]}
{"timestamp": 6105, "input_length": 6721, "output_length": 29, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1046, 1047]}
{"timestamp": 6105, "input_length": 5698, "output_length": 745, "hash_ids": [0, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058]}
{"timestamp": 6105, "input_length": 3153, "output_length": 25, "hash_ids": [74, 75, 76, 77, 78, 1059, 1060]}
{"timestamp": 6105, "input_length": 3154, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1061, 1062]}
{"timestamp": 6105, "input_length": 6169, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1063]}
{"timestamp": 6105, "input_length": 3132, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 1064, 1065]}
{"timestamp": 6105, "input_length": 4346, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1066, 1067, 1068, 1069]}
{"timestamp": 6105, "input_length": 7141, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1070, 1071]}
{"timestamp": 6105, "input_length": 6306, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1072]}
{"timestamp": 9162, "input_length": 10349, "output_length": 584, "hash_ids": [0, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092]}
{"timestamp": 9162, "input_length": 1475, "output_length": 615, "hash_ids": [0, 1093, 1094]}
{"timestamp": 9162, "input_length": 6188, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1095]}
{"timestamp": 9162, "input_length": 15342, "output_length": 344, "hash_ids": [0, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124]}
{"timestamp": 9162, "input_length": 3119, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 1125, 1126]}
{"timestamp": 9162, "input_length": 3803, "output_length": 309, "hash_ids": [0, 1127, 1128, 1129, 1130, 1131, 1132, 1133]}
{"timestamp": 9162, "input_length": 6785, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1134, 1135]}
{"timestamp": 9162, "input_length": 8766, "output_length": 1, "hash_ids": [0, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152]}
{"timestamp": 9162, "input_length": 26124, "output_length": 238, "hash_ids": [0, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203]}
{"timestamp": 9162, "input_length": 7490, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1204, 1205, 1206]}
{"timestamp": 9162, "input_length": 6669, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1207, 1208]}
{"timestamp": 9162, "input_length": 4113, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 1209, 1210, 1211, 1212]}
{"timestamp": 9162, "input_length": 16631, "output_length": 449, "hash_ids": [0, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244]}
{"timestamp": 9162, "input_length": 6598, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1245]}
{"timestamp": 9162, "input_length": 6563, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1246]}
{"timestamp": 9162, "input_length": 6950, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1247, 1248]}
{"timestamp": 9162, "input_length": 1106, "output_length": 240, "hash_ids": [0, 1249, 1250]}
{"timestamp": 12214, "input_length": 3627, "output_length": 555, "hash_ids": [0, 1251, 1252, 1253, 1254, 1255, 1256, 1257]}
{"timestamp": 12214, "input_length": 6520, "output_length": 47, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1258]}
{"timestamp": 12214, "input_length": 2033, "output_length": 524, "hash_ids": [0, 1259, 1260, 1261]}
{"timestamp": 12214, "input_length": 1900, "output_length": 587, "hash_ids": [0, 1264, 1265, 1266]}
{"timestamp": 12214, "input_length": 6185, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1267]}
{"timestamp": 12214, "input_length": 14024, "output_length": 227, "hash_ids": [0, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294]}
{"timestamp": 12214, "input_length": 6618, "output_length": 35, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1295]}
{"timestamp": 12214, "input_length": 12091, "output_length": 239, "hash_ids": [0, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318]}
{"timestamp": 12214, "input_length": 7413, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1319, 1320, 1321]}
{"timestamp": 12214, "input_length": 3375, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 1322, 1323]}
{"timestamp": 12214, "input_length": 1065, "output_length": 324, "hash_ids": [0, 1324, 1325]}
{"timestamp": 12214, "input_length": 9612, "output_length": 203, "hash_ids": [0, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343]}
{"timestamp": 12214, "input_length": 19950, "output_length": 105, "hash_ids": [0, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381]}
{"timestamp": 15267, "input_length": 6522, "output_length": 481, "hash_ids": [0, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393]}
{"timestamp": 15267, "input_length": 897, "output_length": 324, "hash_ids": [0, 1394]}
{"timestamp": 15267, "input_length": 5386, "output_length": 361, "hash_ids": [0, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404]}
{"timestamp": 15267, "input_length": 7011, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1405, 1406]}
{"timestamp": 15267, "input_length": 6905, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1407, 1408]}
{"timestamp": 15267, "input_length": 6251, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1409]}
{"timestamp": 15267, "input_length": 23576, "output_length": 362, "hash_ids": [0, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455]}
{"timestamp": 15267, "input_length": 38267, "output_length": 589, "hash_ids": [0, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529]}
{"timestamp": 15267, "input_length": 7539, "output_length": 415, "hash_ids": [0, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543]}
{"timestamp": 15267, "input_length": 3133, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 1544, 1545]}
{"timestamp": 15267, "input_length": 8947, "output_length": 219, "hash_ids": [0, 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562]}
{"timestamp": 15267, "input_length": 24223, "output_length": 587, "hash_ids": [0, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609]}
{"timestamp": 15267, "input_length": 15753, "output_length": 417, "hash_ids": [0, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639]}
{"timestamp": 15267, "input_length": 27662, "output_length": 459, "hash_ids": [0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693]}
{"timestamp": 15267, "input_length": 3329, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1694, 1695]}
{"timestamp": 15267, "input_length": 11035, "output_length": 98, "hash_ids": [0, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716]}
{"timestamp": 15267, "input_length": 3355, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 1717, 1718]}
{"timestamp": 15267, "input_length": 2347, "output_length": 355, "hash_ids": [0, 1719, 1720, 1721, 1722]}
{"timestamp": 15267, "input_length": 932, "output_length": 421, "hash_ids": [0, 1723]}
{"timestamp": 15267, "input_length": 14066, "output_length": 522, "hash_ids": [0, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750]}
{"timestamp": 18320, "input_length": 7932, "output_length": 375, "hash_ids": [0, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765]}
{"timestamp": 18320, "input_length": 13867, "output_length": 534, "hash_ids": [0, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792]}
{"timestamp": 18320, "input_length": 6608, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1793]}
{"timestamp": 18320, "input_length": 6484, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1794]}
{"timestamp": 18320, "input_length": 897, "output_length": 57, "hash_ids": [0, 1795]}
{"timestamp": 18320, "input_length": 19587, "output_length": 178, "hash_ids": [0, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833]}
{"timestamp": 18320, "input_length": 6237, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1834]}
{"timestamp": 18320, "input_length": 6165, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1835]}
{"timestamp": 18320, "input_length": 7307, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1836, 1837, 1838]}
{"timestamp": 18320, "input_length": 7122, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1839, 1840]}
{"timestamp": 18320, "input_length": 6345, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1841]}
{"timestamp": 21373, "input_length": 3180, "output_length": 195, "hash_ids": [0, 1842, 1843, 1844, 1845, 1846, 1847]}
{"timestamp": 21373, "input_length": 3170, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 1848, 1849]}
{"timestamp": 21373, "input_length": 3151, "output_length": 27, "hash_ids": [74, 75, 76, 77, 78, 1850, 1851]}
{"timestamp": 21373, "input_length": 2640, "output_length": 366, "hash_ids": [0, 1852, 1853, 1854, 1855, 1856]}
{"timestamp": 21373, "input_length": 6717, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1857, 1858]}
{"timestamp": 21373, "input_length": 3134, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1859, 1860]}
{"timestamp": 21373, "input_length": 3151, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 1861, 1862]}
{"timestamp": 21373, "input_length": 5915, "output_length": 542, "hash_ids": [0, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873]}
{"timestamp": 21373, "input_length": 8422, "output_length": 439, "hash_ids": [0, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889]}
{"timestamp": 21373, "input_length": 8347, "output_length": 387, "hash_ids": [0, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905]}
{"timestamp": 21373, "input_length": 6231, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1906]}
{"timestamp": 21373, "input_length": 7173, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1907, 1908, 1909]}
{"timestamp": 24426, "input_length": 6854, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1910, 1911]}
{"timestamp": 24426, "input_length": 3220, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 1912, 1913]}
{"timestamp": 24426, "input_length": 6358, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1914]}
{"timestamp": 24426, "input_length": 7379, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1915, 1916, 1917]}
{"timestamp": 24426, "input_length": 4040, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1918, 1919, 1920]}
{"timestamp": 24426, "input_length": 6169, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1921]}
{"timestamp": 24426, "input_length": 3126, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 1922, 1923]}
{"timestamp": 24426, "input_length": 12149, "output_length": 237, "hash_ids": [0, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946]}
{"timestamp": 24426, "input_length": 2981, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 1947]}
{"timestamp": 24426, "input_length": 28211, "output_length": 603, "hash_ids": [0, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002]}
{"timestamp": 24426, "input_length": 8077, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2003, 2004, 2005, 2006]}
{"timestamp": 24426, "input_length": 6658, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2007, 2008]}
{"timestamp": 24426, "input_length": 4230, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 2009, 2010, 2011, 2012]}
{"timestamp": 24426, "input_length": 2127, "output_length": 347, "hash_ids": [0, 2013, 2014, 2015, 2016]}
{"timestamp": 24426, "input_length": 6165, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2017]}
{"timestamp": 24426, "input_length": 36416, "output_length": 255, "hash_ids": [0, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088]}
{"timestamp": 27482, "input_length": 1421, "output_length": 290, "hash_ids": [0, 2089, 2090]}
{"timestamp": 27482, "input_length": 18079, "output_length": 387, "hash_ids": [0, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125]}
{"timestamp": 27482, "input_length": 35084, "output_length": 538, "hash_ids": [0, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193]}
{"timestamp": 27482, "input_length": 953, "output_length": 48, "hash_ids": [0, 2194]}
{"timestamp": 27482, "input_length": 15830, "output_length": 629, "hash_ids": [0, 2195, 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224]}
{"timestamp": 27482, "input_length": 9242, "output_length": 632, "hash_ids": [0, 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242]}
{"timestamp": 27482, "input_length": 12914, "output_length": 460, "hash_ids": [0, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267]}
{"timestamp": 27482, "input_length": 17793, "output_length": 345, "hash_ids": [0, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300, 2301]}
{"timestamp": 27482, "input_length": 8013, "output_length": 1, "hash_ids": [0, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316]}
{"timestamp": 27482, "input_length": 8501, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2317, 2318, 2319, 2320, 2321]}
{"timestamp": 27482, "input_length": 10748, "output_length": 596, "hash_ids": [0, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341]}
{"timestamp": 27482, "input_length": 7295, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2342, 2343, 2344]}
{"timestamp": 27482, "input_length": 4538, "output_length": 362, "hash_ids": [0, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352]}
{"timestamp": 27482, "input_length": 6955, "output_length": 52, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2353, 2354]}
{"timestamp": 27482, "input_length": 9389, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2355, 2356, 2357, 2358, 2359, 2360, 2361]}
{"timestamp": 27482, "input_length": 4386, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 2362, 2363, 2364, 2365]}
{"timestamp": 30535, "input_length": 6472, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2366]}
{"timestamp": 30535, "input_length": 6256, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2367]}
{"timestamp": 30535, "input_length": 7259, "output_length": 34, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2368, 2369, 2370]}
{"timestamp": 30535, "input_length": 42717, "output_length": 464, "hash_ids": [0, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453]}
{"timestamp": 30535, "input_length": 6171, "output_length": 34, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2454]}
{"timestamp": 30535, "input_length": 6639, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2455]}
{"timestamp": 30535, "input_length": 6635, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2456]}
{"timestamp": 30535, "input_length": 6918, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2457, 2458]}
{"timestamp": 30535, "input_length": 6182, "output_length": 34, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2459]}
{"timestamp": 30535, "input_length": 6580, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2460]}
{"timestamp": 30535, "input_length": 13612, "output_length": 492, "hash_ids": [0, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, 2486]}
{"timestamp": 30535, "input_length": 49897, "output_length": 549, "hash_ids": [0, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583]}
{"timestamp": 30535, "input_length": 17068, "output_length": 440, "hash_ids": [0, 2584, 2585, 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616]}
{"timestamp": 30535, "input_length": 6648, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2617]}
{"timestamp": 30535, "input_length": 3235, "output_length": 29, "hash_ids": [74, 75, 76, 77, 78, 2618, 2619]}
{"timestamp": 33588, "input_length": 21085, "output_length": 563, "hash_ids": [0, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660]}
{"timestamp": 33588, "input_length": 6178, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2661]}
{"timestamp": 33588, "input_length": 3154, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 2662, 2663]}
{"timestamp": 33588, "input_length": 6814, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2664, 2665]}
{"timestamp": 33588, "input_length": 29247, "output_length": 448, "hash_ids": [0, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722]}
{"timestamp": 33588, "input_length": 6168, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2723]}
{"timestamp": 33588, "input_length": 4019, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 2724, 2725, 2726]}
{"timestamp": 33588, "input_length": 7038, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2727, 2728]}
{"timestamp": 33588, "input_length": 82188, "output_length": 683, "hash_ids": [0, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888]}
{"timestamp": 33588, "input_length": 26037, "output_length": 578, "hash_ids": [0, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938]}
{"timestamp": 33588, "input_length": 6247, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2939]}
{"timestamp": 33588, "input_length": 6192, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 2940]}
{"timestamp": 33588, "input_length": 120626, "output_length": 580, "hash_ids": [0, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175]}
{"timestamp": 33588, "input_length": 6535, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3176]}
{"timestamp": 33588, "input_length": 1319, "output_length": 514, "hash_ids": [0, 3177, 3178]}
{"timestamp": 33588, "input_length": 915, "output_length": 265, "hash_ids": [0, 3179]}
{"timestamp": 36640, "input_length": 2883, "output_length": 613, "hash_ids": [0, 3180, 3181, 3182, 3183, 3184]}
{"timestamp": 36640, "input_length": 7043, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3185, 3186]}
{"timestamp": 36640, "input_length": 8613, "output_length": 593, "hash_ids": [0, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, 3202]}
{"timestamp": 36640, "input_length": 3176, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 3203, 3204]}
{"timestamp": 36640, "input_length": 1712, "output_length": 31, "hash_ids": [0, 3205, 3206, 3207]}
{"timestamp": 36640, "input_length": 2426, "output_length": 508, "hash_ids": [0, 3208, 3209, 3210, 3211]}
{"timestamp": 36640, "input_length": 7125, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3212, 3213]}
{"timestamp": 36640, "input_length": 11521, "output_length": 373, "hash_ids": [0, 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235]}
{"timestamp": 36640, "input_length": 1082, "output_length": 505, "hash_ids": [0, 3236, 3237]}
{"timestamp": 36640, "input_length": 2387, "output_length": 621, "hash_ids": [0, 3238, 3239, 3240, 3241]}
{"timestamp": 36640, "input_length": 7294, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3242, 3243, 3244]}
{"timestamp": 36640, "input_length": 8552, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3245, 3246, 3247, 3248, 3249]}
{"timestamp": 36640, "input_length": 11989, "output_length": 529, "hash_ids": [0, 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272]}
{"timestamp": 36640, "input_length": 6911, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3273, 3274]}
{"timestamp": 39693, "input_length": 6777, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3275, 3276]}
{"timestamp": 39693, "input_length": 4488, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 3277, 3278, 3279, 3280]}
{"timestamp": 39693, "input_length": 13681, "output_length": 358, "hash_ids": [0, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 3306]}
{"timestamp": 39693, "input_length": 3149, "output_length": 25, "hash_ids": [74, 75, 76, 77, 78, 3307, 3308]}
{"timestamp": 39693, "input_length": 3193, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 3309, 3310]}
{"timestamp": 39693, "input_length": 16461, "output_length": 182, "hash_ids": [0, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3321, 3322, 3323, 3324, 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3339, 3340, 3341, 3342]}
{"timestamp": 39693, "input_length": 6412, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3343]}
{"timestamp": 39693, "input_length": 3156, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 3344, 3345]}
{"timestamp": 39693, "input_length": 22805, "output_length": 463, "hash_ids": [0, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389]}
{"timestamp": 39693, "input_length": 8484, "output_length": 306, "hash_ids": [0, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3401, 3402, 3403, 3404, 3405]}
{"timestamp": 39693, "input_length": 9210, "output_length": 160, "hash_ids": [0, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422]}
{"timestamp": 39693, "input_length": 3532, "output_length": 228, "hash_ids": [0, 3423, 3424, 3425, 3426, 3427, 3428]}
{"timestamp": 39693, "input_length": 6777, "output_length": 39, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3429, 3430]}
{"timestamp": 39693, "input_length": 1203, "output_length": 223, "hash_ids": [0, 3431, 3432]}
{"timestamp": 39693, "input_length": 8514, "output_length": 232, "hash_ids": [0, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448]}
{"timestamp": 39693, "input_length": 895, "output_length": 574, "hash_ids": [0, 3449]}
{"timestamp": 39693, "input_length": 6176, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3450]}
{"timestamp": 39693, "input_length": 6268, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3451]}
{"timestamp": 39693, "input_length": 6555, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3452]}
{"timestamp": 39693, "input_length": 23328, "output_length": 616, "hash_ids": [0, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497]}
{"timestamp": 42746, "input_length": 6648, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3498]}
{"timestamp": 42746, "input_length": 7423, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3499, 3500, 3501]}
{"timestamp": 42746, "input_length": 5148, "output_length": 494, "hash_ids": [0, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511]}
{"timestamp": 42746, "input_length": 6170, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3512]}
{"timestamp": 42746, "input_length": 7952, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3513, 3514, 3515, 3516]}
{"timestamp": 42746, "input_length": 6045, "output_length": 89, "hash_ids": [0, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527]}
{"timestamp": 42746, "input_length": 15448, "output_length": 338, "hash_ids": [0, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557]}
{"timestamp": 42746, "input_length": 3130, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 3558, 3559]}
{"timestamp": 42746, "input_length": 69616, "output_length": 400, "hash_ids": [0, 3560, 3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609, 3610, 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694]}
{"timestamp": 42746, "input_length": 13180, "output_length": 566, "hash_ids": [0, 3695, 3696, 3697, 3698, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719]}
{"timestamp": 42746, "input_length": 1891, "output_length": 456, "hash_ids": [0, 3720, 3721, 3722]}
{"timestamp": 42746, "input_length": 3130, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 3723, 3724]}
{"timestamp": 42746, "input_length": 6288, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3725]}
{"timestamp": 42746, "input_length": 3120, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 3726, 3727]}
{"timestamp": 42746, "input_length": 3124, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 3728, 3729]}
{"timestamp": 45802, "input_length": 905, "output_length": 396, "hash_ids": [0, 3730]}
{"timestamp": 45802, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3731]}
{"timestamp": 45802, "input_length": 6180, "output_length": 30, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3732]}
{"timestamp": 45802, "input_length": 894, "output_length": 439, "hash_ids": [0, 3733]}
{"timestamp": 45802, "input_length": 27129, "output_length": 216, "hash_ids": [0, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785]}
{"timestamp": 45802, "input_length": 6579, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3786]}
{"timestamp": 45802, "input_length": 6172, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3787]}
{"timestamp": 45802, "input_length": 9065, "output_length": 30, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3788, 3789, 3790, 3791, 3792, 3793]}
{"timestamp": 45802, "input_length": 4193, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 3794, 3795, 3796, 3797]}
{"timestamp": 45802, "input_length": 2152, "output_length": 604, "hash_ids": [0, 3798, 3799, 3800, 3801]}
{"timestamp": 45802, "input_length": 6662, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3802, 3803]}
{"timestamp": 45802, "input_length": 6757, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3804, 3805]}
{"timestamp": 45802, "input_length": 11218, "output_length": 453, "hash_ids": [0, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826]}
{"timestamp": 48855, "input_length": 15394, "output_length": 534, "hash_ids": [0, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 3856]}
{"timestamp": 48855, "input_length": 3012, "output_length": 111, "hash_ids": [0, 1852, 1853, 1854, 1855, 3857]}
{"timestamp": 48855, "input_length": 3116, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 3858, 3859]}
{"timestamp": 48855, "input_length": 3131, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 3860, 3861]}
{"timestamp": 48855, "input_length": 7030, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3862, 3863]}
{"timestamp": 48855, "input_length": 49942, "output_length": 173, "hash_ids": [0, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935]}
{"timestamp": 48855, "input_length": 912, "output_length": 387, "hash_ids": [0, 3936]}
{"timestamp": 48855, "input_length": 3117, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 3937, 3938]}
{"timestamp": 48855, "input_length": 6756, "output_length": 38, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3939, 3940]}
{"timestamp": 48855, "input_length": 7027, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3941, 3942]}
{"timestamp": 48855, "input_length": 7175, "output_length": 41, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3943, 3944, 3945]}
{"timestamp": 48855, "input_length": 21275, "output_length": 111, "hash_ids": [0, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986]}
{"timestamp": 48855, "input_length": 6594, "output_length": 37, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3987]}
{"timestamp": 48855, "input_length": 7828, "output_length": 374, "hash_ids": [0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 3988, 3989]}
{"timestamp": 48855, "input_length": 7436, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3990, 3991, 3992]}
{"timestamp": 48855, "input_length": 943, "output_length": 536, "hash_ids": [0, 3993]}
{"timestamp": 48855, "input_length": 6326, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3994]}
{"timestamp": 48855, "input_length": 2983, "output_length": 436, "hash_ids": [0, 3995, 3996, 3997, 3998, 3999]}
{"timestamp": 51908, "input_length": 1081, "output_length": 481, "hash_ids": [0, 4000, 4001]}
{"timestamp": 51908, "input_length": 6171, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4002]}
{"timestamp": 51908, "input_length": 3962, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 4003, 4004, 4005]}
{"timestamp": 51908, "input_length": 13230, "output_length": 434, "hash_ids": [0, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030]}
{"timestamp": 51908, "input_length": 41004, "output_length": 575, "hash_ids": [0, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110]}
{"timestamp": 51908, "input_length": 24546, "output_length": 362, "hash_ids": [0, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157]}
{"timestamp": 51908, "input_length": 896, "output_length": 906, "hash_ids": [0, 4158]}
{"timestamp": 51908, "input_length": 1078, "output_length": 75, "hash_ids": [0, 4159, 4160]}
{"timestamp": 51908, "input_length": 6810, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4161, 4162]}
{"timestamp": 51908, "input_length": 3145, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 4163, 4164]}
{"timestamp": 51908, "input_length": 8099, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4165, 4166, 4167, 4168]}
{"timestamp": 51908, "input_length": 3916, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 4169, 4170, 4171]}
{"timestamp": 51908, "input_length": 5651, "output_length": 442, "hash_ids": [0, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, 4181, 4182]}
{"timestamp": 51908, "input_length": 6177, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4183]}
{"timestamp": 51908, "input_length": 5920, "output_length": 15, "hash_ids": [0, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194]}
{"timestamp": 54961, "input_length": 6172, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4195]}
{"timestamp": 54961, "input_length": 5097, "output_length": 413, "hash_ids": [0, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 4204]}
{"timestamp": 54961, "input_length": 3162, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 4205, 4206]}
{"timestamp": 54961, "input_length": 3299, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 4207, 4208]}
{"timestamp": 54961, "input_length": 6641, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4209]}
{"timestamp": 54961, "input_length": 6165, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4210]}
{"timestamp": 54961, "input_length": 2175, "output_length": 186, "hash_ids": [0, 4211, 4212, 4213, 4214]}
{"timestamp": 54961, "input_length": 10698, "output_length": 346, "hash_ids": [0, 4215, 4216, 4217, 4218, 4219, 4220, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234]}
{"timestamp": 54961, "input_length": 3159, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 4235, 4236]}
{"timestamp": 54961, "input_length": 9345, "output_length": 339, "hash_ids": [0, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, 4254]}
{"timestamp": 54961, "input_length": 3252, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 4255, 4256]}
{"timestamp": 54961, "input_length": 6863, "output_length": 45, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4257, 4258]}
{"timestamp": 54961, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4259]}
{"timestamp": 54961, "input_length": 3125, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 4260, 4261]}
{"timestamp": 54961, "input_length": 6180, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4262]}
{"timestamp": 54961, "input_length": 974, "output_length": 237, "hash_ids": [0, 4263]}
{"timestamp": 54961, "input_length": 6613, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4264]}
{"timestamp": 54961, "input_length": 18692, "output_length": 109, "hash_ids": [0, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 4300]}
{"timestamp": 58014, "input_length": 2012, "output_length": 302, "hash_ids": [0, 4301, 4302, 4303]}
{"timestamp": 58014, "input_length": 6193, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4304]}
{"timestamp": 58014, "input_length": 6411, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4305]}
{"timestamp": 58014, "input_length": 6547, "output_length": 254, "hash_ids": [0, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317]}
{"timestamp": 58014, "input_length": 3149, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 4318, 4319]}
{"timestamp": 58014, "input_length": 5676, "output_length": 35, "hash_ids": [0, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330]}
{"timestamp": 58014, "input_length": 6454, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4331]}
{"timestamp": 58014, "input_length": 7883, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4332, 4333, 4334, 4335]}
{"timestamp": 58014, "input_length": 6621, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4336]}
{"timestamp": 58014, "input_length": 1899, "output_length": 720, "hash_ids": [0, 4337, 4338, 4339]}
{"timestamp": 58014, "input_length": 1379, "output_length": 722, "hash_ids": [0, 4340, 4341]}
{"timestamp": 61070, "input_length": 3183, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 4342, 4343]}
{"timestamp": 61070, "input_length": 6956, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4344, 4345]}
{"timestamp": 61070, "input_length": 7718, "output_length": 191, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4346, 4347, 4348, 4349]}
{"timestamp": 61070, "input_length": 891, "output_length": 449, "hash_ids": [0, 4350]}
{"timestamp": 61070, "input_length": 6889, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4351, 4352]}
{"timestamp": 61070, "input_length": 7077, "output_length": 35, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4353, 4354]}
{"timestamp": 61070, "input_length": 11375, "output_length": 337, "hash_ids": [0, 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4372, 4373, 4374, 4375, 4376]}
{"timestamp": 61070, "input_length": 2707, "output_length": 359, "hash_ids": [0, 4377, 4378, 4379, 4380, 4381]}
{"timestamp": 61070, "input_length": 7164, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4382, 4383]}
{"timestamp": 61070, "input_length": 6165, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4384]}
{"timestamp": 61070, "input_length": 6991, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4385, 4386]}
{"timestamp": 64123, "input_length": 19771, "output_length": 161, "hash_ids": [0, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 4387]}
{"timestamp": 64123, "input_length": 3135, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 4388, 4389]}
{"timestamp": 64123, "input_length": 893, "output_length": 133, "hash_ids": [0, 4390]}
{"timestamp": 64123, "input_length": 18295, "output_length": 575, "hash_ids": [0, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425]}
{"timestamp": 64123, "input_length": 21612, "output_length": 467, "hash_ids": [0, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467]}
{"timestamp": 64123, "input_length": 7081, "output_length": 48, "hash_ids": [0, 4468, 4469, 4470, 4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480]}
{"timestamp": 64123, "input_length": 6787, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4481, 4482]}
{"timestamp": 67176, "input_length": 6454, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4483]}
{"timestamp": 67176, "input_length": 1527, "output_length": 513, "hash_ids": [0, 4484, 4485]}
{"timestamp": 67176, "input_length": 7339, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4486, 4487, 4488]}
{"timestamp": 67176, "input_length": 10930, "output_length": 247, "hash_ids": [0, 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509]}
{"timestamp": 67176, "input_length": 7011, "output_length": 53, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4510, 4511]}
{"timestamp": 67176, "input_length": 11954, "output_length": 463, "hash_ids": [0, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, 4522, 4523, 4524, 4525, 4526, 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534]}
{"timestamp": 67176, "input_length": 977, "output_length": 427, "hash_ids": [0, 4535]}
{"timestamp": 67176, "input_length": 7443, "output_length": 319, "hash_ids": [0, 4536, 4537, 4538, 4539, 4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549]}
{"timestamp": 67176, "input_length": 6486, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4550]}
{"timestamp": 67176, "input_length": 1071, "output_length": 481, "hash_ids": [0, 4551, 4552]}
{"timestamp": 67176, "input_length": 14310, "output_length": 364, "hash_ids": [0, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562]}
{"timestamp": 67176, "input_length": 102860, "output_length": 401, "hash_ids": [0, 4563, 4564, 4565, 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574, 4575, 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4626, 4627, 4628, 4629, 4630, 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, 4640, 4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689, 4690, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, 4700, 4701, 4702, 4703, 4704, 4705, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4714, 4715, 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, 4730, 4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4743, 4744, 4745, 4746, 4747, 4748, 4749, 4750, 4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, 4760, 4761, 4762]}
{"timestamp": 67176, "input_length": 75499, "output_length": 531, "hash_ids": [0, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, 4821, 4822, 4823, 4824, 4825, 4826, 4827, 4828, 4829, 4830, 4831, 4832, 4833, 4834, 4835, 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899, 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909]}
{"timestamp": 67176, "input_length": 15215, "output_length": 300, "hash_ids": [0, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 4910, 4911, 4912]}
{"timestamp": 67176, "input_length": 3063, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 4913]}
{"timestamp": 67176, "input_length": 6794, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4914, 4915]}
{"timestamp": 67176, "input_length": 7133, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4916, 4917]}
{"timestamp": 70228, "input_length": 10109, "output_length": 509, "hash_ids": [0, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936]}
{"timestamp": 70228, "input_length": 3150, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 4937, 4938]}
{"timestamp": 70228, "input_length": 7083, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4939, 4940]}
{"timestamp": 70228, "input_length": 4882, "output_length": 353, "hash_ids": [0, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949]}
{"timestamp": 70228, "input_length": 4573, "output_length": 225, "hash_ids": [0, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957]}
{"timestamp": 70228, "input_length": 892, "output_length": 334, "hash_ids": [0, 4958]}
{"timestamp": 70228, "input_length": 7746, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4959, 4960, 4961, 4962]}
{"timestamp": 70228, "input_length": 6942, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4963, 4964]}
{"timestamp": 70228, "input_length": 9916, "output_length": 356, "hash_ids": [0, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983]}
{"timestamp": 70228, "input_length": 1173, "output_length": 120, "hash_ids": [0, 4984, 4985]}
{"timestamp": 70228, "input_length": 6312, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4986]}
{"timestamp": 70228, "input_length": 9263, "output_length": 306, "hash_ids": [0, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 5004]}
{"timestamp": 70228, "input_length": 71917, "output_length": 433, "hash_ids": [0, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143, 5144]}
{"timestamp": 70228, "input_length": 1338, "output_length": 128, "hash_ids": [0, 5145, 5146]}
{"timestamp": 70228, "input_length": 2100, "output_length": 508, "hash_ids": [0, 1093, 5147, 5148, 5149]}
{"timestamp": 70228, "input_length": 16528, "output_length": 725, "hash_ids": [0, 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180, 5181]}
{"timestamp": 70228, "input_length": 6895, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5182, 5183]}
{"timestamp": 70228, "input_length": 3339, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 5184, 5185]}
{"timestamp": 70228, "input_length": 3223, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 5186, 5187]}
{"timestamp": 70228, "input_length": 3144, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 5188, 5189]}
{"timestamp": 73281, "input_length": 3150, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 5190, 5191]}
{"timestamp": 73281, "input_length": 17024, "output_length": 904, "hash_ids": [0, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199, 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224]}
{"timestamp": 73281, "input_length": 1623, "output_length": 578, "hash_ids": [0, 5225, 5226, 5227]}
{"timestamp": 73281, "input_length": 1531, "output_length": 356, "hash_ids": [0, 5228, 5229]}
{"timestamp": 73281, "input_length": 8423, "output_length": 19, "hash_ids": [0, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244, 5245]}
{"timestamp": 73281, "input_length": 3129, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 5246, 5247]}
{"timestamp": 73281, "input_length": 4073, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 5248, 5249, 5250]}
{"timestamp": 73281, "input_length": 3216, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 5251, 5252]}
{"timestamp": 73281, "input_length": 6586, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5253]}
{"timestamp": 73281, "input_length": 16877, "output_length": 431, "hash_ids": [0, 5254, 5255, 5256, 5257, 5258, 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274, 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, 5285]}
{"timestamp": 73281, "input_length": 4071, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 5286, 5287, 5288]}
{"timestamp": 73281, "input_length": 19949, "output_length": 448, "hash_ids": [0, 5289, 5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324, 5325, 5326]}
{"timestamp": 73281, "input_length": 1573, "output_length": 579, "hash_ids": [0, 5327, 5328, 5329]}
{"timestamp": 73281, "input_length": 9547, "output_length": 713, "hash_ids": [0, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 5330]}
{"timestamp": 73281, "input_length": 6508, "output_length": 565, "hash_ids": [0, 5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342]}
{"timestamp": 76334, "input_length": 13532, "output_length": 480, "hash_ids": [0, 5343, 5344, 5345, 5346, 5347, 5348, 5349, 5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, 5362, 5363, 5364, 5365, 5366, 5367, 5368]}
{"timestamp": 76334, "input_length": 896, "output_length": 286, "hash_ids": [0, 5369]}
{"timestamp": 76334, "input_length": 7168, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5370, 5371]}
{"timestamp": 76334, "input_length": 6295, "output_length": 413, "hash_ids": [0, 5372, 5373, 5374, 5375, 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383]}
{"timestamp": 76334, "input_length": 3211, "output_length": 26, "hash_ids": [74, 75, 76, 77, 78, 5384, 5385]}
{"timestamp": 76334, "input_length": 8760, "output_length": 121, "hash_ids": [0, 5386, 5387, 5388, 5389, 5390, 5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402]}
{"timestamp": 76334, "input_length": 38147, "output_length": 316, "hash_ids": [0, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, 5422, 5423, 5424, 5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449, 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5469, 5470, 5471, 5472, 5473, 5474, 5475, 5476]}
{"timestamp": 76334, "input_length": 5077, "output_length": 476, "hash_ids": [0, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5484, 5485]}
{"timestamp": 76334, "input_length": 6990, "output_length": 461, "hash_ids": [0, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, 5495, 5496, 5497, 5498]}
{"timestamp": 76334, "input_length": 37873, "output_length": 532, "hash_ids": [0, 5499, 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524, 5525, 5526, 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, 5571]}
{"timestamp": 76334, "input_length": 17577, "output_length": 464, "hash_ids": [0, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, 5600, 5601, 5602, 5603, 5604, 5605]}
{"timestamp": 76334, "input_length": 17793, "output_length": 576, "hash_ids": [0, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639]}
{"timestamp": 76334, "input_length": 14331, "output_length": 501, "hash_ids": [0, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666]}
{"timestamp": 76334, "input_length": 8629, "output_length": 835, "hash_ids": [0, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682]}
{"timestamp": 76334, "input_length": 6521, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5683]}
{"timestamp": 76334, "input_length": 920, "output_length": 452, "hash_ids": [0, 5684]}
{"timestamp": 76334, "input_length": 964, "output_length": 637, "hash_ids": [0, 5685]}
{"timestamp": 76334, "input_length": 13984, "output_length": 315, "hash_ids": [0, 5686, 5687, 5688, 5689, 5690, 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699, 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709, 5710, 5711, 5712]}
{"timestamp": 76334, "input_length": 7306, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5713, 5714, 5715]}
{"timestamp": 76334, "input_length": 6532, "output_length": 442, "hash_ids": [0, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 5716, 5717]}
{"timestamp": 79390, "input_length": 51114, "output_length": 620, "hash_ids": [0, 5718, 5719, 5720, 5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814, 5815, 5816]}
{"timestamp": 79390, "input_length": 3159, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 5817, 5818]}
{"timestamp": 79390, "input_length": 4208, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 5819, 5820, 5821, 5822]}
{"timestamp": 79390, "input_length": 6178, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5823]}
{"timestamp": 79390, "input_length": 16964, "output_length": 526, "hash_ids": [0, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 5824, 5825, 5826, 5827, 5828]}
{"timestamp": 79390, "input_length": 3132, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 5829, 5830]}
{"timestamp": 79390, "input_length": 6522, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5831]}
{"timestamp": 79390, "input_length": 3128, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 5832, 5833]}
{"timestamp": 79390, "input_length": 6221, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5834]}
{"timestamp": 79390, "input_length": 45064, "output_length": 109, "hash_ids": [0, 5835, 5836, 5837, 5838, 5839, 5840, 5841, 5842, 5843, 5844, 5845, 5846, 5847, 5848, 5849, 5850, 5851, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 5859, 5860, 5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, 5871, 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, 5920, 5921, 5922]}
{"timestamp": 79390, "input_length": 6686, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5923, 5924]}
{"timestamp": 79390, "input_length": 7087, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5925, 5926]}
{"timestamp": 79390, "input_length": 6487, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5927]}
{"timestamp": 79390, "input_length": 7116, "output_length": 51, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5928, 5929]}
{"timestamp": 79390, "input_length": 5383, "output_length": 545, "hash_ids": [0, 5930, 5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939]}
{"timestamp": 79390, "input_length": 6449, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5940]}
{"timestamp": 79390, "input_length": 6164, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5941]}
{"timestamp": 79390, "input_length": 6593, "output_length": 57, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5942]}
{"timestamp": 79390, "input_length": 6214, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5943]}
{"timestamp": 79390, "input_length": 6169, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5944]}
{"timestamp": 82443, "input_length": 7256, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5945, 5946, 5947]}
{"timestamp": 82443, "input_length": 6735, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5948, 5949]}
{"timestamp": 82443, "input_length": 1359, "output_length": 480, "hash_ids": [0, 5950, 5951]}
{"timestamp": 82443, "input_length": 22072, "output_length": 367, "hash_ids": [0, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974, 5975, 5976, 5977, 5978, 5979, 5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, 5991, 5992, 5993, 5994]}
{"timestamp": 82443, "input_length": 6175, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 5995]}
{"timestamp": 82443, "input_length": 1638, "output_length": 567, "hash_ids": [0, 5996, 5997, 5998]}
{"timestamp": 82443, "input_length": 3213, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 5999, 6000]}
{"timestamp": 82443, "input_length": 4299, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 6001, 6002, 6003, 6004]}
{"timestamp": 82443, "input_length": 4380, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 6005, 6006, 6007, 6008]}
{"timestamp": 82443, "input_length": 3245, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 6009, 6010]}
{"timestamp": 82443, "input_length": 13104, "output_length": 172, "hash_ids": [0, 3406, 3407, 3408, 3409, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024, 6025, 6026, 6027, 6028, 6029, 6030, 6031]}
{"timestamp": 82443, "input_length": 4047, "output_length": 547, "hash_ids": [0, 6032, 6033, 6034, 6035, 6036, 6037, 6038]}
{"timestamp": 82443, "input_length": 904, "output_length": 28, "hash_ids": [0, 6039]}
{"timestamp": 82443, "input_length": 7214, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6040, 6041, 6042]}
{"timestamp": 82443, "input_length": 6178, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6043]}
{"timestamp": 82443, "input_length": 6453, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6044]}
{"timestamp": 82443, "input_length": 3706, "output_length": 300, "hash_ids": [0, 6045, 6046, 6047, 6048, 6049, 6050, 6051]}
{"timestamp": 82443, "input_length": 6187, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6052]}
{"timestamp": 82443, "input_length": 6679, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6053, 6054]}
{"timestamp": 82443, "input_length": 6169, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6055]}
{"timestamp": 82443, "input_length": 23987, "output_length": 645, "hash_ids": [0, 6056, 6057, 6058, 6059, 6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077, 6078, 6079, 6080, 6081, 6082, 6083, 6084, 6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100, 6101]}
{"timestamp": 82443, "input_length": 4531, "output_length": 521, "hash_ids": [0, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109]}
{"timestamp": 82443, "input_length": 6167, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6110]}
{"timestamp": 82443, "input_length": 25075, "output_length": 284, "hash_ids": [0, 6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, 6141, 6142, 6143, 6144, 6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158]}
{"timestamp": 85496, "input_length": 7904, "output_length": 510, "hash_ids": [0, 6159, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173]}
{"timestamp": 85496, "input_length": 89831, "output_length": 556, "hash_ids": [0, 6174, 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199, 6200, 6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, 6249, 6250, 6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, 6260, 6261, 6262, 6263, 6264, 6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274, 6275, 6276, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6323, 6324, 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348]}
{"timestamp": 85496, "input_length": 6296, "output_length": 165, "hash_ids": [0, 6349, 6350, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360]}
{"timestamp": 85496, "input_length": 6177, "output_length": 44, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6361]}
{"timestamp": 85496, "input_length": 6805, "output_length": 196, "hash_ids": [0, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, 6373, 6374]}
{"timestamp": 85496, "input_length": 7168, "output_length": 26, "hash_ids": [0, 4468, 4469, 4470, 4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479, 6375]}
{"timestamp": 85496, "input_length": 20481, "output_length": 362, "hash_ids": [0, 6376, 6377, 6378, 6379, 6380, 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399, 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, 6411, 6412, 6413, 6414, 6415]}
{"timestamp": 85496, "input_length": 1368, "output_length": 427, "hash_ids": [0, 6416, 6417]}
{"timestamp": 85496, "input_length": 10086, "output_length": 421, "hash_ids": [0, 6418, 6419, 6420, 6421, 6422, 6423, 6424, 6425, 6426, 6427, 6428, 6429, 6430, 6431, 6432, 6433, 6434, 6435, 6436]}
{"timestamp": 85496, "input_length": 18054, "output_length": 428, "hash_ids": [0, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, 6471]}
{"timestamp": 85496, "input_length": 6166, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6472]}
{"timestamp": 85496, "input_length": 6251, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6473]}
{"timestamp": 85496, "input_length": 75081, "output_length": 456, "hash_ids": [0, 6474, 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, 6500, 6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519, 6520, 6521, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, 6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574, 6575, 6576, 6577, 6578, 6579, 6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, 6591, 6592, 6593, 6594, 6595, 6596, 6597, 6598, 6599, 6600, 6601, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619]}
{"timestamp": 85496, "input_length": 7056, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6620, 6621]}
{"timestamp": 85496, "input_length": 7353, "output_length": 44, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6622, 6623, 6624]}
{"timestamp": 88549, "input_length": 891, "output_length": 78, "hash_ids": [0, 6625]}
{"timestamp": 88549, "input_length": 11399, "output_length": 445, "hash_ids": [0, 2584, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, 6643, 6644, 6645, 6646]}
{"timestamp": 88549, "input_length": 7757, "output_length": 328, "hash_ids": [0, 6647, 6648, 6649, 6650, 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, 6661]}
{"timestamp": 88549, "input_length": 14782, "output_length": 409, "hash_ids": [0, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, 6687, 6688, 6689]}
{"timestamp": 88549, "input_length": 6311, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6690]}
{"timestamp": 88549, "input_length": 1032, "output_length": 183, "hash_ids": [0, 6691, 6692]}
{"timestamp": 88549, "input_length": 3155, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 6693, 6694]}
{"timestamp": 88549, "input_length": 7010, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6695, 6696]}
{"timestamp": 88549, "input_length": 6689, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6697, 6698]}
{"timestamp": 88549, "input_length": 7217, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6699, 6700, 6701]}
{"timestamp": 88549, "input_length": 6857, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6702, 6703]}
{"timestamp": 88549, "input_length": 19661, "output_length": 445, "hash_ids": [0, 6704, 6705, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, 6740, 6741]}
{"timestamp": 88549, "input_length": 1306, "output_length": 111, "hash_ids": [0, 6742, 6743]}
{"timestamp": 88549, "input_length": 2512, "output_length": 549, "hash_ids": [0, 6744, 6745, 6746, 6747]}
{"timestamp": 88549, "input_length": 16704, "output_length": 445, "hash_ids": [0, 6748, 6749, 6750, 6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774, 6775, 6776, 6777, 6778, 6779]}
{"timestamp": 88549, "input_length": 1756, "output_length": 431, "hash_ids": [0, 6780, 6781, 6782]}
{"timestamp": 88549, "input_length": 2958, "output_length": 16, "hash_ids": [74, 75, 76, 77, 78, 6783]}
{"timestamp": 88549, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6784]}
{"timestamp": 88549, "input_length": 903, "output_length": 28, "hash_ids": [0, 6785]}
{"timestamp": 88549, "input_length": 1884, "output_length": 312, "hash_ids": [0, 6786, 6787, 6788]}
{"timestamp": 88549, "input_length": 17871, "output_length": 881, "hash_ids": [0, 6789, 6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822]}
{"timestamp": 91602, "input_length": 3951, "output_length": 297, "hash_ids": [0, 3995, 3996, 3997, 3998, 6823, 6824, 6825]}
{"timestamp": 91602, "input_length": 1900, "output_length": 654, "hash_ids": [0, 1264, 1265, 1266]}
{"timestamp": 91602, "input_length": 3135, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 6826, 6827]}
{"timestamp": 91602, "input_length": 6624, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 6828]}
{"timestamp": 91602, "input_length": 27288, "output_length": 268, "hash_ids": [0, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, 6981]}
{"timestamp": 91602, "input_length": 9404, "output_length": 555, "hash_ids": [0, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999]}
{"timestamp": 91602, "input_length": 7005, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7000, 7001]}
{"timestamp": 91602, "input_length": 7192, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7002, 7003, 7004]}
{"timestamp": 91602, "input_length": 12432, "output_length": 1644, "hash_ids": [0, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028]}
{"timestamp": 91602, "input_length": 5234, "output_length": 534, "hash_ids": [0, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038]}
{"timestamp": 91602, "input_length": 7364, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7039, 7040, 7041]}
{"timestamp": 91602, "input_length": 6587, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7042]}
{"timestamp": 91602, "input_length": 3130, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 7043, 7044]}
{"timestamp": 91602, "input_length": 7023, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7049, 7050]}
{"timestamp": 91602, "input_length": 54999, "output_length": 644, "hash_ids": [0, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157]}
{"timestamp": 91602, "input_length": 6272, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7158]}
{"timestamp": 91602, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7159]}
{"timestamp": 91602, "input_length": 6172, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7160]}
{"timestamp": 91602, "input_length": 39379, "output_length": 243, "hash_ids": [0, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199, 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, 7235, 7236]}
{"timestamp": 94654, "input_length": 901, "output_length": 171, "hash_ids": [0, 7237]}
{"timestamp": 94654, "input_length": 6201, "output_length": 30, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7306]}
{"timestamp": 94654, "input_length": 6785, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7307, 7308]}
{"timestamp": 94654, "input_length": 6845, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7309, 7310]}
{"timestamp": 94654, "input_length": 2779, "output_length": 415, "hash_ids": [0, 7311, 7312, 7313, 7314, 7315]}
{"timestamp": 94654, "input_length": 9173, "output_length": 531, "hash_ids": [0, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332]}
{"timestamp": 94654, "input_length": 36032, "output_length": 632, "hash_ids": [0, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, 7400, 7401, 7402]}
{"timestamp": 97707, "input_length": 13881, "output_length": 775, "hash_ids": [0, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429]}
{"timestamp": 97707, "input_length": 8759, "output_length": 449, "hash_ids": [0, 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446]}
{"timestamp": 97707, "input_length": 7726, "output_length": 347, "hash_ids": [0, 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461]}
{"timestamp": 97707, "input_length": 6169, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7462]}
{"timestamp": 97707, "input_length": 6619, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7463]}
{"timestamp": 97707, "input_length": 2996, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 7464]}
{"timestamp": 97707, "input_length": 6168, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7465]}
{"timestamp": 97707, "input_length": 6565, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7466]}
{"timestamp": 97707, "input_length": 13741, "output_length": 304, "hash_ids": [0, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492]}
{"timestamp": 97707, "input_length": 6873, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7493, 7494]}
{"timestamp": 97707, "input_length": 895, "output_length": 94, "hash_ids": [0, 7495]}
{"timestamp": 97707, "input_length": 2966, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 7496]}
{"timestamp": 97707, "input_length": 6167, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7497]}
{"timestamp": 97707, "input_length": 4021, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 7498, 7499, 7500]}
{"timestamp": 97707, "input_length": 7613, "output_length": 435, "hash_ids": [0, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514]}
{"timestamp": 97707, "input_length": 3129, "output_length": 398, "hash_ids": [0, 1852, 1853, 1854, 1855, 7515, 7516]}
{"timestamp": 97707, "input_length": 24114, "output_length": 2000, "hash_ids": [0, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563]}
{"timestamp": 100764, "input_length": 4689, "output_length": 446, "hash_ids": [0, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572]}
{"timestamp": 100764, "input_length": 3353, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 1717, 7573]}
{"timestamp": 100764, "input_length": 6624, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7574]}
{"timestamp": 100764, "input_length": 7294, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3242, 3243, 3244]}
{"timestamp": 100764, "input_length": 6174, "output_length": 32, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7575]}
{"timestamp": 100764, "input_length": 19060, "output_length": 247, "hash_ids": [0, 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612]}
{"timestamp": 100764, "input_length": 898, "output_length": 418, "hash_ids": [0, 7613]}
{"timestamp": 100764, "input_length": 6654, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7614]}
{"timestamp": 100764, "input_length": 7124, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7615, 7616]}
{"timestamp": 100764, "input_length": 6179, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7617]}
{"timestamp": 100764, "input_length": 6554, "output_length": 20, "hash_ids": [0, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 7629]}
{"timestamp": 100764, "input_length": 50458, "output_length": 621, "hash_ids": [0, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 7630, 7631]}
{"timestamp": 100764, "input_length": 3023, "output_length": 673, "hash_ids": [0, 7632, 7633, 7634, 7635, 7636]}
{"timestamp": 100764, "input_length": 3098, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 7637, 7638]}
{"timestamp": 100764, "input_length": 6176, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7639]}
{"timestamp": 100764, "input_length": 913, "output_length": 275, "hash_ids": [0, 7640]}
{"timestamp": 100764, "input_length": 14414, "output_length": 385, "hash_ids": [0, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 7641, 7642]}
{"timestamp": 100764, "input_length": 17176, "output_length": 595, "hash_ids": [0, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, 7675]}
{"timestamp": 103816, "input_length": 67085, "output_length": 358, "hash_ids": [0, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774, 7775, 7776, 7777, 7778, 7779, 7780, 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, 7805, 7806]}
{"timestamp": 103816, "input_length": 4332, "output_length": 29, "hash_ids": [74, 75, 76, 77, 78, 7807, 7808, 7809, 7810]}
{"timestamp": 103816, "input_length": 6533, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7811]}
{"timestamp": 103816, "input_length": 10267, "output_length": 269, "hash_ids": [0, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831]}
{"timestamp": 103816, "input_length": 13619, "output_length": 510, "hash_ids": [0, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 7832, 7833, 7834, 7835]}
{"timestamp": 103816, "input_length": 7277, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7836, 7837, 7838]}
{"timestamp": 103816, "input_length": 6179, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7839]}
{"timestamp": 103816, "input_length": 3170, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 7840, 7841]}
{"timestamp": 103816, "input_length": 8651, "output_length": 831, "hash_ids": [0, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857]}
{"timestamp": 103816, "input_length": 24479, "output_length": 306, "hash_ids": [0, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899, 7900, 7901, 7902, 7903, 7904]}
{"timestamp": 103816, "input_length": 6651, "output_length": 38, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 7905]}
{"timestamp": 103816, "input_length": 69267, "output_length": 430, "hash_ids": [0, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924, 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 7985, 7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8024, 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039, 8040]}
{"timestamp": 103816, "input_length": 3374, "output_length": 617, "hash_ids": [0, 1842, 1843, 1844, 1845, 1846, 8041]}
{"timestamp": 103816, "input_length": 977, "output_length": 140, "hash_ids": [0, 8042]}
{"timestamp": 103816, "input_length": 6439, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8043]}
{"timestamp": 103816, "input_length": 4741, "output_length": 541, "hash_ids": [0, 8044, 8045, 8046, 8047, 8048, 8049, 8050, 8051, 8052]}
{"timestamp": 103816, "input_length": 7714, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8053, 8054, 8055, 8056]}
{"timestamp": 103816, "input_length": 6338, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8057]}
{"timestamp": 103816, "input_length": 6710, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8058, 8059]}
{"timestamp": 103816, "input_length": 3143, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 8060, 8061]}
{"timestamp": 103816, "input_length": 4989, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 8062, 8063, 8064, 8065, 8066]}
{"timestamp": 103816, "input_length": 6673, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8067, 8068]}
{"timestamp": 106869, "input_length": 28828, "output_length": 634, "hash_ids": [0, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 8069, 8070]}
{"timestamp": 106869, "input_length": 6568, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8071]}
{"timestamp": 106869, "input_length": 3289, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 8072, 8073]}
{"timestamp": 106869, "input_length": 6180, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8074]}
{"timestamp": 106869, "input_length": 6700, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8075, 8076]}
{"timestamp": 106869, "input_length": 3171, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 8077, 8078]}
{"timestamp": 106869, "input_length": 3016, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 8079]}
{"timestamp": 106869, "input_length": 7559, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8080, 8081, 8082]}
{"timestamp": 106869, "input_length": 7566, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8083, 8084, 8085]}
{"timestamp": 106869, "input_length": 6417, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8086]}
{"timestamp": 106869, "input_length": 11834, "output_length": 382, "hash_ids": [0, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, 8087, 8088, 8089, 8090, 8091, 8092]}
{"timestamp": 106869, "input_length": 3145, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 8093, 8094]}
{"timestamp": 106869, "input_length": 3168, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 8095, 8096]}
{"timestamp": 106869, "input_length": 6677, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8097, 8098]}
{"timestamp": 106869, "input_length": 6171, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8099]}
{"timestamp": 106869, "input_length": 6714, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8100, 8101]}
{"timestamp": 106869, "input_length": 6704, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8102, 8103]}
{"timestamp": 106869, "input_length": 21393, "output_length": 384, "hash_ids": [0, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 8104]}
{"timestamp": 106869, "input_length": 3939, "output_length": 515, "hash_ids": [0, 8105, 8106, 8107, 8108, 8109, 8110, 8111]}
{"timestamp": 109922, "input_length": 8503, "output_length": 38, "hash_ids": [0, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244, 8112]}
{"timestamp": 109922, "input_length": 6166, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8113]}
{"timestamp": 109922, "input_length": 6193, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8114]}
{"timestamp": 109922, "input_length": 3152, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 8115, 8116]}
{"timestamp": 109922, "input_length": 6173, "output_length": 32, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8117]}
{"timestamp": 109922, "input_length": 26711, "output_length": 370, "hash_ids": [0, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 8118, 8119]}
{"timestamp": 109922, "input_length": 12583, "output_length": 387, "hash_ids": [0, 8120, 8121, 8122, 8123, 8124, 8125, 8126, 8127, 8128, 8129, 8130, 8131, 8132, 8133, 8134, 8135, 8136, 8137, 8138, 8139, 8140, 8141, 8142, 8143]}
{"timestamp": 109922, "input_length": 1658, "output_length": 93, "hash_ids": [0, 5145, 8144, 8145]}
{"timestamp": 109922, "input_length": 7059, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8146, 8147]}
{"timestamp": 109922, "input_length": 3507, "output_length": 760, "hash_ids": [0, 3180, 3181, 3182, 3183, 8148, 8149]}
{"timestamp": 109922, "input_length": 20181, "output_length": 124, "hash_ids": [0, 8150, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174, 8175, 8176, 8177, 8178, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188]}
{"timestamp": 109922, "input_length": 14979, "output_length": 32, "hash_ids": [0, 8189, 8190, 8191, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8203, 8204, 8205, 8206, 8207, 8208, 8209, 8210, 8211, 8212, 8213, 8214, 8215, 8216, 8217]}
{"timestamp": 109922, "input_length": 6172, "output_length": 29, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8218]}
{"timestamp": 109922, "input_length": 13689, "output_length": 527, "hash_ids": [0, 8219, 8220, 8221, 8222, 8223, 8224, 8225, 8226, 8227, 8228, 8229, 8230, 8231, 8232, 8233, 8234, 8235, 8236, 8237, 8238, 8239, 8240, 8241, 8242, 8243, 8244]}
{"timestamp": 109922, "input_length": 8036, "output_length": 457, "hash_ids": [0, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 8245]}
{"timestamp": 112978, "input_length": 9312, "output_length": 644, "hash_ids": [0, 8249, 8250, 8251, 8252, 8253, 8254, 8255, 8256, 8257, 8258, 8259, 8260, 8261, 8262, 8263, 8264, 8265, 8266]}
{"timestamp": 112978, "input_length": 7224, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8267, 8268, 8269]}
{"timestamp": 112978, "input_length": 7002, "output_length": 34, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8270, 8271]}
{"timestamp": 112978, "input_length": 14306, "output_length": 57, "hash_ids": [0, 8272, 8273, 8274, 8275, 8276, 8277, 8278, 8279, 8280, 8281, 8282, 8283, 8284, 8285, 8286, 8287, 8288, 8289, 8290, 8291, 8292, 8293, 8294, 8295, 8296, 8297, 8298]}
{"timestamp": 112978, "input_length": 7083, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8299, 8300]}
{"timestamp": 112978, "input_length": 1057, "output_length": 60, "hash_ids": [0, 8301, 8302]}
{"timestamp": 112978, "input_length": 9530, "output_length": 529, "hash_ids": [0, 8303, 8304, 8305, 8306, 8307, 8308, 8309, 8310, 8311, 8312, 8313, 8314, 8315, 8316, 8317, 8318, 8319, 8320]}
{"timestamp": 112978, "input_length": 3178, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 8321, 8322]}
{"timestamp": 112978, "input_length": 33985, "output_length": 521, "hash_ids": [0, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 8325, 8326, 8327, 8328, 8329, 8330, 8331, 8332, 8333, 8334, 8335, 8336, 8337, 8338, 8339, 8340, 8341, 8342, 8343, 8344, 8345, 8346, 8347]}
{"timestamp": 112978, "input_length": 5234, "output_length": 111, "hash_ids": [0, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038]}
{"timestamp": 112978, "input_length": 6932, "output_length": 51, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8348, 8349]}
{"timestamp": 112978, "input_length": 23969, "output_length": 553, "hash_ids": [0, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 8350, 8351, 8352, 8353, 8354, 8355, 8356, 8357, 8358, 8359, 8360, 8361, 8362, 8363, 8364, 8365, 8366]}
{"timestamp": 112978, "input_length": 6706, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8374, 8375]}
{"timestamp": 112978, "input_length": 6883, "output_length": 366, "hash_ids": [0, 8376, 8377, 8378, 8379, 8380, 8381, 8382, 8383, 8384, 8385, 8386, 8387, 8388]}
{"timestamp": 112978, "input_length": 6951, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8389, 8390]}
{"timestamp": 116028, "input_length": 10597, "output_length": 123, "hash_ids": [0, 8488, 8489, 8490, 8491, 8492, 8493, 8494, 8495, 8496, 8497, 8498, 8499, 8500, 8501, 8502, 8503, 8504, 8505, 8506, 8507]}
{"timestamp": 116028, "input_length": 6172, "output_length": 29, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8508]}
{"timestamp": 116028, "input_length": 115593, "output_length": 271, "hash_ids": [0, 8509, 8510, 8511, 8512, 8513, 8514, 8515, 8516, 8517, 8518, 8519, 8520, 8521, 8522, 8523, 8524, 8525, 8526, 8527, 8528, 8529, 8530, 8531, 8532, 8533, 8534, 8535, 8536, 8537, 8538, 8539, 8540, 8541, 8542, 8543, 8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 8554, 8555, 8556, 8557, 8558, 8559, 8560, 8561, 8562, 8563, 8564, 8565, 8566, 8567, 8568, 8569, 8570, 8571, 8572, 8573, 8574, 8575, 8576, 8577, 8578, 8579, 8580, 8581, 8582, 8583, 8584, 8585, 8586, 8587, 8588, 8589, 8590, 8591, 8592, 8593, 8594, 8595, 8596, 8597, 8598, 8599, 8600, 8601, 8602, 8603, 8604, 8605, 8606, 8607, 8608, 8609, 8610, 8611, 8612, 8613, 8614, 8615, 8616, 8617, 8618, 8619, 8620, 8621, 8622, 8623, 8624, 8625, 8626, 8627, 8628, 8629, 8630, 8631, 8632, 8633, 8634, 8635, 8636, 8637, 8638, 8639, 8640, 8641, 8642, 8643, 8644, 8645, 8646, 8647, 8648, 8649, 8650, 8651, 8652, 8653, 8654, 8655, 8656, 8657, 8658, 8659, 8660, 8661, 8662, 8663, 8664, 8665, 8666, 8667, 8668, 8669, 8670, 8671, 8672, 8673, 8674, 8675, 8676, 8677, 8678, 8679, 8680, 8681, 8682, 8683, 8684, 8685, 8686, 8687, 8688, 8689, 8690, 8691, 8692, 8693, 8694, 8695, 8696, 8697, 8698, 8699, 8700, 8701, 8702, 8703, 8704, 8705, 8706, 8707, 8708, 8709, 8710, 8711, 8712, 8713, 8714, 8715, 8716, 8717, 8718, 8719, 8720, 8721, 8722, 8723, 8724, 8725, 8726, 8727, 8728, 8729, 8730, 8731, 8732, 8733]}
{"timestamp": 116028, "input_length": 24806, "output_length": 614, "hash_ids": [0, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 8734, 8735, 8736, 8737]}
{"timestamp": 116028, "input_length": 40531, "output_length": 356, "hash_ids": [0, 8738, 8739, 8740, 8741, 8742, 8743, 8744, 8745, 8746, 8747, 8748, 8749, 8750, 8751, 8752, 8753, 8754, 8755, 8756, 8757, 8758, 8759, 8760, 8761, 8762, 8763, 8764, 8765, 8766, 8767, 8768, 8769, 8770, 8771, 8772, 8773, 8774, 8775, 8776, 8777, 8778, 8779, 8780, 8781, 8782, 8783, 8784, 8785, 8786, 8787, 8788, 8789, 8790, 8791, 8792, 8793, 8794, 8795, 8796, 8797, 8798, 8799, 8800, 8801, 8802, 8803, 8804, 8805, 8806, 8807, 8808, 8809, 8810, 8811, 8812, 8813, 8814, 8815, 8816]}
{"timestamp": 116028, "input_length": 7173, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 1907, 1908, 1909]}
{"timestamp": 116028, "input_length": 13705, "output_length": 394, "hash_ids": [0, 8817, 8818, 8819, 8820, 8821, 8822, 8823, 8824, 8825, 8826, 8827, 8828, 8829, 8830, 8831, 8832, 8833, 8834, 8835, 8836, 8837, 8838, 8839, 8840, 8841, 8842]}
{"timestamp": 116028, "input_length": 7490, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8843, 8844, 8845]}
{"timestamp": 116028, "input_length": 7040, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8846, 8847]}
{"timestamp": 116028, "input_length": 20145, "output_length": 662, "hash_ids": [0, 8848, 8849, 8850, 8851, 8852, 8853, 8854, 8855, 8856, 8857, 8858, 8859, 8860, 8861, 8862, 8863, 8864, 8865, 8866, 8867, 8868, 8869, 8870, 8871, 8872, 8873, 8874, 8875, 8876, 8877, 8878, 8879, 8880, 8881, 8882, 8883, 8884, 8885, 8886]}
{"timestamp": 116028, "input_length": 6300, "output_length": 104, "hash_ids": [0, 8887, 8888, 8889, 8890, 8891, 8892, 8893, 8894, 8895, 8896, 8897, 8898]}
{"timestamp": 116028, "input_length": 4239, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 8899, 8900, 8901, 8902]}
{"timestamp": 116028, "input_length": 7294, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 3242, 3243, 3244]}
{"timestamp": 116028, "input_length": 6172, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8903]}
{"timestamp": 116028, "input_length": 6056, "output_length": 128, "hash_ids": [0, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 8904]}
{"timestamp": 119084, "input_length": 898, "output_length": 200, "hash_ids": [0, 8905]}
{"timestamp": 119084, "input_length": 1214, "output_length": 384, "hash_ids": [0, 8906, 8907]}
{"timestamp": 119084, "input_length": 28618, "output_length": 372, "hash_ids": [0, 8908, 8909, 8910, 8911, 8912, 8913, 8914, 8915, 8916, 8917, 8918, 8919, 8920, 8921, 8922, 8923, 8924, 8925, 8926, 8927, 8928, 8929, 8930, 8931, 8932, 8933, 8934, 8935, 8936, 8937, 8938, 8939, 8940, 8941, 8942, 8943, 8944, 8945, 8946, 8947, 8948, 8949, 8950, 8951, 8952, 8953, 8954, 8955, 8956, 8957, 8958, 8959, 8960, 8961, 8962]}
{"timestamp": 119084, "input_length": 7334, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8963, 8964, 8965]}
{"timestamp": 119084, "input_length": 1884, "output_length": 407, "hash_ids": [0, 8966, 8967, 8968]}
{"timestamp": 119084, "input_length": 7109, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8969, 8970]}
{"timestamp": 119084, "input_length": 6165, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9041]}
{"timestamp": 119084, "input_length": 1430, "output_length": 90, "hash_ids": [0, 6742, 9042]}
{"timestamp": 119084, "input_length": 3137, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 9043, 9044]}
{"timestamp": 119084, "input_length": 6176, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9045]}
{"timestamp": 119084, "input_length": 6277, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9046]}
{"timestamp": 119084, "input_length": 3025, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 9047]}
{"timestamp": 119084, "input_length": 7491, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9048, 9049, 9050]}
{"timestamp": 122137, "input_length": 6175, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9051]}
{"timestamp": 122137, "input_length": 3106, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 9052, 9053]}
{"timestamp": 122137, "input_length": 6527, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9054]}
{"timestamp": 122137, "input_length": 3381, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 9055, 9056]}
{"timestamp": 122137, "input_length": 892, "output_length": 349, "hash_ids": [0, 9057]}
{"timestamp": 122137, "input_length": 35084, "output_length": 618, "hash_ids": [0, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193]}
{"timestamp": 122137, "input_length": 18878, "output_length": 327, "hash_ids": [0, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 9058]}
{"timestamp": 122137, "input_length": 6925, "output_length": 303, "hash_ids": [0, 9059, 9060, 9061, 9062, 9063, 9064, 9065, 9066, 9067, 9068, 9069, 9070, 9071]}
{"timestamp": 122137, "input_length": 7984, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9072, 9073, 9074, 9075]}
{"timestamp": 122137, "input_length": 894, "output_length": 354, "hash_ids": [0, 9076]}
{"timestamp": 122137, "input_length": 8395, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9077, 9078, 9079, 9080, 9081]}
{"timestamp": 122137, "input_length": 6674, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9082, 9083]}
{"timestamp": 122137, "input_length": 893, "output_length": 301, "hash_ids": [0, 9084]}
{"timestamp": 122137, "input_length": 6171, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9085]}
{"timestamp": 125190, "input_length": 7180, "output_length": 41, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9086, 9087, 9088]}
{"timestamp": 125190, "input_length": 6175, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9089]}
{"timestamp": 125190, "input_length": 10240, "output_length": 504, "hash_ids": [0, 9090, 9091, 9092, 9093, 9094, 9095, 9096, 9097, 9098, 9099, 9100, 9101, 9102, 9103, 9104, 9105, 9106, 9107, 9108]}
{"timestamp": 125190, "input_length": 3178, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 9109, 9110]}
{"timestamp": 125190, "input_length": 1173, "output_length": 401, "hash_ids": [0, 9112, 9113]}
{"timestamp": 125190, "input_length": 7000, "output_length": 29, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9114, 9115]}
{"timestamp": 125190, "input_length": 1409, "output_length": 369, "hash_ids": [0, 9116, 9117]}
{"timestamp": 125190, "input_length": 19451, "output_length": 510, "hash_ids": [0, 9118, 9119, 9120, 9121, 9122, 9123, 9124, 9125, 9126, 9127, 9128, 9129, 9130, 9131, 9132, 9133, 9134, 9135, 9136, 9137, 9138, 9139, 9140, 9141, 9142, 9143, 9144, 9145, 9146, 9147, 9148, 9149, 9150, 9151, 9152, 9153, 9154]}
{"timestamp": 125190, "input_length": 3119, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 9155, 9156]}
{"timestamp": 128242, "input_length": 3116, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 9157, 9158]}
{"timestamp": 128242, "input_length": 10045, "output_length": 172, "hash_ids": [0, 9159, 9160, 9161, 9162, 9163, 9164, 9165, 9166, 9167, 9168, 9169, 9170, 9171, 9172, 9173, 9174, 9175, 9176, 9177]}
{"timestamp": 128242, "input_length": 8839, "output_length": 225, "hash_ids": [0, 9178, 9179, 9180, 9181, 9182, 9183, 9184, 9185, 9186, 9187, 9188, 9189, 9190, 9191, 9192, 9193, 9194]}
{"timestamp": 128242, "input_length": 24630, "output_length": 110, "hash_ids": [0, 9195, 9196, 9197, 9198, 9199, 9200, 9201, 9202, 9203, 9204, 9205, 9206, 9207, 9208, 9209, 9210, 9211, 9212, 9213, 9214, 9215, 9216, 9217, 9218, 9219, 9220, 9221, 9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, 9232, 9233, 9234, 9235, 9236, 9237, 9238, 9239, 9240, 9241, 9242]}
{"timestamp": 128242, "input_length": 6622, "output_length": 465, "hash_ids": [0, 9243, 9244, 9245, 9246, 9247, 9248, 9249, 9250, 9251, 9252, 9253, 9254]}
{"timestamp": 128242, "input_length": 12740, "output_length": 347, "hash_ids": [0, 9255, 9256, 9257, 9258, 9259, 9260, 9261, 9262, 9263, 9264, 9265, 9266, 9267, 9268, 9269, 9270, 9271, 9272, 9273, 9274, 9275, 9276, 9277, 9278]}
{"timestamp": 128242, "input_length": 66965, "output_length": 360, "hash_ids": [0, 9279, 9280, 9281, 9282, 9283, 9284, 9285, 9286, 9287, 9288, 9289, 9290, 9291, 9292, 9293, 9294, 9295, 9296, 9297, 9298, 9299, 9300, 9301, 9302, 9303, 9304, 9305, 9306, 9307, 9308, 9309, 9310, 9311, 9312, 9313, 9314, 9315, 9316, 9317, 9318, 9319, 9320, 9321, 9322, 9323, 9324, 9325, 9326, 9327, 9328, 9329, 9330, 9331, 9332, 9333, 9334, 9335, 9336, 9337, 9338, 9339, 9340, 9341, 9342, 9343, 9344, 9345, 9346, 9347, 9348, 9349, 9350, 9351, 9352, 9353, 9354, 9355, 9356, 9357, 9358, 9359, 9360, 9361, 9362, 9363, 9364, 9365, 9366, 9367, 9368, 9369, 9370, 9371, 9372, 9373, 9374, 9375, 9376, 9377, 9378, 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, 9387, 9388, 9389, 9390, 9391, 9392, 9393, 9394, 9395, 9396, 9397, 9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408]}
{"timestamp": 128242, "input_length": 4314, "output_length": 221, "hash_ids": [0, 9409, 9410, 9411, 9412, 9413, 9414, 9415, 9416]}
{"timestamp": 128242, "input_length": 6511, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9417]}
{"timestamp": 128242, "input_length": 3153, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 9418, 9419]}
{"timestamp": 128242, "input_length": 1007, "output_length": 39, "hash_ids": [0, 9420]}
{"timestamp": 128242, "input_length": 14100, "output_length": 267, "hash_ids": [0, 9421, 9422, 9423, 9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 9442, 9443, 9444, 9445, 9446, 9447]}
{"timestamp": 128242, "input_length": 6529, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9448]}
{"timestamp": 128242, "input_length": 23836, "output_length": 383, "hash_ids": [0, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 9449, 9450, 9451, 9452, 9453, 9454, 9455, 9456, 9457, 9458]}
{"timestamp": 128242, "input_length": 3228, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 9459, 9460]}
{"timestamp": 128242, "input_length": 7074, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9461, 9462]}
{"timestamp": 131299, "input_length": 6759, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9463, 9464]}
{"timestamp": 131299, "input_length": 9579, "output_length": 300, "hash_ids": [0, 9465, 9466, 9467, 9468, 9469, 9470, 9471, 9472, 9473, 9474, 9475, 9476, 9477, 9478, 9479, 9480, 9481, 9482]}
{"timestamp": 131299, "input_length": 14374, "output_length": 241, "hash_ids": [0, 9483, 9484, 9485, 9486, 9487, 9488, 9489, 9490, 9491, 9492, 9493, 9494, 9495, 9496, 9497, 9498, 9499, 9500, 9501, 9502, 9503, 9504, 9505, 9506, 9507, 9508, 9509, 9510]}
{"timestamp": 131299, "input_length": 6166, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9511]}
{"timestamp": 131299, "input_length": 16575, "output_length": 2000, "hash_ids": [0, 9513, 9514, 9515, 9516, 9517, 9518, 9519, 9520, 9521, 9522, 9523, 9524, 9525, 9526, 9527, 9528, 9529, 9530, 9531, 9532, 9533, 9534, 9535, 9536, 9537, 9538, 9539, 9540, 9541, 9542, 9543, 9544]}
{"timestamp": 131299, "input_length": 3930, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 9545, 9546, 9547]}
{"timestamp": 131299, "input_length": 2969, "output_length": 14, "hash_ids": [74, 75, 76, 77, 78, 9548]}
{"timestamp": 131299, "input_length": 4994, "output_length": 230, "hash_ids": [0, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 9549, 9550]}
{"timestamp": 131299, "input_length": 3128, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 9551, 9552]}
{"timestamp": 131299, "input_length": 3105, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 9553, 9554]}
{"timestamp": 131299, "input_length": 4172, "output_length": 24, "hash_ids": [74, 75, 76, 77, 78, 9555, 9556, 9557, 9558]}
{"timestamp": 131299, "input_length": 7396, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9559, 9560, 9561]}
{"timestamp": 134348, "input_length": 6800, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9562, 9563]}
{"timestamp": 134348, "input_length": 1316, "output_length": 314, "hash_ids": [0, 9564, 9565]}
{"timestamp": 134348, "input_length": 3122, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 9566, 9567]}
{"timestamp": 134348, "input_length": 6557, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9568]}
{"timestamp": 134348, "input_length": 7268, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9569, 9570, 9571]}
{"timestamp": 134348, "input_length": 11111, "output_length": 467, "hash_ids": [0, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9581, 9582, 9583, 9584, 9585, 9586, 9587, 9588, 9589, 9590, 9591, 9592]}
{"timestamp": 134348, "input_length": 6668, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9593, 9594]}
{"timestamp": 134348, "input_length": 9576, "output_length": 270, "hash_ids": [0, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 9595]}
{"timestamp": 134348, "input_length": 8339, "output_length": 455, "hash_ids": [0, 9596, 9597, 9598, 9599, 9600, 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9609, 9610, 9611]}
{"timestamp": 134348, "input_length": 6169, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9612]}
{"timestamp": 134348, "input_length": 11645, "output_length": 324, "hash_ids": [0, 9613, 9614, 9615, 9616, 9617, 9618, 9619, 9620, 9621, 9622, 9623, 9624, 9625, 9626, 9627, 9628, 9629, 9630, 9631, 9632, 9633, 9634]}
{"timestamp": 134348, "input_length": 3145, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 9635, 9636]}
{"timestamp": 134348, "input_length": 3208, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 9637, 9638]}
{"timestamp": 134348, "input_length": 6169, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9639]}
{"timestamp": 134348, "input_length": 7077, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9640, 9641]}
{"timestamp": 134348, "input_length": 997, "output_length": 125, "hash_ids": [0, 9642]}
{"timestamp": 134348, "input_length": 5777, "output_length": 405, "hash_ids": [0, 9643, 9644, 9645, 9646, 9647, 9648, 9649, 9650, 9651, 9652, 9653]}
{"timestamp": 134348, "input_length": 2532, "output_length": 241, "hash_ids": [0, 9654, 9655, 9656, 9657]}
{"timestamp": 134348, "input_length": 9023, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9658, 9659, 9660, 9661, 9662, 9663]}
{"timestamp": 134348, "input_length": 7086, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9664, 9665]}
{"timestamp": 134348, "input_length": 20391, "output_length": 459, "hash_ids": [0, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 9666, 9667, 9668, 9669, 9670, 9671, 9672, 9673, 9674, 9675, 9676, 9677, 9678, 9679, 9680, 9681, 9682, 9683, 9684, 9685, 9686, 9687, 9688, 9689, 9690, 9691]}
{"timestamp": 134348, "input_length": 913, "output_length": 506, "hash_ids": [0, 9692]}
{"timestamp": 137404, "input_length": 11936, "output_length": 413, "hash_ids": [0, 9693, 9694, 9695, 9696, 9697, 9698, 9699, 9700, 9701, 9702, 9703, 9704, 9705, 9706, 9707, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715]}
{"timestamp": 137404, "input_length": 3374, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 9716, 9717]}
{"timestamp": 137404, "input_length": 9543, "output_length": 61, "hash_ids": [0, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735]}
{"timestamp": 137404, "input_length": 7941, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9736, 9737, 9738, 9739]}
{"timestamp": 137404, "input_length": 10294, "output_length": 395, "hash_ids": [0, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, 4181, 9740, 9741, 9742, 9743, 9744, 9745, 9746, 9747, 9748, 9749]}
{"timestamp": 137404, "input_length": 7250, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9750, 9751, 9752]}
{"timestamp": 137404, "input_length": 26568, "output_length": 655, "hash_ids": [0, 9753, 9754, 9755, 9756, 9757, 9758, 9759, 9760, 9761, 9762, 9763, 9764, 9765, 9766, 9767, 9768, 9769, 9770, 9771, 9772, 9773, 9774, 9775, 9776, 9777, 9778, 9779, 9780, 9781, 9782, 9783, 9784, 9785, 9786, 9787, 9788, 9789, 9790, 9791, 9792, 9793, 9794, 9795, 9796, 9797, 9798, 9799, 9800, 9801, 9802, 9803]}
{"timestamp": 137404, "input_length": 81406, "output_length": 365, "hash_ids": [0, 9804, 9805, 9806, 9807, 9808, 9809, 9810, 9811, 9812, 9813, 9814, 9815, 9816, 9817, 9818, 9819, 9820, 9821, 9822, 9823, 9824, 9825, 9826, 9827, 9828, 9829, 9830, 9831, 9832, 9833, 9834, 9835, 9836, 9837, 9838, 9839, 9840, 9841, 9842, 9843, 9844, 9845, 9846, 9847, 9848, 9849, 9850, 9851, 9852, 9853, 9854, 9855, 9856, 9857, 9858, 9859, 9860, 9861, 9862, 9863, 9864, 9865, 9866, 9867, 9868, 9869, 9870, 9871, 9872, 9873, 9874, 9875, 9876, 9877, 9878, 9879, 9880, 9881, 9882, 9883, 9884, 9885, 9886, 9887, 9888, 9889, 9890, 9891, 9892, 9893, 9894, 9895, 9896, 9897, 9898, 9899, 9900, 9901, 9902, 9903, 9904, 9905, 9906, 9907, 9908, 9909, 9910, 9911, 9912, 9913, 9914, 9915, 9916, 9917, 9918, 9919, 9920, 9921, 9922, 9923, 9924, 9925, 9926, 9927, 9928, 9929, 9930, 9931, 9932, 9933, 9934, 9935, 9936, 9937, 9938, 9939, 9940, 9941, 9942, 9943, 9944, 9945, 9946, 9947, 9948, 9949, 9950, 9951, 9952, 9953, 9954, 9955, 9956, 9957, 9958, 9959, 9960, 9961]}
{"timestamp": 137404, "input_length": 3151, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 9962, 9963]}
{"timestamp": 137404, "input_length": 5466, "output_length": 472, "hash_ids": [0, 9964, 9965, 9966, 9967, 9968, 9969, 9970, 9971, 9972, 9973]}
{"timestamp": 137404, "input_length": 6324, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9974]}
{"timestamp": 137404, "input_length": 3124, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 9975, 9976]}
{"timestamp": 137404, "input_length": 24066, "output_length": 422, "hash_ids": [0, 9977, 9978, 9979, 9980, 9981, 9982, 9983, 9984, 9985, 9986, 9987, 9988, 9989, 9990, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999, 10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014, 10015, 10016, 10017, 10018, 10019, 10020, 10021, 10022, 10023]}
{"timestamp": 137404, "input_length": 7011, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10024, 10025]}
{"timestamp": 137404, "input_length": 7078, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10026, 10027]}
{"timestamp": 137404, "input_length": 3208, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 10028, 10029]}
{"timestamp": 137404, "input_length": 3101, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 10030, 10031]}
{"timestamp": 137404, "input_length": 4958, "output_length": 294, "hash_ids": [0, 10032, 10033, 10034, 10035, 10036, 10037, 10038, 10039, 10040]}
{"timestamp": 137404, "input_length": 2988, "output_length": 296, "hash_ids": [0, 10041, 10042, 10043, 10044, 10045]}
{"timestamp": 140457, "input_length": 7001, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10046, 10047]}
{"timestamp": 140457, "input_length": 3279, "output_length": 52, "hash_ids": [0, 10048, 10049, 10050, 10051, 10052, 10053]}
{"timestamp": 140457, "input_length": 6855, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10054, 10055]}
{"timestamp": 140457, "input_length": 8902, "output_length": 499, "hash_ids": [0, 10056, 10057, 10058, 10059, 10060, 10061, 10062, 10063, 10064, 10065, 10066, 10067, 10068, 10069, 10070, 10071, 10072]}
{"timestamp": 140457, "input_length": 3193, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 10073, 10074]}
{"timestamp": 140457, "input_length": 7505, "output_length": 34, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10075, 10076, 10077]}
{"timestamp": 140457, "input_length": 9862, "output_length": 321, "hash_ids": [0, 10078, 10079, 10080, 10081, 10082, 10083, 10084, 10085, 10086, 10087, 10088, 10089, 10090, 10091, 10092, 10093, 10094, 10095, 10096]}
{"timestamp": 140457, "input_length": 6357, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10097]}
{"timestamp": 140457, "input_length": 7553, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10098, 10099, 10100]}
{"timestamp": 140457, "input_length": 3845, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 10101, 10102, 10103]}
{"timestamp": 140457, "input_length": 7044, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10104, 10105]}
{"timestamp": 140457, "input_length": 6091, "output_length": 364, "hash_ids": [0, 10106, 10107, 10108, 10109, 10110, 10111, 10112, 10113, 10114, 10115, 10116]}
{"timestamp": 140457, "input_length": 11970, "output_length": 450, "hash_ids": [0, 10117, 10118, 10119, 10120, 10121, 10122, 10123, 10124, 10125, 10126, 10127, 10128, 10129, 10130, 10131, 10132, 10133, 10134, 10135, 10136, 10137, 10138, 10139]}
{"timestamp": 140457, "input_length": 7122, "output_length": 126, "hash_ids": [0, 10140, 10141, 10142, 10143, 10144, 10145, 10146, 10147, 10148, 10149, 10150, 10151, 10152]}
{"timestamp": 140457, "input_length": 6706, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10153, 10154]}
{"timestamp": 140457, "input_length": 906, "output_length": 341, "hash_ids": [0, 10155]}
{"timestamp": 140457, "input_length": 121290, "output_length": 614, "hash_ids": [0, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 10156, 10157]}
{"timestamp": 140457, "input_length": 3157, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 10158, 10159]}
{"timestamp": 140457, "input_length": 11283, "output_length": 48, "hash_ids": [0, 10160, 10161, 10162, 10163, 10164, 10165, 10166, 10167, 10168, 10169, 10170, 10171, 10172, 10173, 10174, 10175, 10176, 10177, 10178, 10179, 10180, 10181]}
{"timestamp": 143510, "input_length": 1807, "output_length": 634, "hash_ids": [0, 10182, 10183, 10184]}
{"timestamp": 143510, "input_length": 24980, "output_length": 480, "hash_ids": [0, 10185, 10186, 10187, 10188, 10189, 10190, 10191, 10192, 10193, 10194, 10195, 10196, 10197, 10198, 10199, 10200, 10201, 10202, 10203, 10204, 10205, 10206, 10207, 10208, 10209, 10210, 10211, 10212, 10213, 10214, 10215, 10216, 10217, 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10225, 10226, 10227, 10228, 10229, 10230, 10231, 10232]}
{"timestamp": 143510, "input_length": 7074, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9461, 9462]}
{"timestamp": 143510, "input_length": 6994, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10233, 10234]}
{"timestamp": 143510, "input_length": 3208, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 10235, 10236]}
{"timestamp": 143510, "input_length": 7473, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10237, 10238, 10239]}
{"timestamp": 143510, "input_length": 18196, "output_length": 359, "hash_ids": [0, 10240, 10241, 10242, 10243, 10244, 10245, 10246, 10247, 10248, 10249, 10250, 10251, 10252, 10253, 10254, 10255, 10256, 10257, 10258, 10259, 10260, 10261, 10262, 10263, 10264, 10265, 10266, 10267, 10268, 10269, 10270, 10271, 10272, 10273, 10274]}
{"timestamp": 143510, "input_length": 6661, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10275, 10276]}
{"timestamp": 143510, "input_length": 6304, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10277]}
{"timestamp": 143510, "input_length": 22450, "output_length": 504, "hash_ids": [0, 10278, 10279, 10280, 10281, 10282, 10283, 10284, 10285, 10286, 10287, 10288, 10289, 10290, 10291, 10292, 10293, 10294, 10295, 10296, 10297, 10298, 10299, 10300, 10301, 10302, 10303, 10304, 10305, 10306, 10307, 10308, 10309, 10310, 10311, 10312, 10313, 10314, 10315, 10316, 10317, 10318, 10319, 10320]}
{"timestamp": 143510, "input_length": 3157, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 10321, 10322]}
{"timestamp": 143510, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10323]}
{"timestamp": 143510, "input_length": 4013, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 10324, 10325, 10326]}
{"timestamp": 143510, "input_length": 9865, "output_length": 464, "hash_ids": [0, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, 5495, 5496, 5497, 10327, 10328, 10329, 10330, 10331, 10332, 10333]}
{"timestamp": 143510, "input_length": 6270, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10334]}
{"timestamp": 143510, "input_length": 6444, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10335]}
{"timestamp": 143510, "input_length": 10457, "output_length": 62, "hash_ids": [0, 7643, 7644, 7645, 7646, 10336, 10337, 10338, 10339, 10340, 10341, 10342, 10343, 10344, 10345, 10346, 10347, 10348, 10349, 10350, 10351]}
{"timestamp": 143510, "input_length": 15959, "output_length": 210, "hash_ids": [0, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 4910, 4911, 10352, 10353, 10354]}
{"timestamp": 143510, "input_length": 3118, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 10355, 10356]}
{"timestamp": 143510, "input_length": 6459, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10357]}
{"timestamp": 143510, "input_length": 25257, "output_length": 2000, "hash_ids": [0, 10358, 10359, 10360, 10361, 10362, 10363, 10364, 10365, 10366, 10367, 10368, 10369, 10370, 10371, 10372, 10373, 10374, 10375, 10376, 10377, 10378, 10379, 10380, 10381, 10382, 10383, 10384, 10385, 10386, 10387, 10388, 10389, 10390, 10391, 10392, 10393, 10394, 10395, 10396, 10397, 10398, 10399, 10400, 10401, 10402, 10403, 10404, 10405, 10406]}
{"timestamp": 143510, "input_length": 6637, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10407]}
{"timestamp": 143510, "input_length": 3157, "output_length": 33, "hash_ids": [74, 75, 76, 77, 78, 10408, 10409]}
{"timestamp": 143510, "input_length": 912, "output_length": 394, "hash_ids": [0, 10410]}
{"timestamp": 143510, "input_length": 5014, "output_length": 145, "hash_ids": [0, 10411, 10412, 10413, 10414, 10415, 10416, 10417, 10418, 10419]}
{"timestamp": 143510, "input_length": 4107, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 10420, 10421, 10422, 10423]}
{"timestamp": 146563, "input_length": 16086, "output_length": 676, "hash_ids": [0, 10424, 10425, 10426, 10427, 10428, 10429, 10430, 10431, 10432, 10433, 10434, 10435, 10436, 10437, 10438, 10439, 10440, 10441, 10442, 10443, 10444, 10445, 10446, 10447, 10448, 10449, 10450, 10451, 10452, 10453, 10454]}
{"timestamp": 146563, "input_length": 7366, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10455, 10456, 10457]}
{"timestamp": 146563, "input_length": 7438, "output_length": 35, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10458, 10459, 10460]}
{"timestamp": 146563, "input_length": 6168, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10461]}
{"timestamp": 146563, "input_length": 7076, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10462, 10463]}
{"timestamp": 146563, "input_length": 9458, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10464, 10465, 10466, 10467, 10468, 10469, 10470]}
{"timestamp": 146563, "input_length": 6975, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10471, 10472]}
{"timestamp": 146563, "input_length": 18376, "output_length": 533, "hash_ids": [0, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 10473, 10474]}
{"timestamp": 146563, "input_length": 15949, "output_length": 336, "hash_ids": [0, 10475, 10476, 10477, 10478, 10479, 10480, 10481, 10482, 10483, 10484, 10485, 10486, 10487, 10488, 10489, 10490, 10491, 10492, 10493, 10494, 10495, 10496, 10497, 10498, 10499, 10500, 10501, 10502, 10503, 10504, 10505]}
{"timestamp": 146563, "input_length": 4814, "output_length": 361, "hash_ids": [0, 10506, 10507, 10508, 10509, 10510, 10511, 10512, 10513, 10514]}
{"timestamp": 146563, "input_length": 6599, "output_length": 22, "hash_ids": [0, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 10515]}
{"timestamp": 146563, "input_length": 85360, "output_length": 435, "hash_ids": [0, 10516, 10517, 10518, 10519, 10520, 10521, 10522, 10523, 10524, 10525, 10526, 10527, 10528, 10529, 10530, 10531, 10532, 10533, 10534, 10535, 10536, 10537, 10538, 10539, 10540, 10541, 10542, 10543, 10544, 10545, 10546, 10547, 10548, 10549, 10550, 10551, 10552, 10553, 10554, 10555, 10556, 10557, 10558, 10559, 10560, 10561, 10562, 10563, 10564, 10565, 10566, 10567, 10568, 10569, 10570, 10571, 10572, 10573, 10574, 10575, 10576, 10577, 10578, 10579, 10580, 10581, 10582, 10583, 10584, 10585, 10586, 10587, 10588, 10589, 10590, 10591, 10592, 10593, 10594, 10595, 10596, 10597, 10598, 10599, 10600, 10601, 10602, 10603, 10604, 10605, 10606, 10607, 10608, 10609, 10610, 10611, 10612, 10613, 10614, 10615, 10616, 10617, 10618, 10619, 10620, 10621, 10622, 10623, 10624, 10625, 10626, 10627, 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, 10648, 10649, 10650, 10651, 10652, 10653, 10654, 10655, 10656, 10657, 10658, 10659, 10660, 10661, 10662, 10663, 10664, 10665, 10666, 10667, 10668, 10669, 10670, 10671, 10672, 10673, 10674, 10675, 10676, 10677, 10678, 10679, 10680, 10681]}
{"timestamp": 146563, "input_length": 6168, "output_length": 24, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10682]}
{"timestamp": 146563, "input_length": 6166, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10683]}
{"timestamp": 146563, "input_length": 6203, "output_length": 35, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10684]}
{"timestamp": 146563, "input_length": 19392, "output_length": 310, "hash_ids": [0, 10685, 10686, 10687, 10688, 10689, 10690, 10691, 10692, 10693, 10694, 10695, 10696, 10697, 10698, 10699, 10700, 10701, 10702, 10703, 10704, 10705, 10706, 10707, 10708, 10709, 10710, 10711, 10712, 10713, 10714, 10715, 10716, 10717, 10718, 10719, 10720, 10721]}
{"timestamp": 146563, "input_length": 68965, "output_length": 505, "hash_ids": [0, 10722, 10723, 10724, 10725, 10726, 10727, 10728, 10729, 10730, 10731, 10732, 10733, 10734, 10735, 10736, 10737, 10738, 10739, 10740, 10741, 10742, 10743, 10744, 10745, 10746, 10747, 10748, 10749, 10750, 10751, 10752, 10753, 10754, 10755, 10756, 10757, 10758, 10759, 10760, 10761, 10762, 10763, 10764, 10765, 10766, 10767, 10768, 10769, 10770, 10771, 10772, 10773, 10774, 10775, 10776, 10777, 10778, 10779, 10780, 10781, 10782, 10783, 10784, 10785, 10786, 10787, 10788, 10789, 10790, 10791, 10792, 10793, 10794, 10795, 10796, 10797, 10798, 10799, 10800, 10801, 10802, 10803, 10804, 10805, 10806, 10807, 10808, 10809, 10810, 10811, 10812, 10813, 10814, 10815, 10816, 10817, 10818, 10819, 10820, 10821, 10822, 10823, 10824, 10825, 10826, 10827, 10828, 10829, 10830, 10831, 10832, 10833, 10834, 10835, 10836, 10837, 10838, 10839, 10840, 10841, 10842, 10843, 10844, 10845, 10846, 10847, 10848, 10849, 10850, 10851, 10852, 10853, 10854, 10855]}
{"timestamp": 146563, "input_length": 7420, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10856, 10857, 10858]}
{"timestamp": 146563, "input_length": 1179, "output_length": 27, "hash_ids": [0, 10859, 10860]}
{"timestamp": 146563, "input_length": 6664, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10861, 10862]}
{"timestamp": 146563, "input_length": 51754, "output_length": 381, "hash_ids": [0, 5718, 5719, 5720, 5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814, 5815, 10863, 10864, 10865]}
{"timestamp": 146563, "input_length": 10043, "output_length": 372, "hash_ids": [0, 10866, 10867, 10868, 10869, 10870, 10871, 10872, 10873, 10874, 10875, 10876, 10877, 10878, 10879, 10880, 10881, 10882, 10883, 10884]}
{"timestamp": 146563, "input_length": 21786, "output_length": 216, "hash_ids": [0, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 10885, 10886]}
{"timestamp": 146563, "input_length": 7188, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10887, 10888, 10889]}
{"timestamp": 146563, "input_length": 40138, "output_length": 222, "hash_ids": [0, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 10890, 10891, 10892, 10893, 10894, 10895, 10896, 10897, 10898, 10899, 10900, 10901, 10902, 10903, 10904, 10905, 10906, 10907, 10908, 10909, 10910, 10911, 10912, 10913, 10914, 10915, 10916, 10917, 10918, 10919, 10920, 10921, 10922, 10923, 10924, 10925, 10926, 10927, 10928, 10929, 10930, 10931, 10932, 10933, 10934, 10935, 10936, 10937]}
{"timestamp": 146563, "input_length": 3130, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 10938, 10939]}
{"timestamp": 149619, "input_length": 6308, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10940]}
{"timestamp": 149619, "input_length": 3073, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 10941, 10942]}
{"timestamp": 149619, "input_length": 5280, "output_length": 222, "hash_ids": [0, 10943, 10944, 10945, 10946, 10947, 10948, 10949, 10950, 10951, 10952]}
{"timestamp": 149619, "input_length": 8439, "output_length": 5, "hash_ids": [0, 10953, 10954, 10955, 10956, 10957, 10958, 10959, 10960, 10961, 10962, 10963, 10964, 10965, 10966, 10967, 10968]}
{"timestamp": 149619, "input_length": 7002, "output_length": 36, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10969, 10970]}
{"timestamp": 149619, "input_length": 892, "output_length": 459, "hash_ids": [0, 10971]}
{"timestamp": 149619, "input_length": 6173, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10972]}
{"timestamp": 149619, "input_length": 6924, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 10973, 10974]}
{"timestamp": 149619, "input_length": 10149, "output_length": 571, "hash_ids": [0, 10975, 10976, 10977, 10978, 10979, 10980, 10981, 10982, 10983, 10984, 10985, 10986, 10987, 10988, 10989, 10990, 10991, 10992, 10993]}
{"timestamp": 149619, "input_length": 32091, "output_length": 537, "hash_ids": [0, 10994, 10995, 10996, 10997, 10998, 10999, 11000, 11001, 11002, 11003, 11004, 11005, 11006, 11007, 11008, 11009, 11010, 11011, 11012, 11013, 11014, 11015, 11016, 11017, 11018, 11019, 11020, 11021, 11022, 11023, 11024, 11025, 11026, 11027, 11028, 11029, 11030, 11031, 11032, 11033, 11034, 11035, 11036, 11037, 11038, 11039, 11040, 11041, 11042, 11043, 11044, 11045, 11046, 11047, 11048, 11049, 11050, 11051, 11052, 11053, 11054, 11055]}
{"timestamp": 149619, "input_length": 9543, "output_length": 71, "hash_ids": [0, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735]}
{"timestamp": 149619, "input_length": 27829, "output_length": 300, "hash_ids": [0, 11056, 11057, 11058, 11059, 11060, 11061, 11062, 11063, 11064, 11065, 11066, 11067, 11068, 11069, 11070, 11071, 11072, 11073, 11074, 11075, 11076, 11077, 11078, 11079, 11080, 11081, 11082, 11083, 11084, 11085, 11086, 11087, 11088, 11089, 11090, 11091, 11092, 11093, 11094, 11095, 11096, 11097, 11098, 11099, 11100, 11101, 11102, 11103, 11104, 11105, 11106, 11107, 11108, 11109]}
{"timestamp": 149619, "input_length": 28589, "output_length": 542, "hash_ids": [0, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 11110, 11111, 11112, 11113, 11114, 11115, 11116, 11117, 11118, 11119, 11120, 11121, 11122, 11123, 11124, 11125, 11126, 11127, 11128, 11129, 11130, 11131, 11132, 11133, 11134, 11135, 11136, 11137, 11138, 11139, 11140, 11141, 11142, 11143]}
{"timestamp": 149619, "input_length": 3127, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 11144, 11145]}
{"timestamp": 149619, "input_length": 3179, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 11146, 11147]}
{"timestamp": 149619, "input_length": 6165, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11148]}
{"timestamp": 149619, "input_length": 3902, "output_length": 341, "hash_ids": [0, 3423, 3424, 3425, 3426, 3427, 11149, 11150]}
{"timestamp": 149619, "input_length": 24589, "output_length": 540, "hash_ids": [0, 10185, 10186, 10187, 10188, 10189, 10190, 10191, 10192, 10193, 10194, 10195, 10196, 10197, 10198, 10199, 10200, 10201, 10202, 10203, 10204, 10205, 10206, 10207, 10208, 10209, 10210, 10211, 10212, 10213, 10214, 10215, 10216, 10217, 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10225, 10226, 10227, 10228, 10229, 10230, 10231, 11151]}
{"timestamp": 149619, "input_length": 6179, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11152]}
{"timestamp": 149619, "input_length": 930, "output_length": 40, "hash_ids": [0, 11153]}
{"timestamp": 149619, "input_length": 1541, "output_length": 87, "hash_ids": [0, 6742, 11154, 11155]}
{"timestamp": 149619, "input_length": 15511, "output_length": 464, "hash_ids": [0, 11156, 11157, 11158, 11159, 11160, 11161, 11162, 11163, 11164, 11165, 11166, 11167, 11168, 11169, 11170, 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, 11181, 11182, 11183, 11184, 11185]}
{"timestamp": 152672, "input_length": 6168, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11186]}
{"timestamp": 152672, "input_length": 6861, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11187, 11188]}
{"timestamp": 152672, "input_length": 7058, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11189, 11190]}
{"timestamp": 152672, "input_length": 9679, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11191, 11192, 11193, 11194, 11195, 11196, 11197]}
{"timestamp": 152672, "input_length": 8370, "output_length": 459, "hash_ids": [0, 11198, 11199, 11200, 11201, 11202, 11203, 11204, 11205, 11206, 11207, 11208, 11209, 11210, 11211, 11212, 11213]}
{"timestamp": 152672, "input_length": 6994, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11214, 11215]}
{"timestamp": 152672, "input_length": 5747, "output_length": 317, "hash_ids": [0, 11216, 11217, 11218, 11219, 11220, 11221, 11222, 11223, 11224, 11225, 11226]}
{"timestamp": 152672, "input_length": 6452, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11227]}
{"timestamp": 152672, "input_length": 8456, "output_length": 421, "hash_ids": [0, 11228, 11229, 11230, 11231, 11232, 11233, 11234, 11235, 11236, 11237, 11238, 11239, 11240, 11241, 11242, 11243]}
{"timestamp": 152672, "input_length": 31578, "output_length": 582, "hash_ids": [0, 11244, 11245, 11246, 11247, 11248, 11249, 11250, 11251, 11252, 11253, 11254, 11255, 11256, 11257, 11258, 11259, 11260, 11261, 11262, 11263, 11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278, 11279, 11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304]}
{"timestamp": 152672, "input_length": 4030, "output_length": 22, "hash_ids": [74, 75, 76, 77, 78, 11305, 11306, 11307]}
{"timestamp": 152672, "input_length": 15176, "output_length": 585, "hash_ids": [0, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 11308, 11309, 11310, 11311, 11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325]}
{"timestamp": 152672, "input_length": 1839, "output_length": 590, "hash_ids": [0, 3177, 11326, 11327]}
{"timestamp": 152672, "input_length": 8506, "output_length": 583, "hash_ids": [0, 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343]}
{"timestamp": 152672, "input_length": 6880, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11344, 11345]}
{"timestamp": 152672, "input_length": 6714, "output_length": 41, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11346, 11347]}
{"timestamp": 152672, "input_length": 3124, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 11348, 11349]}
{"timestamp": 152672, "input_length": 3142, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 11350, 11351]}
{"timestamp": 152672, "input_length": 6216, "output_length": 193, "hash_ids": [0, 11352, 11353, 11354, 11355, 11356, 11357, 11358, 11359, 11360, 11361, 11362, 11363]}
{"timestamp": 152672, "input_length": 897, "output_length": 276, "hash_ids": [0, 11364]}
{"timestamp": 152672, "input_length": 1051, "output_length": 185, "hash_ids": [0, 11365, 11366]}
{"timestamp": 152672, "input_length": 19019, "output_length": 430, "hash_ids": [0, 5254, 5255, 5256, 5257, 11367, 11368, 11369, 11370, 11371, 11372, 11373, 11374, 11375, 11376, 11377, 11378, 11379, 11380, 11381, 11382, 11383, 11384, 11385, 11386, 11387, 11388, 11389, 11390, 11391, 11392, 11393, 11394, 11395, 11396, 11397, 11398, 11399]}
{"timestamp": 152672, "input_length": 2060, "output_length": 479, "hash_ids": [0, 4484, 11400, 11401, 11402]}
{"timestamp": 152672, "input_length": 6180, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11403]}
{"timestamp": 152672, "input_length": 6168, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11404]}
{"timestamp": 155725, "input_length": 3159, "output_length": 23, "hash_ids": [74, 75, 76, 77, 78, 11405, 11406]}
{"timestamp": 155725, "input_length": 6170, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11407]}
{"timestamp": 155725, "input_length": 21658, "output_length": 689, "hash_ids": [0, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 11408, 11409]}
{"timestamp": 155725, "input_length": 9171, "output_length": 454, "hash_ids": [0, 11410, 11411, 11412, 11413, 11414, 11415, 11416, 11417, 11418, 11419, 11420, 11421, 11422, 11423, 11424, 11425, 11426]}
{"timestamp": 155725, "input_length": 6171, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11427]}
{"timestamp": 155725, "input_length": 6192, "output_length": 18, "hash_ids": [0, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 11428, 11429]}
{"timestamp": 155725, "input_length": 2531, "output_length": 386, "hash_ids": [0, 11430, 11431, 11432, 11433]}
{"timestamp": 155725, "input_length": 3070, "output_length": 666, "hash_ids": [0, 11434, 11435, 11436, 11437, 11438]}
{"timestamp": 155725, "input_length": 6752, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11439, 11440]}
{"timestamp": 155725, "input_length": 3092, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 11441, 11442]}
{"timestamp": 155725, "input_length": 6178, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11443]}
{"timestamp": 155725, "input_length": 6170, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11444]}
{"timestamp": 155725, "input_length": 5756, "output_length": 389, "hash_ids": [0, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 11445, 11446]}
{"timestamp": 155725, "input_length": 3165, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 11447, 11448]}
{"timestamp": 155725, "input_length": 6961, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11449, 11450]}
{"timestamp": 155725, "input_length": 2996, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 11451]}
{"timestamp": 155725, "input_length": 6170, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11452]}
{"timestamp": 155725, "input_length": 22671, "output_length": 532, "hash_ids": [0, 11453, 11454, 11455, 11456, 11457, 11458, 11459, 11460, 11461, 11462, 11463, 11464, 11465, 11466, 11467, 11468, 11469, 11470, 11471, 11472, 11473, 11474, 11475, 11476, 11477, 11478, 11479, 11480, 11481, 11482, 11483, 11484, 11485, 11486, 11487, 11488, 11489, 11490, 11491, 11492, 11493, 11494, 11495, 11496]}
{"timestamp": 158778, "input_length": 7227, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11497, 11498, 11499]}
{"timestamp": 158778, "input_length": 3122, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 11500, 11501]}
{"timestamp": 158778, "input_length": 6520, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11502]}
{"timestamp": 158778, "input_length": 8347, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11503, 11504, 11505, 11506, 11507]}
{"timestamp": 158778, "input_length": 6984, "output_length": 495, "hash_ids": [0, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 5716, 11508, 11509]}
{"timestamp": 158778, "input_length": 3262, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 11510, 11511]}
{"timestamp": 158778, "input_length": 6357, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11512]}
{"timestamp": 158778, "input_length": 6231, "output_length": 39, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11513]}
{"timestamp": 158778, "input_length": 8824, "output_length": 411, "hash_ids": [0, 11514, 11515, 11516, 11517, 11518, 11519, 11520, 11521, 11522, 11523, 11524, 11525, 11526, 11527, 11528, 11529, 11530]}
{"timestamp": 158778, "input_length": 3203, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 11531, 11532]}
{"timestamp": 158778, "input_length": 21188, "output_length": 367, "hash_ids": [0, 11533, 11534, 11535, 11536, 11537, 11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, 11551, 11552, 11553, 11554, 11555, 11556, 11557, 11558, 11559, 11560, 11561, 11562, 11563, 11564, 11565, 11566, 11567, 11568, 11569, 11570, 11571, 11572, 11573]}
{"timestamp": 158778, "input_length": 3133, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 11574, 11575]}
{"timestamp": 158778, "input_length": 3134, "output_length": 17, "hash_ids": [74, 75, 76, 77, 78, 11576, 11577]}
{"timestamp": 158778, "input_length": 1231, "output_length": 381, "hash_ids": [0, 11578, 11579]}
{"timestamp": 158778, "input_length": 8341, "output_length": 297, "hash_ids": [0, 11580, 11581, 11582, 11583, 11584, 11585, 11586, 11587, 11588, 11589, 11590, 11591, 11592, 11593, 11594, 11595]}
{"timestamp": 158778, "input_length": 6493, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11596]}
{"timestamp": 158778, "input_length": 6168, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11597]}
{"timestamp": 158778, "input_length": 6647, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11598]}
{"timestamp": 158778, "input_length": 3887, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 11599, 11600, 11601]}
{"timestamp": 158778, "input_length": 6168, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11602]}
{"timestamp": 158778, "input_length": 2211, "output_length": 520, "hash_ids": [0, 11603, 11604, 11605, 11606]}
{"timestamp": 158778, "input_length": 6542, "output_length": 31, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11607]}
{"timestamp": 158778, "input_length": 14095, "output_length": 381, "hash_ids": [0, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 11608, 11609, 11610, 11611]}
{"timestamp": 158778, "input_length": 6908, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11612, 11613]}
{"timestamp": 158778, "input_length": 5283, "output_length": 452, "hash_ids": [0, 11614, 11615, 11616, 11617, 11618, 11619, 11620, 11621, 11622, 11623]}
{"timestamp": 161830, "input_length": 6423, "output_length": 269, "hash_ids": [0, 11624, 11625, 11626, 11627, 11628, 11629, 11630, 11631, 11632, 11633, 11634, 11635]}
{"timestamp": 161830, "input_length": 6166, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11636]}
{"timestamp": 161830, "input_length": 7491, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 4382, 11637, 11638]}
{"timestamp": 161830, "input_length": 7801, "output_length": 600, "hash_ids": [0, 11639, 11640, 11641, 11642, 11643, 11644, 11645, 11646, 11647, 11648, 11649, 11650, 11651, 11652, 11653]}
{"timestamp": 161830, "input_length": 11143, "output_length": 349, "hash_ids": [0, 11654, 11655, 11656, 11657, 11658, 11659, 11660, 11661, 11662, 11663, 11664, 11665, 11666, 11667, 11668, 11669, 11670, 11671, 11672, 11673, 11674]}
{"timestamp": 161830, "input_length": 4335, "output_length": 582, "hash_ids": [0, 11675, 11676, 11677, 11678, 11679, 11680, 11681, 11682]}
{"timestamp": 161830, "input_length": 7092, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 11683, 11684]}
{"timestamp": 161830, "input_length": 112880, "output_length": 199, "hash_ids": [0, 11685, 11686, 11687, 11688, 11689, 11690, 11691, 11692, 11693, 11694, 11695, 11696, 11697, 11698, 11699, 11700, 11701, 11702, 11703, 11704, 11705, 11706, 11707, 11708, 11709, 11710, 11711, 11712, 11713, 11714, 11715, 11716, 11717, 11718, 11719, 11720, 11721, 11722, 11723, 11724, 11725, 11726, 11727, 11728, 11729, 11730, 11731, 11732, 11733, 11734, 11735, 11736, 11737, 11738, 11739, 11740, 11741, 11742, 11743, 11744, 11745, 11746, 11747, 11748, 11749, 11750, 11751, 11752, 11753, 11754, 11755, 11756, 11757, 11758, 11759, 11760, 11761, 11762, 11763, 11764, 11765, 11766, 11767, 11768, 11769, 11770, 11771, 11772, 11773, 11774, 11775, 11776, 11777, 11778, 11779, 11780, 11781, 11782, 11783, 11784, 11785, 11786, 11787, 11788, 11789, 11790, 11791, 11792, 11793, 11794, 11795, 11796, 11797, 11798, 11799, 11800, 11801, 11802, 11803, 11804, 11805, 11806, 11807, 11808, 11809, 11810, 11811, 11812, 11813, 11814, 11815, 11816, 11817, 11818, 11819, 11820, 11821, 11822, 11823, 11824, 11825, 11826, 11827, 11828, 11829, 11830, 11831, 11832, 11833, 11834, 11835, 11836, 11837, 11838, 11839, 11840, 11841, 11842, 11843, 11844, 11845, 11846, 11847, 11848, 11849, 11850, 11851, 11852, 11853, 11854, 11855, 11856, 11857, 11858, 11859, 11860, 11861, 11862, 11863, 11864, 11865, 11866, 11867, 11868, 11869, 11870, 11871, 11872, 11873, 11874, 11875, 11876, 11877, 11878, 11879, 11880, 11881, 11882, 11883, 11884, 11885, 11886, 11887, 11888, 11889, 11890, 11891, 11892, 11893, 11894, 11895, 11896, 11897, 11898, 11899, 11900, 11901, 11902, 11903, 11904]}
{"timestamp": 161830, "input_length": 24024, "output_length": 810, "hash_ids": [0, 11905, 11906, 11907, 11908, 11909, 11910, 11911, 11912, 11913, 11914, 11915, 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933, 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950]}
{"timestamp": 161830, "input_length": 26689, "output_length": 36, "hash_ids": [0, 11951, 11952, 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965, 11966, 11967, 11968, 11969, 11970, 11971, 11972, 11973, 11974, 11975, 11976, 11977, 11978, 11979, 11980, 11981, 11982, 11983, 11984, 11985, 11986, 11987, 11988, 11989, 11990, 11991, 11992, 11993, 11994, 11995, 11996, 11997, 11998, 11999, 12000, 12001, 12002]}
{"timestamp": 161830, "input_length": 77792, "output_length": 466, "hash_ids": [0, 9804, 9805, 9806, 9807, 9808, 9809, 9810, 9811, 9812, 9813, 9814, 9815, 9816, 9817, 9818, 9819, 9820, 9821, 9822, 9823, 9824, 9825, 9826, 9827, 9828, 9829, 9830, 9831, 9832, 9833, 9834, 9835, 9836, 9837, 9838, 9839, 9840, 9841, 9842, 9843, 9844, 9845, 9846, 9847, 9848, 9849, 9850, 9851, 9852, 9853, 9854, 9855, 9856, 9857, 9858, 9859, 9860, 9861, 9862, 9863, 9864, 9865, 9866, 9867, 9868, 9869, 9870, 9871, 9872, 9873, 9874, 9875, 9876, 9877, 9878, 9879, 9880, 9881, 9882, 9883, 9884, 9885, 9886, 9887, 9888, 9889, 9890, 9891, 9892, 9893, 9894, 9895, 9896, 9897, 9898, 9899, 9900, 9901, 9902, 9903, 9904, 9905, 9906, 9907, 9908, 9909, 9910, 9911, 9912, 9913, 9914, 9915, 9916, 9917, 9918, 9919, 9920, 9921, 9922, 9923, 9924, 9925, 9926, 9927, 9928, 9929, 9930, 9931, 9932, 9933, 9934, 9935, 9936, 9937, 9938, 9939, 9940, 9941, 9942, 9943, 9944, 9945, 9946, 9947, 12003, 12004, 12005, 12006, 12007, 12008, 12009]}
{"timestamp": 161830, "input_length": 1760, "output_length": 509, "hash_ids": [0, 4000, 12010, 12011]}
{"timestamp": 161830, "input_length": 3704, "output_length": 589, "hash_ids": [0, 7632, 7633, 7634, 7635, 12012, 12013, 12014]}
{"timestamp": 161830, "input_length": 24584, "output_length": 436, "hash_ids": [0, 12015, 12016, 12017, 12018, 12019, 12020, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12029, 12030, 12031, 12032, 12033, 12034, 12035, 12036, 12037, 12038, 12039, 12040, 12041, 12042, 12043, 12044, 12045, 12046, 12047, 12048, 12049, 12050, 12051, 12052, 12053, 12054, 12055, 12056, 12057, 12058, 12059, 12060, 12061, 12062]}
{"timestamp": 161830, "input_length": 9504, "output_length": 476, "hash_ids": [0, 12063, 12064, 12065, 12066, 12067, 12068, 12069, 12070, 12071, 12072, 12073, 12074, 12075, 12076, 12077, 12078, 12079, 12080]}
{"timestamp": 161830, "input_length": 20555, "output_length": 12, "hash_ids": [0, 12081, 12082, 12083, 12084, 12085, 12086, 12087, 12088, 12089, 12090, 12091, 12092, 12093, 12094, 12095, 12096, 12097, 12098, 12099, 12100, 12101, 12102, 12103, 12104, 12105, 12106, 12107, 12108, 12109, 12110, 12111, 12112, 12113, 12114, 12115, 12116, 12117, 12118, 12119, 12120]}
{"timestamp": 161830, "input_length": 1796, "output_length": 323, "hash_ids": [0, 12121, 12122, 12123]}
{"timestamp": 161830, "input_length": 6211, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12124]}
{"timestamp": 161830, "input_length": 3439, "output_length": 421, "hash_ids": [0, 12125, 12126, 12127, 12128, 12129, 12130]}
{"timestamp": 164883, "input_length": 3387, "output_length": 369, "hash_ids": [0, 12131, 12132, 12133, 12134, 12135, 12136]}
{"timestamp": 164883, "input_length": 7045, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12137, 12138]}
{"timestamp": 164883, "input_length": 17581, "output_length": 9, "hash_ids": [0, 12139, 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 12149, 12150, 12151, 12152, 12153, 12154, 12155, 12156, 12157, 12158, 12159, 12160, 12161, 12162, 12163, 12164, 12165, 12166, 12167, 12168, 12169, 12170, 12171, 12172]}
{"timestamp": 164883, "input_length": 3874, "output_length": 468, "hash_ids": [0, 12173, 12174, 12175, 12176, 12177, 12178, 12179]}
{"timestamp": 164883, "input_length": 1578, "output_length": 125, "hash_ids": [0, 12180, 12181, 12182]}
{"timestamp": 164883, "input_length": 7391, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12183, 12184, 12185]}
{"timestamp": 164883, "input_length": 6167, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12186]}
{"timestamp": 164883, "input_length": 20857, "output_length": 319, "hash_ids": [0, 6376, 6377, 6378, 12187, 12188, 12189, 12190, 12191, 12192, 12193, 12194, 12195, 12196, 12197, 12198, 12199, 12200, 12201, 12202, 12203, 12204, 12205, 12206, 12207, 12208, 12209, 12210, 12211, 12212, 12213, 12214, 12215, 12216, 12217, 12218, 12219, 12220, 12221, 12222, 12223]}
{"timestamp": 164883, "input_length": 1213, "output_length": 60, "hash_ids": [0, 11365, 12224]}
{"timestamp": 164883, "input_length": 1083, "output_length": 342, "hash_ids": [0, 12225, 12226]}
{"timestamp": 164883, "input_length": 7081, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12227, 12228]}
{"timestamp": 164883, "input_length": 3195, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 12229, 12230]}
{"timestamp": 164883, "input_length": 3123, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 12231, 12232]}
{"timestamp": 164883, "input_length": 6559, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12233]}
{"timestamp": 164883, "input_length": 11242, "output_length": 703, "hash_ids": [0, 12234, 12235, 12236, 12237, 12238, 12239, 12240, 12241, 12242, 12243, 12244, 12245, 12246, 12247, 12248, 12249, 12250, 12251, 12252, 12253, 12254]}
{"timestamp": 167940, "input_length": 21308, "output_length": 347, "hash_ids": [0, 12255, 12256, 12257, 12258, 12259, 12260, 12261, 12262, 12263, 12264, 12265, 12266, 12267, 12268, 12269, 12270, 12271, 12272, 12273, 12274, 12275, 12276, 12277, 12278, 12279, 12280, 12281, 12282, 12283, 12284, 12285, 12286, 12287, 12288, 12289, 12290, 12291, 12292, 12293, 12294, 12295]}
{"timestamp": 167940, "input_length": 9965, "output_length": 279, "hash_ids": [0, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 12296, 12297]}
{"timestamp": 167940, "input_length": 9190, "output_length": 46, "hash_ids": [0, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, 12307, 12308, 12309, 12310, 12311, 12312, 12313, 12314]}
{"timestamp": 167940, "input_length": 2207, "output_length": 32, "hash_ids": [0, 6786, 6787, 12315, 12316]}
{"timestamp": 167940, "input_length": 5234, "output_length": 535, "hash_ids": [0, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038]}
{"timestamp": 167940, "input_length": 4210, "output_length": 606, "hash_ids": [0, 12317, 12318, 12319, 12320, 12321, 12322, 12323, 12324]}
{"timestamp": 167940, "input_length": 6271, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12325]}
{"timestamp": 167940, "input_length": 4094, "output_length": 1, "hash_ids": [0, 12326, 12327, 12328, 12329, 12330, 12331, 12332]}
{"timestamp": 167940, "input_length": 3184, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 12333, 12334]}
{"timestamp": 167940, "input_length": 6168, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12335]}
{"timestamp": 167940, "input_length": 6926, "output_length": 26, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12336, 12337]}
{"timestamp": 167940, "input_length": 7172, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12338, 12339, 12340]}
{"timestamp": 167940, "input_length": 8804, "output_length": 423, "hash_ids": [0, 9596, 9597, 9598, 9599, 9600, 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9609, 9610, 12341, 12342]}
{"timestamp": 167940, "input_length": 6891, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12343, 12344]}
{"timestamp": 167940, "input_length": 6168, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12345]}
{"timestamp": 167940, "input_length": 15591, "output_length": 138, "hash_ids": [0, 12346, 12347, 12348, 12349, 12350, 12351, 12352, 12353, 12354, 12355, 12356, 12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375]}
{"timestamp": 170992, "input_length": 4681, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 12376, 12377, 12378, 12379, 12380]}
{"timestamp": 170992, "input_length": 1900, "output_length": 661, "hash_ids": [0, 1264, 1265, 1266]}
{"timestamp": 170992, "input_length": 12375, "output_length": 415, "hash_ids": [0, 12381, 12382, 12383, 12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404]}
{"timestamp": 170992, "input_length": 899, "output_length": 240, "hash_ids": [0, 12405]}
{"timestamp": 170992, "input_length": 2111, "output_length": 508, "hash_ids": [0, 4340, 12406, 12407, 12408]}
{"timestamp": 170992, "input_length": 6170, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12409]}
{"timestamp": 170992, "input_length": 2659, "output_length": 394, "hash_ids": [0, 12410, 12411, 12412, 12413, 12414]}
{"timestamp": 170992, "input_length": 3114, "output_length": 21, "hash_ids": [74, 75, 76, 77, 78, 12415, 12416]}
{"timestamp": 170992, "input_length": 5145, "output_length": 510, "hash_ids": [0, 12417, 12418, 12419, 12420, 12421, 12422, 12423, 12424, 12425, 12426]}
{"timestamp": 170992, "input_length": 20755, "output_length": 502, "hash_ids": [0, 12427, 12428, 12429, 12430, 12431, 12432, 12433, 12434, 12435, 12436, 12437, 12438, 12439, 12440, 12441, 12442, 12443, 12444, 12445, 12446, 12447, 12448, 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466]}
{"timestamp": 170992, "input_length": 3135, "output_length": 18, "hash_ids": [74, 75, 76, 77, 78, 12467, 12468]}
{"timestamp": 170992, "input_length": 6388, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12469]}
{"timestamp": 170992, "input_length": 7067, "output_length": 33, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12470, 12471]}
{"timestamp": 170992, "input_length": 6186, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12472]}
{"timestamp": 170992, "input_length": 8342, "output_length": 331, "hash_ids": [0, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, 12482, 12483, 12484, 12485, 12486, 12487, 12488]}
{"timestamp": 170992, "input_length": 16701, "output_length": 484, "hash_ids": [0, 12489, 12490, 12491, 12492, 12493, 12494, 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, 12520]}
{"timestamp": 170992, "input_length": 3328, "output_length": 15, "hash_ids": [74, 75, 76, 77, 78, 12521, 12522]}
{"timestamp": 170992, "input_length": 6938, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12523, 12524]}
{"timestamp": 170992, "input_length": 5712, "output_length": 515, "hash_ids": [0, 12525, 12526, 12527, 12528, 12529, 12530, 12531, 12532, 12533, 12534, 12535]}
{"timestamp": 174045, "input_length": 15941, "output_length": 340, "hash_ids": [0, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 12536, 12537]}
{"timestamp": 174045, "input_length": 7184, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12538, 12539, 12540]}
{"timestamp": 174045, "input_length": 1425, "output_length": 362, "hash_ids": [0, 12541, 12542]}
{"timestamp": 174045, "input_length": 6637, "output_length": 15, "hash_ids": [0, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 12543]}
{"timestamp": 174045, "input_length": 6175, "output_length": 32, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12544]}
{"timestamp": 174045, "input_length": 8849, "output_length": 346, "hash_ids": [0, 8105, 8106, 8107, 8108, 8109, 8110, 12545, 12546, 12547, 12548, 12549, 12550, 12551, 12552, 12553, 12554, 12555]}
{"timestamp": 174045, "input_length": 11703, "output_length": 53, "hash_ids": [0, 5386, 5387, 12556, 12557, 12558, 12559, 12560, 12561, 12562, 12563, 12564, 12565, 12566, 12567, 12568, 12569, 12570, 12571, 12572, 12573, 12574, 12575]}
{"timestamp": 174045, "input_length": 6590, "output_length": 28, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12576]}
{"timestamp": 174045, "input_length": 3148, "output_length": 20, "hash_ids": [74, 75, 76, 77, 78, 12577, 12578]}
{"timestamp": 174045, "input_length": 9576, "output_length": 242, "hash_ids": [0, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 9595]}
{"timestamp": 174045, "input_length": 7188, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12579, 12580, 12581]}
{"timestamp": 174045, "input_length": 893, "output_length": 357, "hash_ids": [0, 12582]}
{"timestamp": 174045, "input_length": 6632, "output_length": 23, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12583]}
{"timestamp": 174045, "input_length": 4210, "output_length": 353, "hash_ids": [0, 12584, 12585, 12586, 12587, 12588, 12589, 12590, 12591]}
{"timestamp": 174045, "input_length": 7960, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12592, 12593, 12594, 12595]}
{"timestamp": 174045, "input_length": 7232, "output_length": 368, "hash_ids": [0, 10140, 10141, 10142, 10143, 10144, 10145, 10146, 10147, 10148, 10149, 10150, 10151, 12596, 12597]}
{"timestamp": 174045, "input_length": 16430, "output_length": 219, "hash_ids": [0, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 4910, 4911, 10352, 10353, 12598, 12599]}
{"timestamp": 174045, "input_length": 2584, "output_length": 562, "hash_ids": [0, 1259, 1260, 12600, 12601, 12602]}
{"timestamp": 177098, "input_length": 6241, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12603]}
{"timestamp": 177098, "input_length": 7393, "output_length": 389, "hash_ids": [0, 12604, 12605, 12606, 12607, 12608, 12609, 12610, 12611, 12612, 12613, 12614, 12615, 12616, 12617]}
{"timestamp": 177098, "input_length": 6170, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12618]}
{"timestamp": 177098, "input_length": 7518, "output_length": 27, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12619, 12620, 12621]}
{"timestamp": 177098, "input_length": 6350, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12622]}
{"timestamp": 177098, "input_length": 4262, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 12623, 12624, 12625, 12626]}
{"timestamp": 177098, "input_length": 6712, "output_length": 25, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12627, 12628]}
{"timestamp": 177098, "input_length": 7420, "output_length": 173, "hash_ids": [0, 12629, 12630, 12631, 12632, 12633, 12634, 12635, 12636, 12637, 12638, 12639, 12640, 12641, 12642]}
{"timestamp": 177098, "input_length": 14136, "output_length": 424, "hash_ids": [0, 12643, 12644, 12645, 12646, 12647, 12648, 12649, 12650, 12651, 12652, 12653, 12654, 12655, 12656, 12657, 12658, 12659, 12660, 12661, 12662, 12663, 12664, 12665, 12666, 12667, 12668, 12669]}
{"timestamp": 177098, "input_length": 16531, "output_length": 375, "hash_ids": [0, 2889, 2890, 2891, 12670, 12671, 12672, 12673, 12674, 12675, 12676, 12677, 12678, 12679, 12680, 12681, 12682, 12683, 12684, 12685, 12686, 12687, 12688, 12689, 12690, 12691, 12692, 12693, 12694, 12695, 12696, 12697, 12698]}
{"timestamp": 177098, "input_length": 4121, "output_length": 158, "hash_ids": [0, 12699, 12700, 12701, 12702, 12703, 12704, 12705, 12706]}
{"timestamp": 177098, "input_length": 1381, "output_length": 426, "hash_ids": [0, 12707, 12708]}
{"timestamp": 177098, "input_length": 18556, "output_length": 648, "hash_ids": [0, 12709, 12710, 12711, 12712, 12713, 12714, 12715, 12716, 12717, 12718, 12719, 12720, 12721, 12722, 12723, 12724, 12725, 12726, 12727, 12728, 12729, 12730, 12731, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12739, 12740, 12741, 12742, 12743, 12744]}
{"timestamp": 177098, "input_length": 6826, "output_length": 47, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12745, 12746]}
{"timestamp": 177098, "input_length": 39243, "output_length": 277, "hash_ids": [0, 12747, 12748, 12749, 12750, 12751, 12752, 12753, 12754, 12755, 12756, 12757, 12758, 12759, 12760, 12761, 12762, 12763, 12764, 12765, 12766, 12767, 12768, 12769, 12770, 12771, 12772, 12773, 12774, 12775, 12776, 12777, 12778, 12779, 12780, 12781, 12782, 12783, 12784, 12785, 12786, 12787, 12788, 12789, 12790, 12791, 12792, 12793, 12794, 12795, 12796, 12797, 12798, 12799, 12800, 12801, 12802, 12803, 12804, 12805, 12806, 12807, 12808, 12809, 12810, 12811, 12812, 12813, 12814, 12815, 12816, 12817, 12818, 12819, 12820, 12821, 12822]}
{"timestamp": 177098, "input_length": 3132, "output_length": 19, "hash_ids": [74, 75, 76, 77, 78, 12823, 12824]}
{"timestamp": 177098, "input_length": 6689, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 12825, 12826]}
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
mod support;
#[path = "../kv_router/common/shared.rs"]
mod common;
#[path = "../kv_router/active_sequences_shared.rs"]
mod active_sequences_shared;
use active_sequences_shared::{generate_sequence_events, run_benchmark};
use common::process_mooncake_trace;
const BLOCK_SIZE: u32 = 128;
const NUM_GPU_BLOCKS: usize = 16384;
const TRACE_SIMULATION_DURATION_MS: Option<u64> = None;
const BENCHMARK_DURATION_MS: u64 = 4000;
const NUM_UNIQUE_INFERENCE_WORKERS: usize = 10;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn active_sequences_trace_replays_without_warnings_or_leaks() -> anyhow::Result<()> {
let warning_count = support::warning_counter(&["dynamo_kv_router::sequences", "dynamo_mocker"]);
support::reset_warning_count(&warning_count);
let fixture = support::fixture_path("mooncake_trace_1000.jsonl")?;
let traces =
process_mooncake_trace(&fixture, BLOCK_SIZE, 1, 1, NUM_UNIQUE_INFERENCE_WORKERS, 42)?;
let sequence_traces = generate_sequence_events(
&traces,
NUM_GPU_BLOCKS,
BLOCK_SIZE,
TRACE_SIMULATION_DURATION_MS,
)
.await?;
let run = run_benchmark(&sequence_traces, BLOCK_SIZE, BENCHMARK_DURATION_MS, 1).await?;
assert!(
run.kept_up,
"benchmark replay fell behind in test profile; increase BENCHMARK_DURATION_MS if this becomes too tight"
);
assert!(
run.results.ops_throughput > 0.0,
"benchmark replay should record positive throughput"
);
assert_eq!(
warning_count.load(std::sync::atomic::Ordering::Relaxed),
0,
"sequence replay emitted warn/error logs from dynamo_kv_router::sequences or dynamo_mocker"
);
Ok(())
}
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
mod support;
#[path = "../kv_router/common/shared.rs"]
mod common;
#[path = "../kv_router/mooncake_shared.rs"]
mod mooncake_shared;
use std::collections::HashSet;
use std::io::Write;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::time::Duration;
use common::{generate_replay_artifacts, process_mooncake_trace};
use dynamo_kv_router::indexer::KvIndexerMetrics;
use dynamo_mocker::loadgen::{SessionTrace, Trace, TurnTrace};
use mooncake_shared::{MooncakeBenchmarkConfig, MooncakeIndexerConfig, run_benchmark};
use tempfile::NamedTempFile;
const BLOCK_SIZE: u32 = 128;
const NUM_GPU_BLOCKS: usize = 16384;
const NUM_UNIQUE_INFERENCE_WORKERS: usize = 10;
const BENCHMARK_DURATION_MS: u64 = 2000;
const NUM_EVENT_WORKERS: usize = 4;
#[test]
fn process_mooncake_trace_expands_and_duplicates_hash_space() -> anyhow::Result<()> {
let mut file = NamedTempFile::new()?;
for (i, (hash_ids, output_length)) in [(&[0u64, 1, 2] as &[u64], 10u64), (&[0, 1, 3, 4], 10)]
.iter()
.enumerate()
{
writeln!(
file,
"{}",
serde_json::json!({
"timestamp": i as u64,
"input_length": hash_ids.len(),
"hash_ids": hash_ids,
"output_length": output_length,
})
)?;
}
let traces = process_mooncake_trace(
file.path().to_str().expect("temp path should be UTF-8"),
512,
2,
2,
2,
42,
)?;
let mut all_hashes: Vec<Vec<u64>> = traces
.into_iter()
.flat_map(|worker| worker.sessions.into_iter())
.flat_map(|session| session.turns.into_iter().map(|turn| turn.hash_ids))
.collect();
all_hashes.sort();
let mut expected = vec![
vec![0, 1, 2, 3, 4, 5],
vec![10, 11, 12, 13, 14, 15],
vec![0, 1, 2, 3, 6, 7, 8, 9],
vec![10, 11, 12, 13, 16, 17, 18, 19],
];
expected.sort();
assert_eq!(all_hashes, expected, "hash_ids mismatch");
let copy0: Vec<&Vec<u64>> = all_hashes.iter().filter(|hashes| hashes[0] == 0).collect();
let copy1: Vec<&Vec<u64>> = all_hashes.iter().filter(|hashes| hashes[0] == 10).collect();
assert_eq!(copy0.len(), 2);
assert_eq!(copy1.len(), 2);
assert_eq!(copy0[0][..4], copy0[1][..4], "copy 0 shared prefix broken");
assert_eq!(copy1[0][..4], copy1[1][..4], "copy 1 shared prefix broken");
let set0: HashSet<u64> = copy0
.iter()
.flat_map(|hashes| hashes.iter().copied())
.collect();
let set1: HashSet<u64> = copy1
.iter()
.flat_map(|hashes| hashes.iter().copied())
.collect();
assert!(set0.is_disjoint(&set1), "copies are not hash-disjoint");
Ok(())
}
#[tokio::test(flavor = "current_thread")]
async fn generate_replay_artifacts_waits_for_completion_delay() -> anyhow::Result<()> {
let trace = Trace {
block_size: 2,
sessions: vec![SessionTrace {
session_id: "session-a".to_string(),
first_arrival_timestamp_ms: Some(0.0),
turns: vec![
TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![1, 2],
delay_after_previous_ms: 0.0,
},
TurnTrace {
input_length: 4,
max_output_tokens: 2,
hash_ids: vec![3, 4],
delay_after_previous_ms: 5.0,
},
],
}],
};
let artifacts = generate_replay_artifacts(&[trace], 1024, 2, None).await?;
assert_eq!(artifacts.len(), 1);
assert_eq!(artifacts[0].requests.len(), 2);
let first_uuid = artifacts[0].requests[0].uuid;
let first_completion_ms = artifacts[0]
.output_signals
.iter()
.find(|signal| signal.signal.uuid == first_uuid && signal.signal.completed)
.expect("first request must complete")
.timestamp_us as f64
/ 1000.0;
assert!(
artifacts[0].requests[1].scheduled_ready_at_ms + 0.1 >= first_completion_ms + 5.0,
"expected second request to wait for completion plus delay"
);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn mooncake_trace_replays_without_warnings_across_indexer_variants() -> anyhow::Result<()> {
let warning_count = support::warning_counter(&["dynamo_kv_router::indexer", "dynamo_mocker"]);
let fixture = support::fixture_path("mooncake_trace_1000.jsonl")?;
let traces =
process_mooncake_trace(&fixture, BLOCK_SIZE, 1, 1, NUM_UNIQUE_INFERENCE_WORKERS, 42)?;
let artifacts = generate_replay_artifacts(&traces, NUM_GPU_BLOCKS, BLOCK_SIZE, None).await?;
let variants = [
MooncakeIndexerConfig::radix_tree(),
MooncakeIndexerConfig::nested_map(8, NUM_EVENT_WORKERS),
MooncakeIndexerConfig::concurrent_radix_tree(NUM_EVENT_WORKERS),
MooncakeIndexerConfig::concurrent_radix_tree_compressed(NUM_EVENT_WORKERS),
];
for config in variants {
support::reset_warning_count(&warning_count);
let metrics = Arc::new(KvIndexerMetrics::new_unregistered());
let run = {
let indexer = config.build(BLOCK_SIZE, Arc::clone(&metrics));
run_benchmark(
indexer,
artifacts.clone(),
MooncakeBenchmarkConfig {
benchmark_duration_ms: BENCHMARK_DURATION_MS,
inference_worker_duplication_factor: 1,
count_events: config.supports_remove(),
find_matches_concurrency: 0,
},
)
.await?
};
tokio::time::sleep(Duration::from_millis(50)).await;
assert!(
run.kept_up,
"{} replay fell behind in test profile; increase BENCHMARK_DURATION_MS if this becomes too tight",
config.short_name()
);
assert!(
run.results.ops_throughput > 0.0,
"{} replay should record positive throughput",
config.short_name()
);
assert_eq!(
warning_count.load(Ordering::Relaxed),
0,
"{} emitted warn/error logs from dynamo_kv_router::indexer or dynamo_mocker",
config.short_name()
);
assert_eq!(
support::duplicate_store_warning_count(metrics.as_ref()),
0,
"{} recorded duplicate-store warning metrics",
config.short_name()
);
}
Ok(())
}
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, OnceLock};
use anyhow::Context;
use dynamo_kv_router::indexer::{KvIndexerMetrics, METRIC_WARNING_DUPLICATE_STORE};
use tracing::{Event, Level, Subscriber};
use tracing_subscriber::Registry;
use tracing_subscriber::layer::{Context as LayerContext, Layer};
use tracing_subscriber::prelude::*;
struct WarningCounterLayer {
count: Arc<AtomicUsize>,
target_prefixes: &'static [&'static str],
}
impl<S> Layer<S> for WarningCounterLayer
where
S: Subscriber,
{
fn on_event(&self, event: &Event<'_>, _ctx: LayerContext<'_, S>) {
let metadata = event.metadata();
let target = metadata.target();
if matches!(*metadata.level(), Level::WARN | Level::ERROR)
&& self
.target_prefixes
.iter()
.any(|prefix| target.starts_with(prefix))
{
self.count.fetch_add(1, Ordering::Relaxed);
}
}
}
pub fn warning_counter(target_prefixes: &'static [&'static str]) -> Arc<AtomicUsize> {
static COUNTER: OnceLock<Arc<AtomicUsize>> = OnceLock::new();
COUNTER
.get_or_init(|| {
let count = Arc::new(AtomicUsize::new(0));
let subscriber = Registry::default().with(WarningCounterLayer {
count: Arc::clone(&count),
target_prefixes,
});
tracing::subscriber::set_global_default(subscriber)
.expect("global warning counter subscriber should initialize once");
count
})
.clone()
}
pub fn reset_warning_count(counter: &Arc<AtomicUsize>) {
counter.store(0, Ordering::Relaxed);
}
pub fn fixture_path(file_name: &str) -> anyhow::Result<String> {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("testdata")
.join(file_name)
.to_str()
.map(str::to_owned)
.context("fixture path is not valid UTF-8")
}
#[allow(dead_code)]
pub fn duplicate_store_warning_count(metrics: &KvIndexerMetrics) -> u64 {
metrics
.kv_cache_event_warnings
.get_metric_with_label_values(&[METRIC_WARNING_DUPLICATE_STORE])
.expect("duplicate_store warning metric should exist")
.get()
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment