blob: 9cceadf9bcdc790200702fea44b96e087f37f582 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! High-level benchmarks.
//!
//! This module contains end-to-end and other high-level benchmarks for the
//! netstack.
use packet::Serializer;
use std::time::{Duration, Instant};
use test::{black_box, Bencher};
use crate::device::ethernet::EtherType;
use crate::device::{receive_frame, DeviceId, DeviceLayerEventDispatcher};
use crate::ip::IpProto;
use crate::testutil::{DummyEventDispatcherBuilder, DUMMY_CONFIG_V4};
use crate::transport::udp::UdpEventDispatcher;
use crate::transport::TransportLayerEventDispatcher;
use crate::wire::ethernet::{
EthernetFrameBuilder, ETHERNET_DST_MAC_BYTE_OFFSET, ETHERNET_HDR_LEN_NO_TAG,
ETHERNET_MIN_BODY_LEN_NO_TAG, ETHERNET_SRC_MAC_BYTE_OFFSET,
};
use crate::wire::ipv4::{
Ipv4PacketBuilder, IPV4_CHECKSUM_OFFSET, IPV4_MIN_HDR_LEN, IPV4_TTL_OFFSET,
};
use crate::{EventDispatcher, StackStateBuilder, TimerId};
#[derive(Default)]
struct BenchmarkEventDispatcher;
impl UdpEventDispatcher for BenchmarkEventDispatcher {
type UdpConn = ();
type UdpListener = ();
}
impl TransportLayerEventDispatcher for BenchmarkEventDispatcher {}
impl DeviceLayerEventDispatcher for BenchmarkEventDispatcher {
// Override send_frame to have no code at all (rather than a
// log_unimplemented! call).
fn send_frame(&mut self, device: DeviceId, frame: &[u8]) {}
}
impl EventDispatcher for BenchmarkEventDispatcher {
fn schedule_timeout(&mut self, duration: Duration, id: TimerId) -> Option<Instant> {
unimplemented!()
}
fn schedule_timeout_instant(&mut self, time: Instant, id: TimerId) -> Option<Instant> {
unimplemented!()
}
fn cancel_timeout(&mut self, id: TimerId) -> Option<Instant> {
unimplemented!()
}
}
// Benchmark the minimum possible time to forward by stripping out all
// interesting computation. We have the simplest possible setup - a forwarding
// table with a single entry, and a single device - and we receive an IP packet
// frame which we expect will be parsed and forwarded without requiring any new
// buffers to be allocated.
//
// As of Change-Id Iaa22ea23620405dadd0b4f58d112781b29890a46, on a 2018 MacBook
// Pro, this benchmark takes in the neighborhood of 96ns - 100ns for all frame
// sizes.
fn bench_forward_minimum(b: &mut Bencher, frame_size: usize) {
let mut state_builder = StackStateBuilder::default();
state_builder.ip_builder().forward(true);
let mut ctx = DummyEventDispatcherBuilder::from_config(DUMMY_CONFIG_V4)
.build_with::<BenchmarkEventDispatcher>(state_builder, BenchmarkEventDispatcher);
assert!(
frame_size
>= ETHERNET_HDR_LEN_NO_TAG
+ std::cmp::max(ETHERNET_MIN_BODY_LEN_NO_TAG, IPV4_MIN_HDR_LEN)
);
let mut body = vec![0; frame_size - (ETHERNET_HDR_LEN_NO_TAG + IPV4_MIN_HDR_LEN)];
let mut buf = body
.encapsulate(Ipv4PacketBuilder::new(
// Use the remote IP as the destination so that we decide to
// forward.
DUMMY_CONFIG_V4.remote_ip,
DUMMY_CONFIG_V4.remote_ip,
64,
IpProto::Udp,
))
.encapsulate(EthernetFrameBuilder::new(
DUMMY_CONFIG_V4.remote_mac,
DUMMY_CONFIG_V4.local_mac,
EtherType::Ipv4,
))
.serialize_outer()
.unwrap();
let device = DeviceId::new_ethernet(1);
b.iter(|| {
let buf = buf.as_mut();
black_box(receive_frame(black_box(&mut ctx), black_box(device), black_box(buf)));
// Since we modified the buffer in-place, it now has the wrong source
// and destination MAC addresses and IP TTL. We reset them to their
// original values as efficiently as we can to avoid affecting the
// results of the benchmark.
(&mut buf[ETHERNET_SRC_MAC_BYTE_OFFSET..ETHERNET_SRC_MAC_BYTE_OFFSET + 6])
.copy_from_slice(&DUMMY_CONFIG_V4.remote_mac.bytes()[..]);
(&mut buf[ETHERNET_DST_MAC_BYTE_OFFSET..ETHERNET_DST_MAC_BYTE_OFFSET + 6])
.copy_from_slice(&DUMMY_CONFIG_V4.local_mac.bytes()[..]);
buf[ETHERNET_HDR_LEN_NO_TAG + IPV4_TTL_OFFSET] = 64;
buf[IPV4_CHECKSUM_OFFSET] = 249;
buf[IPV4_CHECKSUM_OFFSET + 1] = 102;
});
}
#[bench]
fn bench_forward_minimum_64(b: &mut Bencher) {
bench_forward_minimum(b, 64);
}
#[bench]
fn bench_forward_minimum_128(b: &mut Bencher) {
bench_forward_minimum(b, 128);
}
#[bench]
fn bench_forward_minimum_256(b: &mut Bencher) {
bench_forward_minimum(b, 256);
}
#[bench]
fn bench_forward_minimum_512(b: &mut Bencher) {
bench_forward_minimum(b, 512);
}
#[bench]
fn bench_forward_minimum_1024(b: &mut Bencher) {
bench_forward_minimum(b, 1024);
}