From 1f41d66a125521f162fd4b4a3ca9095296c82048 Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sat, 26 Nov 2016 17:11:20 -0800 Subject: [PATCH] initial benchmarks --- server/benches/bind_conf/example.conf | 49 ++++++ server/benches/comparison_benches.rs | 222 ++++++++++++++++++++++++++ server/src/named.rs | 17 +- server/src/server/server.rs | 1 + 4 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 server/benches/bind_conf/example.conf create mode 100644 server/benches/comparison_benches.rs diff --git a/server/benches/bind_conf/example.conf b/server/benches/bind_conf/example.conf new file mode 100644 index 0000000000..a6654f09c6 --- /dev/null +++ b/server/benches/bind_conf/example.conf @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014, 2016 Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + */ + +/* Trust-DNS bench setup: this is meant to mimic the trust-dns-server config + which is in tests/named_test_configs/example.toml */ + +controls { /* empty */ }; + +options { + pid-file "/tmp/named.pid"; + listen-on { 127.0.0.1; }; + listen-on-v6 { none; }; + recursion no; +}; + +zone "localhost" { + type master; + file "../../server/tests/named_test_configs/default/localhost.zone"; +}; + +zone "0.0.127.in-addr.arpa" { + type master; + file "../../server/tests/named_test_configs/default/127.0.0.1.zone"; +}; + +zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" { + type master; + file "../../server/tests/named_test_configs/default/ipv6_1.zone"; +}; + +zone "255.in-addr.arpa" { + type master; + file "../../server/tests/named_test_configs/default/255.zone"; +}; + +zone "0.in-addr.arpa" { + type master; + file "../../server/tests/named_test_configs/default/0.zone"; +}; + +zone "example.com" { + type master; + file "../../server/tests/named_test_configs/example.com.zone"; +}; diff --git a/server/benches/comparison_benches.rs b/server/benches/comparison_benches.rs new file mode 100644 index 0000000000..3d2ee69dbf --- /dev/null +++ b/server/benches/comparison_benches.rs @@ -0,0 +1,222 @@ +#![feature(test)] + +extern crate futures; +extern crate test; +extern crate tokio_core; + +extern crate trust_dns; +extern crate trust_dns_server; + +use std::fs::DirBuilder; +use std::env; +use std::io::{BufRead, BufReader, Read, stdout, Write}; +use std::mem; +use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs}; +use std::path::Path; +use std::process::{Child, Command, Stdio}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +use test::Bencher; +use tokio_core::reactor::Core; + +use trust_dns::client::*; +use trust_dns::op::*; +use trust_dns::rr::*; +use trust_dns::udp::*; +use trust_dns::tcp::*; + +fn find_test_port() -> u16 { + let server = std::net::UdpSocket::bind(("0.0.0.0", 0)).unwrap(); + let server_addr = server.local_addr().unwrap(); + server_addr.port() +} + +struct NamedProcess{ named: Child, thread_notice: Arc } + +impl Drop for NamedProcess { + fn drop(&mut self) { + self.named.kill().expect("could not kill process"); + self.named.wait().expect("waiting failed"); + + self.thread_notice.store(true, Ordering::Relaxed); + } +} + +fn wrap_process(named: Child, io: R, started_str: &str) -> NamedProcess where R: Read + Send + 'static { + let mut named_out = BufReader::new(io); + + // we should get the correct output before 1000 lines... + let mut output = String::new(); + let mut found = false; + for _ in 0..1000 { + output.clear(); + named_out.read_line(&mut output).expect("could not read stdout"); + // stdout().write(b"SRV: ").unwrap(); + // stdout().write(output.as_bytes()).unwrap(); + if output.ends_with(started_str) { found = true; break } + } + + stdout().flush().unwrap(); + assert!(found, "server did not startup..."); + + let thread_notice = Arc::new(AtomicBool::new(false)); + let thread_notice_clone = thread_notice.clone(); + + thread::Builder::new().name("named stdout".into()).spawn(move ||{ + let thread_notice = thread_notice_clone; + while !thread_notice.load(std::sync::atomic::Ordering::Relaxed) { + output.clear(); + named_out.read_line(&mut output).expect("could not read stdout"); + // stdout().write(b"SRV: ").unwrap(); + // stdout().write(output.as_bytes()).unwrap(); + } + }).expect("no thread available"); + + // return handle to child process + NamedProcess{ named: named, thread_notice: thread_notice } +} + +/// Returns a NamedProcess (cleans the process up on drop), and a socket addr for connecting +/// to the server. +fn trust_dns_process() -> (NamedProcess, u16) { + // find a random port to listen on + let test_port = find_test_port(); + + let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned()); + + let mut named = Command::new(&format!("{}/../target/debug/named", server_path)) + .stdout(Stdio::piped()) + .arg("-q") + .arg(&format!("--config={}/tests/named_test_configs/example.toml", server_path)) + .arg(&format!("--zonedir={}/tests/named_test_configs", server_path)) + .arg(&format!("--port={}", test_port)) + .spawn() + .expect("failed to start named"); + // + + let stdout = mem::replace(&mut named.stdout, None).unwrap(); + let process = wrap_process(named, stdout, "awaiting connections...\n"); + // return handle to child process + (process, test_port) +} + +/// Runs the bench tesk using the specified client +fn bench(b: &mut Bencher, io_loop: &mut Core, client: &mut BasicClientHandle) { + let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]); + + // validate the request + let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)); + assert!(!response.is_err(), "request failed: {}", response.unwrap_err()); + + let response = response.unwrap(); + assert_eq!(response.get_response_code(), ResponseCode::NoError); + + let record = &response.get_answers()[0]; + if let &RData::A(ref address) = record.get_rdata() { + assert_eq!(address, &Ipv4Addr::new(127,0,0,1)); + } else { + assert!(false); + } + + b.iter(|| { + let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)); + response.unwrap() + }); +} + + +#[bench] +fn trust_dns_udp_bench(b: &mut Bencher) { + let (named, server_port) = trust_dns_process(); + + let mut io_loop = Core::new().unwrap(); + let addr: SocketAddr = ("127.0.0.1", server_port).to_socket_addrs().unwrap().next().unwrap(); + let (stream, sender) = UdpClientStream::new(addr, io_loop.handle()); + let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None); + + bench(b, &mut io_loop, &mut client); + + // cleaning up the named process + drop(named); +} + +#[bench] +fn trust_dns_tcp_bench(b: &mut Bencher) { + let (named, server_port) = trust_dns_process(); + + let mut io_loop = Core::new().unwrap(); + let addr: SocketAddr = ("127.0.0.1", server_port).to_socket_addrs().unwrap().next().unwrap(); + let (stream, sender) = TcpClientStream::new(addr, io_loop.handle()); + let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None); + + bench(b, &mut io_loop, &mut client); + + // cleaning up the named process + drop(named); +} + +// downloaded from https://www.isc.org/downloads/file/bind-9-11-0-p1/ +// cd bind-9-11-0-p1 +// .configure +// make +// export TDNS_BIND_PATH=${PWD}/bin/named/named +fn bind_process() -> (NamedProcess, u16) { + let test_port = find_test_port(); + + let bind_path = env::var("TDNS_BIND_PATH").unwrap_or("bind".to_owned()); + let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned()); + + // create the work directory + let working_dir = format!("{}/../target/bind_pwd", server_path); + if !Path::new(&working_dir).exists() { + DirBuilder::new().create(&working_dir).expect("failed to create dir"); + } + + let mut named = Command::new(bind_path) + .current_dir(&working_dir) + .stderr(Stdio::piped()) + .arg("-c").arg(&format!("../../server/benches/bind_conf/example.conf")) + //.arg("-d").arg("0") + .arg("-D").arg("TRust-DNS cmp bench") + .arg("-g") + .arg("-p").arg(&format!("{}", test_port)) + .spawn() + .expect("failed to start named"); + + // + let stderr = mem::replace(&mut named.stderr, None).unwrap(); + let process = wrap_process(named, stderr, "running\n"); + (process, test_port) +} + +#[bench] +fn bind_udp_bench(b: &mut Bencher) { + let (named, server_port) = bind_process(); + + let mut io_loop = Core::new().unwrap(); + let addr: SocketAddr = ("127.0.0.1", server_port).to_socket_addrs().unwrap().next().unwrap(); + let (stream, sender) = UdpClientStream::new(addr, io_loop.handle()); + let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None); + + bench(b, &mut io_loop, &mut client); + + // cleaning up the named process + drop(named); +} + +#[bench] +fn bind_tcp_bench(b: &mut Bencher) { + let (named, server_port) = bind_process(); + + let mut io_loop = Core::new().unwrap(); + let addr: SocketAddr = ("127.0.0.1", server_port).to_socket_addrs().unwrap().next().unwrap(); + let (stream, sender) = TcpClientStream::new(addr, io_loop.handle()); + let mut client = ClientFuture::new(stream, sender, io_loop.handle(), None); + + bench(b, &mut io_loop, &mut client); + + // cleaning up the named process + drop(named); +} diff --git a/server/src/named.rs b/server/src/named.rs index f6e6eac5c7..5f382b262f 100644 --- a/server/src/named.rs +++ b/server/src/named.rs @@ -63,6 +63,7 @@ use trust_dns_server::server::ServerFuture; // the Docopt usage string. // http://docopt.org +// TODO: add option for specifying list of addresses instead of just port. const USAGE: &'static str = " Usage: named [options] named (-h | --help | --version) @@ -273,7 +274,7 @@ pub fn main() { } banner(); - info!("awaiting connections..."); + println!("awaiting connections..."); if let Err(e) = server.listen() { error!("failed to listen: {}", e); } @@ -283,11 +284,11 @@ pub fn main() { } fn banner() { - println!(""); - println!(" o o o "); - println!(" | | | "); - println!(" -o- o-o o o o-o -o- o-o o-O o-o o-o "); - println!(" | | | | \\ | | | | | \\ "); - println!(" o o o--o o-o o o-o o o o-o "); - println!(""); + info!(""); + info!(" o o o "); + info!(" | | | "); + info!(" --O-- o-o o o o-o --O-- o-o o-O o-o o-o "); + info!(" | | | | \\ | | | | | \\ "); + info!(" o o o--o o-o o o-o o o o-o "); + info!(""); } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index a625b5a852..06362579ae 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -219,6 +219,7 @@ impl DnsHandler for TcpListener { } } +#[allow(unreachable_code)] // this has been deprecated impl DnsHandler for (UdpSocket, VecDeque) { fn handle(&mut self, events: EventSet, catalog: &Arc) -> (Option, Option<(DnsHandlerType, EventSet)>) { let ref socket = self.0;