Skip to content

Commit 8231e42

Browse files
committed
feat(l1): add peer table timing metrics for Kademlia comparison baseline
Add Prometheus histograms to measure peer table operation latencies on the current flat IndexMap implementation. These metrics provide the baseline for comparing against the k-bucket implementation in #6458. Metrics added: - ethrex_kademlia_insert_contact_duration_seconds: times contact insertion via IndexMap::entry in do_new_contacts - ethrex_kademlia_iter_contacts_duration_seconds: times full table scan in do_get_closest_nodes Also adds three Grafana panels to the P2P Packets dashboard for visualizing p50/p99 latencies and operation rates.
1 parent 5a84846 commit 8231e42

3 files changed

Lines changed: 218 additions & 1 deletion

File tree

crates/blockchain/metrics/p2p.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use prometheus::{Encoder, IntCounterVec, IntGauge, IntGaugeVec, Opts, Registry, TextEncoder};
1+
use prometheus::{
2+
Encoder, Histogram, HistogramOpts, IntCounterVec, IntGauge, IntGaugeVec, Opts, Registry,
3+
TextEncoder,
4+
};
25
use std::sync::LazyLock;
36

47
use crate::MetricsError;
@@ -16,6 +19,8 @@ pub struct MetricsP2P {
1619
discv4_outgoing_messages: IntCounterVec,
1720
discv5_incoming_messages: IntCounterVec,
1821
discv5_outgoing_messages: IntCounterVec,
22+
kademlia_insert_contact_duration: Histogram,
23+
kademlia_iter_contacts_duration: Histogram,
1924
}
2025

2126
impl Default for MetricsP2P {
@@ -90,6 +95,26 @@ impl MetricsP2P {
9095
&["msg_type"],
9196
)
9297
.expect("Failed to create discv5_outgoing_messages metric"),
98+
kademlia_insert_contact_duration: Histogram::with_opts(
99+
HistogramOpts::new(
100+
"ethrex_kademlia_insert_contact_duration_seconds",
101+
"Duration of peer table contact insertion operations",
102+
)
103+
.buckets(vec![
104+
0.000_001, 0.000_005, 0.000_01, 0.000_05, 0.000_1, 0.000_5, 0.001, 0.01,
105+
]),
106+
)
107+
.expect("Failed to create kademlia_insert_contact_duration metric"),
108+
kademlia_iter_contacts_duration: Histogram::with_opts(
109+
HistogramOpts::new(
110+
"ethrex_kademlia_iter_contacts_duration_seconds",
111+
"Duration of peer table full-scan operations",
112+
)
113+
.buckets(vec![
114+
0.000_01, 0.000_05, 0.000_1, 0.000_5, 0.001, 0.005, 0.01, 0.05, 0.1,
115+
]),
116+
)
117+
.expect("Failed to create kademlia_iter_contacts_duration metric"),
93118
}
94119
}
95120

@@ -153,6 +178,14 @@ impl MetricsP2P {
153178
.inc();
154179
}
155180

181+
pub fn observe_insert_contact_duration(&self, duration_secs: f64) {
182+
self.kademlia_insert_contact_duration.observe(duration_secs);
183+
}
184+
185+
pub fn observe_iter_contacts_duration(&self, duration_secs: f64) {
186+
self.kademlia_iter_contacts_duration.observe(duration_secs);
187+
}
188+
156189
pub fn gather_metrics(&self) -> Result<String, MetricsError> {
157190
let r = Registry::new();
158191

@@ -174,6 +207,10 @@ impl MetricsP2P {
174207
.map_err(|e| MetricsError::PrometheusErr(e.to_string()))?;
175208
r.register(Box::new(self.discv5_outgoing_messages.clone()))
176209
.map_err(|e| MetricsError::PrometheusErr(e.to_string()))?;
210+
r.register(Box::new(self.kademlia_insert_contact_duration.clone()))
211+
.map_err(|e| MetricsError::PrometheusErr(e.to_string()))?;
212+
r.register(Box::new(self.kademlia_iter_contacts_duration.clone()))
213+
.map_err(|e| MetricsError::PrometheusErr(e.to_string()))?;
177214

178215
let encoder = TextEncoder::new();
179216
let metric_families = r.gather();

crates/networking/p2p/peer_table.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,9 @@ impl PeerTableServer {
938938

939939
/// Get closest nodes for discv4 (returns Vec<Node>)
940940
fn do_get_closest_nodes(&self, node_id: H256) -> Vec<Node> {
941+
#[cfg(feature = "metrics")]
942+
let scan_start = std::time::Instant::now();
943+
941944
let mut nodes: Vec<(Node, usize)> = vec![];
942945

943946
for (contact_id, contact) in &self.contacts {
@@ -953,6 +956,13 @@ impl PeerTableServer {
953956
}
954957
}
955958
}
959+
960+
#[cfg(feature = "metrics")]
961+
{
962+
use ethrex_metrics::p2p::METRICS_P2P;
963+
METRICS_P2P.observe_iter_contacts_duration(scan_start.elapsed().as_secs_f64());
964+
}
965+
956966
nodes.into_iter().map(|(node, _)| node).collect()
957967
}
958968

@@ -986,6 +996,9 @@ impl PeerTableServer {
986996
if self.discarded_contacts.contains(&node_id) || node_id == local_node_id {
987997
continue;
988998
}
999+
#[cfg(feature = "metrics")]
1000+
let insert_start = std::time::Instant::now();
1001+
9891002
match self.contacts.entry(node_id) {
9901003
Entry::Vacant(vacant_entry) => {
9911004
vacant_entry.insert(Contact::new(node, protocol));
@@ -996,6 +1009,12 @@ impl PeerTableServer {
9961009
occupied_entry.get_mut().add_protocol(protocol);
9971010
}
9981011
}
1012+
1013+
#[cfg(feature = "metrics")]
1014+
{
1015+
use ethrex_metrics::p2p::METRICS_P2P;
1016+
METRICS_P2P.observe_insert_contact_duration(insert_start.elapsed().as_secs_f64());
1017+
}
9991018
}
10001019
}
10011020

metrics/provisioning/grafana/dashboards/common_dashboards/p2p_packets.json

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,167 @@
459459
}
460460
]
461461
}
462+
,
463+
{
464+
"title": "Kademlia Table",
465+
"type": "row",
466+
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 63 },
467+
"id": 103,
468+
"collapsed": false
469+
},
470+
{
471+
"title": "insert_contact Duration (p50 / p99)",
472+
"description": "Duration of peer table contact insertion operations",
473+
"type": "timeseries",
474+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
475+
"gridPos": { "h": 10, "w": 12, "x": 0, "y": 64 },
476+
"id": 30,
477+
"fieldConfig": {
478+
"defaults": {
479+
"color": { "mode": "palette-classic" },
480+
"custom": {
481+
"axisBorderShow": false,
482+
"axisCenteredZero": false,
483+
"axisLabel": "",
484+
"drawStyle": "line",
485+
"fillOpacity": 10,
486+
"gradientMode": "none",
487+
"lineInterpolation": "smooth",
488+
"lineWidth": 2,
489+
"pointSize": 5,
490+
"showPoints": "never",
491+
"spanNulls": false,
492+
"stacking": { "group": "A", "mode": "none" },
493+
"thresholdsStyle": { "mode": "off" }
494+
},
495+
"unit": "s"
496+
},
497+
"overrides": []
498+
},
499+
"options": {
500+
"legend": { "calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "bottom" },
501+
"tooltip": { "mode": "multi", "sort": "desc" }
502+
},
503+
"targets": [
504+
{
505+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
506+
"editorMode": "code",
507+
"expr": "histogram_quantile(0.50, rate(ethrex_kademlia_insert_contact_duration_seconds_bucket{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval]))",
508+
"legendFormat": "p50",
509+
"refId": "A"
510+
},
511+
{
512+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
513+
"editorMode": "code",
514+
"expr": "histogram_quantile(0.99, rate(ethrex_kademlia_insert_contact_duration_seconds_bucket{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval]))",
515+
"legendFormat": "p99",
516+
"refId": "B"
517+
}
518+
]
519+
},
520+
{
521+
"title": "iter_contacts Full-Scan Duration (p50 / p99)",
522+
"description": "Duration of full peer table scans (e.g. get_closest_nodes)",
523+
"type": "timeseries",
524+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
525+
"gridPos": { "h": 10, "w": 12, "x": 12, "y": 64 },
526+
"id": 31,
527+
"fieldConfig": {
528+
"defaults": {
529+
"color": { "mode": "palette-classic" },
530+
"custom": {
531+
"axisBorderShow": false,
532+
"axisCenteredZero": false,
533+
"axisLabel": "",
534+
"drawStyle": "line",
535+
"fillOpacity": 10,
536+
"gradientMode": "none",
537+
"lineInterpolation": "smooth",
538+
"lineWidth": 2,
539+
"pointSize": 5,
540+
"showPoints": "never",
541+
"spanNulls": false,
542+
"stacking": { "group": "A", "mode": "none" },
543+
"thresholdsStyle": { "mode": "off" }
544+
},
545+
"unit": "s"
546+
},
547+
"overrides": []
548+
},
549+
"options": {
550+
"legend": { "calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "bottom" },
551+
"tooltip": { "mode": "multi", "sort": "desc" }
552+
},
553+
"targets": [
554+
{
555+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
556+
"editorMode": "code",
557+
"expr": "histogram_quantile(0.50, rate(ethrex_kademlia_iter_contacts_duration_seconds_bucket{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval]))",
558+
"legendFormat": "p50",
559+
"refId": "A"
560+
},
561+
{
562+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
563+
"editorMode": "code",
564+
"expr": "histogram_quantile(0.99, rate(ethrex_kademlia_iter_contacts_duration_seconds_bucket{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval]))",
565+
"legendFormat": "p99",
566+
"refId": "B"
567+
}
568+
]
569+
},
570+
{
571+
"title": "Peer Table Operations Rate",
572+
"description": "Rate of contact insertion and full-scan operations per second",
573+
"type": "timeseries",
574+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
575+
"gridPos": { "h": 10, "w": 24, "x": 0, "y": 74 },
576+
"id": 32,
577+
"fieldConfig": {
578+
"defaults": {
579+
"color": { "mode": "palette-classic" },
580+
"custom": {
581+
"axisBorderShow": false,
582+
"axisCenteredZero": false,
583+
"axisLabel": "ops/s",
584+
"drawStyle": "line",
585+
"fillOpacity": 20,
586+
"gradientMode": "scheme",
587+
"lineInterpolation": "smooth",
588+
"lineWidth": 2,
589+
"pointSize": 5,
590+
"showPoints": "never",
591+
"spanNulls": false,
592+
"stacking": { "group": "A", "mode": "none" },
593+
"thresholdsStyle": { "mode": "off" }
594+
},
595+
"unit": "ops"
596+
},
597+
"overrides": [
598+
{ "matcher": { "id": "byName", "options": "insert_contact" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] },
599+
{ "matcher": { "id": "byName", "options": "iter_contacts" }, "properties": [{ "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } }] }
600+
]
601+
},
602+
"options": {
603+
"legend": { "calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "bottom" },
604+
"tooltip": { "mode": "multi", "sort": "desc" }
605+
},
606+
"targets": [
607+
{
608+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
609+
"editorMode": "code",
610+
"expr": "rate(ethrex_kademlia_insert_contact_duration_seconds_count{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval])",
611+
"legendFormat": "insert_contact",
612+
"refId": "A"
613+
},
614+
{
615+
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" },
616+
"editorMode": "code",
617+
"expr": "rate(ethrex_kademlia_iter_contacts_duration_seconds_count{instance=~\"$instance(:\\\\d+)?$\"}[$__rate_interval])",
618+
"legendFormat": "iter_contacts",
619+
"refId": "B"
620+
}
621+
]
622+
}
462623
],
463624
"schemaVersion": 39,
464625
"tags": ["ethrex", "p2p"],

0 commit comments

Comments
 (0)