Skip to content

Commit

Permalink
Bug 1906853 - add glean probe for http3 udp datagram size r=necko-rev…
Browse files Browse the repository at this point in the history
…iewers,kershaw,janerik

This commit adds four Glean probes:
- http3_udp_datagram_segment_size_sent
- http3_udp_datagram_segment_size_received
- http3_udp_datagram_size_received
- http3_udp_datagram_num_segments_received

Given the performance impact tracking Glean metrics in the UDP hot path, see
https://phabricator.services.mozilla.com/D216034#7453056, this commit introduces
a sample buffer per metric.

This will enable us to measure the impact of:

- Implementation of Packetization Layer Path MTU Discovery for Datagram Transports (RFC 8899) [in Neqo](mozilla/neqo#1903)
- [Fast UDP for Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=1901292)

Differential Revision: https://phabricator.services.mozilla.com/D216034
  • Loading branch information
mxinden committed Sep 16, 2024
1 parent 5e44a3d commit c85cdce
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 3 deletions.
71 changes: 71 additions & 0 deletions netwerk/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1488,3 +1488,74 @@ networking:
- necko@mozilla.com
- acreskey@mozilla.com
expires: never

http_3_udp_datagram_segment_size_sent:
type: memory_distribution
memory_unit: byte
description: >
HTTP3 UDP datagram segment size sent.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_sensitivity:
- technical
notification_emails:
- necko@mozilla.com
- minden@mozilla.com
expires: never

http_3_udp_datagram_segment_size_received:
type: memory_distribution
memory_unit: byte
description: >
HTTP3 UDP datagram size received.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_sensitivity:
- technical
notification_emails:
- necko@mozilla.com
- minden@mozilla.com
expires: never

http_3_udp_datagram_size_received:
type: memory_distribution
memory_unit: byte
description: >
HTTP3 UDP datagram size received.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_sensitivity:
- technical
notification_emails:
- necko@mozilla.com
- minden@mozilla.com
expires: never

http_3_udp_datagram_segments_received:
type: custom_distribution
unit: integer
range_min: 0
# Maximum number of UDP segments per datagram.
#
# See e.g. Linux https://github.com/torvalds/linux/blob/20371ba120635d9ab7fc7670497105af8f33eb08/include/linux/udp.h#L111.
range_max: 128
bucket_count: 100
histogram_type: exponential
description: >
HTTP3 UDP number of segments per datagram received.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1906853
data_sensitivity:
- technical
notification_emails:
- necko@mozilla.com
- minden@mozilla.com
expires: never
29 changes: 26 additions & 3 deletions netwerk/socket/neqo_glue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ use uuid::Uuid;
use winapi::shared::ws2def::{AF_INET, AF_INET6};
use xpcom::{interfaces::nsISocketProvider, AtomicRefcnt, RefCounted, RefPtr};

/// Provides a buffered wrapper around [`firefox_on_glean`] metrics.
///
/// Enables instrumentation in the UDP IO hotpath, without a significant
/// performance overhead through instrumentation itself.
///
/// See also performance analysis without it in
/// <https://phabricator.services.mozilla.com/D216034#7453056>.
///
/// Will be replaced by <https://bugzilla.mozilla.org/show_bug.cgi?id=1915388>
/// once available.
mod metrics;

#[repr(C)]
pub struct NeqoHttp3Conn {
conn: Http3Client,
Expand All @@ -59,6 +71,7 @@ pub struct NeqoHttp3Conn {
impl Drop for NeqoHttp3Conn {
fn drop(&mut self) {
self.record_stats_in_glean();
metrics::METRICS.with_borrow_mut(|m| m.sync_to_glean());
}
}

Expand Down Expand Up @@ -543,12 +556,21 @@ pub unsafe extern "C" fn neqo_http3conn_process_input(
if dgrams.is_empty() {
break;
}
bytes_read += dgrams.iter().map(|d| d.len()).sum::<usize>();
if !static_prefs::pref!("network.http.http3.ecn") {
for dgram in &mut dgrams {

let mut sum = 0;
let ecn_enabled = static_prefs::pref!("network.http.http3.ecn");
for dgram in &mut dgrams {
if !ecn_enabled {
dgram.set_tos(Default::default());
}
metrics::METRICS
.with_borrow_mut(|m| m.datagram_segment_size_received.sample(dgram.len()));
sum += dgram.len();
}
metrics::METRICS.with_borrow_mut(|m| m.datagram_size_received.sample(sum));
metrics::METRICS.with_borrow_mut(|m| m.datagram_segments_received.sample(dgrams.len()));
bytes_read += sum;

conn.conn
.process_multiple_input(dgrams.iter(), Instant::now());
}
Expand Down Expand Up @@ -705,6 +727,7 @@ pub extern "C" fn neqo_http3conn_process_output_and_send(
}
}
bytes_written += dg.len();
metrics::METRICS.with_borrow_mut(|m| m.datagram_segment_size_sent.sample(dg.len()));
}
Output::Callback(to) => {
if to.is_zero() {
Expand Down
96 changes: 96 additions & 0 deletions netwerk/socket/neqo_glue/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::cell::RefCell;
#[cfg(not(target_os = "android"))]
use std::convert::{TryFrom, TryInto};

use firefox_on_glean::metrics::networking as glean;

#[cfg(not(target_os = "android"))]
const BUFFER_SIZE: usize = 1024;

std::thread_local! {
pub static METRICS: RefCell<BufferedMetrics> = RefCell::new(BufferedMetrics::default());
}

#[allow(dead_code)]
pub struct BufferedMetric<S> {
buffer: Vec<S>,
sync: fn(Vec<S>),
}

impl<S> BufferedMetric<S> {
fn new(f: fn(Vec<S>)) -> Self {
Self {
buffer: vec![],
sync: f,
}
}
}

#[cfg(not(target_os = "android"))]
impl<S: TryFrom<usize>> BufferedMetric<S> {
pub fn sample(&mut self, sample: usize) {
let Ok(sample) = sample.try_into() else {
neqo_common::qdebug!("failed to convert {sample} to metric's sample type");
return;
};
self.buffer.push(sample);
if self.buffer.len() == BUFFER_SIZE {
self.sync_to_glean();
}
}

fn sync_to_glean(&mut self) {
if !self.buffer.is_empty() {
(self.sync)(std::mem::take(&mut self.buffer));
}
}
}

// Noop on Android for now, due to performance regressions.
// - <https://bugzilla.mozilla.org/show_bug.cgi?id=1898810>
// - <https://bugzilla.mozilla.org/show_bug.cgi?id=1906664>
#[cfg(target_os = "android")]
impl<S> BufferedMetric<S> {
pub fn sample(&mut self, _sample: usize) {}

fn sync_to_glean(&mut self) {}
}

pub struct BufferedMetrics {
pub datagram_segment_size_sent: BufferedMetric<u64>,
pub datagram_segment_size_received: BufferedMetric<u64>,
pub datagram_size_received: BufferedMetric<u64>,
pub datagram_segments_received: BufferedMetric<i64>,
}

impl Default for BufferedMetrics {
fn default() -> Self {
Self {
datagram_segment_size_sent: BufferedMetric::new(|samples| {
glean::http_3_udp_datagram_segment_size_sent.accumulate_samples(samples)
}),
datagram_segment_size_received: BufferedMetric::new(|samples| {
glean::http_3_udp_datagram_segment_size_received.accumulate_samples(samples)
}),
datagram_size_received: BufferedMetric::new(|samples| {
glean::http_3_udp_datagram_size_received.accumulate_samples(samples)
}),
datagram_segments_received: BufferedMetric::new(|samples| {
glean::http_3_udp_datagram_segments_received.accumulate_samples_signed(samples)
}),
}
}
}

impl BufferedMetrics {
pub fn sync_to_glean(&mut self) {
self.datagram_segment_size_sent.sync_to_glean();
self.datagram_segment_size_received.sync_to_glean();
self.datagram_size_received.sync_to_glean();
self.datagram_segments_received.sync_to_glean();
}
}

0 comments on commit c85cdce

Please sign in to comment.