Skip to content

Commit a0879e8

Browse files
authored
Include visualizer in docs site (#301)
* Include visualizer in docs site * Fix linting error causing build failure * Fix static site path * Trigger docs build when apropos * Use relative resource paths * Try different link path * Use absolute path * Support pre-aggregated event streams in the UI * Optionally gzip-compress output * Speed up CBOR decoding * Add trace to git * Add more traces to git
1 parent 45bccdf commit a0879e8

File tree

30 files changed

+10426
-88
lines changed

30 files changed

+10426
-88
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ui/public/traces/1xsummary.jsonl.gz filter=lfs diff=lfs merge=lfs -text
2+
ui/public/traces/100xsummary.jsonl.gz filter=lfs diff=lfs merge=lfs -text
3+
ui/public/traces/10xsummary.jsonl.gz filter=lfs diff=lfs merge=lfs -text

.github/workflows/docs.yaml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ on:
55
paths:
66
- "**/*.d2"
77
- "site/**"
8+
- "ui/**"
89
push:
910
branches:
1011
- main
1112
paths:
1213
- "**/*.d2"
1314
- "site/**"
15+
- "ui/**"
1416

1517
jobs:
1618
docs-generate-d2-diagrams:
@@ -72,9 +74,43 @@ jobs:
7274
git commit -m "Auto-generate diagram PNGs [skip ci]"
7375
git push origin HEAD:${{ github.head_ref || github.ref_name }}
7476
77+
viz-build:
78+
name: "Build Visualizer"
79+
runs-on: ubuntu-22.04
80+
steps:
81+
- name: 📥 Checkout repository
82+
uses: actions/checkout@v4
83+
with:
84+
lfs: true
85+
fetch-depth: 2
86+
87+
- name: 🛠️ Setup Node.js
88+
uses: actions/setup-node@v4
89+
with:
90+
node-version: 22
91+
cache: "yarn"
92+
cache-dependency-path: ./ui/yarn.lock
93+
94+
- name: 📦 Install dependencies
95+
working-directory: ui
96+
run: yarn install
97+
98+
- name: 🏗️ Build visualizer
99+
working-directory: ui
100+
run: |
101+
yarn build
102+
103+
- name: 🚢 Upload visualizer static site
104+
id: upload_viz
105+
uses: actions/upload-artifact@v4
106+
with:
107+
name: visualizer
108+
path: ui/dist
109+
75110
docs-build:
76111
name: "Build"
77112
runs-on: ubuntu-22.04
113+
needs: viz-build
78114
outputs:
79115
has_changes: ${{ steps.check_changes.outputs.has_changes }}
80116
steps:
@@ -83,11 +119,12 @@ jobs:
83119
with:
84120
fetch-depth: 2
85121

86-
- name: Check for site changes
122+
- name: Check for site or visualizer changes
87123
id: check_changes
88124
run: |
89125
SITE_CHANGES=$(git diff --name-only HEAD^ HEAD -- site/ || true)
90-
if [ -z "$SITE_CHANGES" ]; then
126+
VIZ_CHANGES=$(git diff --name-only HEAD^ HEAD -- ui/ || true)
127+
if [ -z "$SITE_CHANGES" ] && [ -z "$VIZ_CHANGES" ]; then
91128
echo "No changes in site directory"
92129
echo "has_changes=false" >> $GITHUB_OUTPUT
93130
else
@@ -110,6 +147,13 @@ jobs:
110147
working-directory: site
111148
run: yarn install
112149

150+
- name: 👁️ Unpack visualizer
151+
if: steps.check_changes.outputs.has_changes == 'true'
152+
uses: actions/download-artifact@v4
153+
with:
154+
name: visualizer
155+
path: site/static/visualizer
156+
113157
- name: 🏗️ Build Docusaurus site
114158
if: steps.check_changes.outputs.has_changes == 'true'
115159
working-directory: site

sim-rs/Cargo.lock

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sim-rs/sim-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rust-version = "1.82"
77

88
[dependencies]
99
anyhow = "1"
10+
async-compression = { version = "0.4", features = ["tokio", "gzip"] }
1011
average = "0.16"
1112
clap = { version = "4", features = ["derive"] }
1213
ctrlc = "3"

sim-rs/sim-cli/src/events.rs

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use std::{
22
collections::{BTreeMap, BTreeSet},
33
path::PathBuf,
4+
pin::Pin,
45
};
56

7+
use aggregate::TraceAggregator;
68
use anyhow::Result;
9+
use async_compression::tokio::write::GzipEncoder;
710
use average::Variance;
811
use itertools::Itertools as _;
912
use pretty_bytes_rust::{pretty_bytes, PrettyBytesOptions};
@@ -16,15 +19,19 @@ use sim_core::{
1619
};
1720
use tokio::{
1821
fs::{self, File},
19-
io::{AsyncWriteExt as _, BufWriter},
22+
io::{AsyncWrite, AsyncWriteExt as _, BufWriter},
2023
sync::mpsc,
2124
};
2225
use tracing::{info, info_span};
2326

27+
mod aggregate;
28+
2429
type InputBlockId = sim_core::model::InputBlockId<Node>;
2530
type EndorserBlockId = sim_core::model::EndorserBlockId<Node>;
2631
type VoteBundleId = sim_core::model::VoteBundleId<Node>;
2732

33+
type TraceSink = Pin<Box<dyn AsyncWrite + Send + Sync + 'static>>;
34+
2835
#[derive(Clone, Serialize)]
2936
struct OutputEvent {
3037
time_s: Timestamp,
@@ -44,6 +51,7 @@ pub struct EventMonitor {
4451
maximum_eb_age: u64,
4552
events_source: mpsc::UnboundedReceiver<(Event, Timestamp)>,
4653
output_path: Option<PathBuf>,
54+
aggregate: bool,
4755
}
4856

4957
impl EventMonitor {
@@ -67,6 +75,7 @@ impl EventMonitor {
6775
maximum_eb_age: config.max_eb_age,
6876
events_source,
6977
output_path,
78+
aggregate: config.aggregate_events,
7079
}
7180
}
7281

@@ -125,9 +134,27 @@ impl EventMonitor {
125134
}
126135
}
127136

128-
let mut output = match self.output_path {
129-
Some(ref path) => {
130-
let file = File::create(path).await?;
137+
let mut output = match self.output_path.as_mut() {
138+
Some(path) => {
139+
let file = File::create(&path).await?;
140+
141+
let mut gzipped = false;
142+
if path
143+
.extension()
144+
.and_then(|e| e.to_str())
145+
.is_some_and(|ext| ext == "gz")
146+
{
147+
path.set_extension("");
148+
gzipped = true;
149+
}
150+
151+
let file: TraceSink = if gzipped {
152+
let encoder = GzipEncoder::new(file);
153+
Box::pin(BufWriter::new(encoder))
154+
} else {
155+
Box::pin(BufWriter::new(file))
156+
};
157+
131158
let format = if path
132159
.extension()
133160
.and_then(|e| e.to_str())
@@ -137,9 +164,14 @@ impl EventMonitor {
137164
} else {
138165
OutputFormat::JsonStream
139166
};
140-
OutputTarget::EventStream {
141-
format,
142-
file: BufWriter::new(file),
167+
if self.aggregate {
168+
OutputTarget::AggregatedEventStream {
169+
aggregation: TraceAggregator::new(),
170+
format,
171+
file,
172+
}
173+
} else {
174+
OutputTarget::EventStream { format, file }
143175
}
144176
}
145177
None => OutputTarget::None,
@@ -576,16 +608,30 @@ fn compute_stats<Iter: IntoIterator<Item = f64>>(data: Iter) -> Stats {
576608
}
577609

578610
enum OutputTarget {
611+
AggregatedEventStream {
612+
aggregation: TraceAggregator,
613+
format: OutputFormat,
614+
file: TraceSink,
615+
},
579616
EventStream {
580617
format: OutputFormat,
581-
file: BufWriter<File>,
618+
file: TraceSink,
582619
},
583620
None,
584621
}
585622

586623
impl OutputTarget {
587624
async fn write(&mut self, event: OutputEvent) -> Result<()> {
588625
match self {
626+
Self::AggregatedEventStream {
627+
aggregation,
628+
format,
629+
file,
630+
} => {
631+
if let Some(summary) = aggregation.process(event) {
632+
Self::write_line(*format, file, summary).await?;
633+
}
634+
}
589635
Self::EventStream { format, file } => {
590636
Self::write_line(*format, file, event).await?;
591637
}
@@ -594,9 +640,9 @@ impl OutputTarget {
594640
Ok(())
595641
}
596642

597-
async fn write_line<T: Serialize>(
643+
async fn write_line<T: Serialize, W: AsyncWrite + Unpin>(
598644
format: OutputFormat,
599-
file: &mut BufWriter<File>,
645+
file: &mut W,
600646
event: T,
601647
) -> Result<()> {
602648
match format {
@@ -615,6 +661,16 @@ impl OutputTarget {
615661

616662
async fn flush(self) -> Result<()> {
617663
match self {
664+
Self::AggregatedEventStream {
665+
aggregation,
666+
format,
667+
mut file,
668+
} => {
669+
if let Some(summary) = aggregation.finish() {
670+
Self::write_line(format, &mut file, summary).await?;
671+
}
672+
file.flush().await?;
673+
}
618674
Self::EventStream { mut file, .. } => {
619675
file.flush().await?;
620676
}

0 commit comments

Comments
 (0)