Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
426fd33
feat: add global allocator wrapper counting metrics per thread and us…
semenov-vladyslav Nov 16, 2025
8eb8b21
feat: add flamegraph-alloc feature support in iota-benchmark
semenov-vladyslav Nov 16, 2025
aa7eb60
feat: improve flamegraph alloc metrics display
semenov-vladyslav Nov 20, 2025
d34e52a
feat: add 'flamegraph-alloc' feature to iota-node crate
semenov-vladyslav Nov 20, 2025
42f87bb
feat: add aws orchestrator settings
semenov-vladyslav Nov 20, 2025
439890d
feat: measure flamegraph spans by duration or memory allocations
semenov-vladyslav Nov 21, 2025
5c161a6
refactor: simplify a bit, remove unneeded type
semenov-vladyslav Nov 21, 2025
b557d01
fix: added license line
semenov-vladyslav Nov 21, 2025
52b1ab9
fix: rebase errors
semenov-vladyslav Dec 10, 2025
3592fd5
feat: let aws orchestrator fetch alloc flamegraphs if 'flamegraph-all…
semenov-vladyslav Dec 10, 2025
9bc3c1c
fix: clippy
semenov-vladyslav Dec 10, 2025
a0262f6
fix: typo
semenov-vladyslav Dec 10, 2025
b85e327
chore: fmt
semenov-vladyslav Dec 11, 2025
b25878a
fix(flamegraphs): only apply `flamegraph-alloc` feature if nightly to…
muXxer Dec 11, 2025
226a71b
feat(aws): fetch flamegraphs from fullnodes as well
muXxer Dec 11, 2025
dd062a3
feat(swarm): also set fullnode admin interface address
muXxer Dec 12, 2025
43b2209
feat(flamegraph): return error if mem flamegraph is not supported by …
muXxer Dec 12, 2025
ff1c71a
feat(flamegraph): add flamegraph type to the caption
muXxer Dec 12, 2025
03906f4
fix(aws): quote all paths used in curl commands
muXxer Dec 12, 2025
410bfef
feat(build-cache): add build.sh script
muXxer Dec 12, 2025
5894b06
fix(swarm): revert changes to network config builder
muXxer Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Move.lock

# Flamegraph output
flamegraph.svg
flamegraph-mem.svg

# Thumbnails
._*
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion crates/iota-aws-orchestrator/src/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,12 +612,28 @@ impl<P: ProtocolCommands<T> + ProtocolMetrics, T: BenchmarkType> Orchestrator<P,
if self.settings.enable_flamegraph {
self.fetch_flamegraphs(
parameters,
self.node_instances.clone(),
self.instances_without_metrics().clone(),
&path,
"?svg=true",
"flamegraph",
)
.await?;

if self
.settings
.build_configs
.get("iota-node")
.is_some_and(|config| config.features.iter().any(|f| f == "flamegraph-alloc"))
{
self.fetch_flamegraphs(
parameters,
self.instances_without_metrics().clone(),
&path,
"?svg=true&mem=true",
"flamegraph-alloc",
)
.await?;
}
}

display::done();
Expand Down
6 changes: 3 additions & 3 deletions crates/iota-aws-orchestrator/src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub trait ProtocolMetrics {
self.nodes_metrics_path(instances, parameters)
.into_iter()
.map(|(instance, path)| {
let cmd = format!("curl {path}");
let cmd = format!("curl '{path}'");
display::action(format!("\n{cmd}"));
(instance, cmd)
})
Expand All @@ -125,7 +125,7 @@ pub trait ProtocolMetrics {
.into_iter()
.map(|instance| {
(instance, {
let cmd = format!("curl http://localhost:1337/flamegraph{query}");
let cmd = format!("curl 'http://localhost:1337/flamegraph{query}'");
display::action(format!("\n{cmd}"));
cmd.to_string()
})
Expand Down Expand Up @@ -154,7 +154,7 @@ pub trait ProtocolMetrics {
{
self.clients_metrics_path(instances, parameters)
.into_iter()
.map(|(instance, path)| (instance, format!("curl {path}")))
.map(|(instance, path)| (instance, format!("curl '{path}'")))
.collect()
}
}
Expand Down
11 changes: 11 additions & 0 deletions crates/iota-benchmark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ publish = false
[lints]
workspace = true

[features]
flamegraph-alloc = ["telemetry-subscribers/flamegraph-alloc"]

[dependencies]
# external dependencies
anyhow = { workspace = true, features = ["backtrace"] }
Expand Down Expand Up @@ -57,3 +60,11 @@ iota-macros.workspace = true
iota-simulator.workspace = true
iota-surfer.workspace = true
typed-store.workspace = true

[build-dependencies]
rustc_version_runtime = "0.3"

[[bin]]
name = "flamegraph"
path = "src/bin/flamegraph.rs"
required-features = ["flamegraph-alloc"]
13 changes: 13 additions & 0 deletions crates/iota-benchmark/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

fn main() {
// Declare the custom cfg to avoid warnings
println!("cargo::rustc-check-cfg=cfg(nightly)");

// Detect if we're using nightly Rust
let meta = rustc_version_runtime::version_meta();
if meta.channel == rustc_version_runtime::Channel::Nightly {
println!("cargo:rustc-cfg=nightly");
}
}
55 changes: 33 additions & 22 deletions crates/iota-benchmark/src/bin/flamegraph.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// Copyright (c) 2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::fs;

use iota_test_transaction_builder::make_transfer_iota_transaction;
use test_cluster::TestClusterBuilder;
use tracing::Instrument as _;

#[cfg(all(feature = "flamegraph-alloc", nightly))]
#[global_allocator]
static GLOBAL: telemetry_subscribers::flamegraph::CounterAlloc<std::alloc::System> =
telemetry_subscribers::flamegraph::CounterAlloc::new(std::alloc::System);

/// This is a binary to generate test flamegraph data in a simple benchmark with
/// a local test cluster. To run it, use:
/// ```cargo run --release --package iota-benchmark --bin flamegraph```
Expand All @@ -26,26 +29,34 @@ async fn main() {

// follow instructions in telemetry-subscribers README how to setup grafana to
// visualize the flamegraphs
println!(
"{}",
serde_json::to_string_pretty(&sub.get_nested_sets(
"iota-benchmark::flamegraph",
true,
true
))
let nested_sets = sub.get_nested_sets("iota-benchmark::flamegraph", true, true);
println!("{}", serde_json::to_string_pretty(&nested_sets).unwrap());

use std::io::Write as _;

#[allow(unused_mut)]
let mut config = Default::default();

std::fs::File::create("flamegraph.svg")
.unwrap()
);
println!();

let svg = sub
.get_combined_svg(
"iota-benchmark::flamegraph",
true,
true,
&Default::default(),
.write_all(
sub.get_combined_svg("iota-benchmark::flamegraph", true, true, &config)
.unwrap()
.into_string()
.as_bytes(),
)
.unwrap()
.into_string();
fs::write("flamegraph.svg", &svg).expect("Failed to write flamegraph.svg");
println!("Flamegraph written to flamegraph.svg");
.unwrap();
#[cfg(all(feature = "flamegraph-alloc", nightly))]
{
config.measure_mem = true;
std::fs::File::create("flamegraph-mem.svg")
.unwrap()
.write_all(
sub.get_combined_svg("iota-benchmark::flamegraph", true, true, &config)
.unwrap()
.into_string()
.as_bytes(),
)
.unwrap();
}
}
23 changes: 23 additions & 0 deletions crates/iota-build-cache-server/scripts/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# Get script directory and source config
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
source "$SCRIPT_DIR/utils.sh"

print_config
check_availability
AVAILABILITY_CHECK=$?
set -e # Enable exit on error

# If build is not available, start build and wait
if [ $AVAILABILITY_CHECK -ne 0 ]; then
# Build will resolve branch/tag to commit and update COMMIT variable
log_info "Starting build for commit/branch/tag: $COMMIT"
build

log_info "Waiting for build to complete for commit: $COMMIT"
wait
fi

log_info "Build completed for commit: $COMMIT"
6 changes: 6 additions & 0 deletions crates/iota-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ publish = false
[lints]
workspace = true

[features]
flamegraph-alloc = ["telemetry-subscribers/flamegraph-alloc"]

[dependencies]
# external dependencies
anemo.workspace = true
Expand Down Expand Up @@ -60,5 +63,8 @@ move-vm-profiler.workspace = true
telemetry-subscribers.workspace = true
typed-store.workspace = true

[build-dependencies]
rustc_version_runtime = "0.3"

[target.'cfg(msim)'.dependencies]
iota-simulator.workspace = true
13 changes: 13 additions & 0 deletions crates/iota-node/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

fn main() {
// Declare the custom cfg to avoid warnings
println!("cargo::rustc-check-cfg=cfg(nightly)");

// Detect if we're using nightly Rust
let meta = rustc_version_runtime::version_meta();
if meta.channel == rustc_version_runtime::Channel::Nightly {
println!("cargo:rustc-cfg=nightly");
}
}
21 changes: 19 additions & 2 deletions crates/iota-node/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ struct Flamegraph {
/// Toggle SVG response, otherwise return nested set model for Grafana.
#[serde(default)]
svg: bool,
/// SVG width in pixels (3600 by default).
/// SVG width in pixels (when missing or set to 0 will default to 1920).
#[serde(default)]
width: usize,
/// Select still running call graphs.
Expand All @@ -472,6 +472,9 @@ struct Flamegraph {
/// Select call graph with the given ID.
#[serde(default)]
graph_id: String,
/// Use memory allocations as span measure rather than duration.
#[serde(default)]
mem: bool,
}

async fn flamegraph(State(state): State<Arc<AppState>>, query: Query<Flamegraph>) -> Response {
Expand All @@ -482,16 +485,30 @@ async fn flamegraph(State(state): State<Arc<AppState>>, query: Query<Flamegraph>
mut running,
mut completed,
graph_id,
mem,
}) = query;
if !running && !completed {
running = true;
completed = true;
}
if svg {
#[cfg(not(all(feature = "flamegraph-alloc", nightly)))]
{
if mem {
return (
StatusCode::BAD_REQUEST,
"memory flamegraphs are not supported (re-run iota-node with 'flamegraph-alloc' feature enabled and on nightly Rust toolchain)",
)
.into_response();
}
}

// draw an svg
let width = if width == 0 { Some(3600) } else { Some(width) };
let width = if width == 0 { Some(1920) } else { Some(width) };
let config = telemetry_subscribers::flamegraph::SvgConfig {
width,
#[cfg(all(feature = "flamegraph-alloc", nightly))]
measure_mem: mem,
..Default::default()
};
let svg = if !graph_id.is_empty() {
Expand Down
6 changes: 6 additions & 0 deletions crates/iota-node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ use iota_types::{
committee::EpochId, messages_checkpoint::CheckpointSequenceNumber, multiaddr::Multiaddr,
supported_protocol_versions::SupportedProtocolVersions,
};
#[cfg(all(feature = "flamegraph-alloc", nightly))]
use telemetry_subscribers::flamegraph::CounterAlloc;
use tokio::sync::broadcast;
use tracing::{error, info};

#[cfg(all(feature = "flamegraph-alloc", nightly))]
#[global_allocator]
static GLOBAL: CounterAlloc<std::alloc::System> = CounterAlloc::new(std::alloc::System);

// Define the `GIT_REVISION` and `VERSION` consts
bin_version::bin_version!();

Expand Down
4 changes: 2 additions & 2 deletions crates/iota-swarm-config/src/node_config_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,9 @@ impl FullnodeConfigBuilder {

pub fn with_admin_interface_address(
mut self,
admin_interface_address: impl Into<SocketAddr>,
admin_interface_address: Option<impl Into<SocketAddr>>,
) -> Self {
self.admin_interface_address = Some(admin_interface_address.into());
self.admin_interface_address = admin_interface_address.map(|addr| addr.into());
self
}

Expand Down
Loading
Loading