Я хотел протестировать запросы от ржавчины к конкретной службе с помощью async-клиента и создал для этого тестер async.
Эта функция должна запускать указанное количество параллельных потоков (фактически, параллельных цепочек фьючерсов) в течение указанной продолжительности и сообщать о количестве достигнутых итераций.
use futures::future;
use futures::prelude::*;
use std::error::Error;
use std::time::{Duration, Instant};
use std::{cell, io, rc};
use tokio::runtime::current_thread::Runtime;
use tokio::timer;
struct Config {
workers: u32,
duration: Duration,
}
/// Build infinitely repeating future
fn cycle<'a, F: Fn() -> P + 'a, P: Future + 'a>(
f: F,
) -> Box<dyn Future<Item = (), Error = P::Error> + 'a> {
Box::new(f().and_then(move |_| cycle(f)))
}
fn benchmark<'a, F: Fn() -> P + 'a, P: Future<Error = io::Error> + 'a>(
config: Config,
f: F,
) -> impl Future<Item = u32, Error = io::Error> + 'a {
let counter = rc::Rc::new(cell::Cell::new(0u32));
let f = rc::Rc::new(f);
future::select_all((0..config.workers).map({
let counter = rc::Rc::clone(&counter);
move |_| {
let counter = rc::Rc::clone(&counter);
let f = rc::Rc::clone(&f);
cycle(move || {
let counter = rc::Rc::clone(&counter);
f().map(move |_| {
counter.set(counter.get() + 1);
})
})
}
}))
.map(|((), _, _)| ())
.map_err(|(err, _, _)| err)
.select(
timer::Delay::new(Instant::now() + config.duration)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.description())),
)
.map(move |((), _)| counter.get())
.map_err(|(err, _)| err)
}
fn main() {
let duration = std::env::args()
.skip(1)
.next()
.expect("Please provide duration in seconds")
.parse()
.expect("Duration must be integer number");
let ms = Duration::from_millis(1);
let mut rt = Runtime::new().expect("Could not create runtime");
loop {
let iters = rt
.block_on(
benchmark(
Config {
workers: 65536,
duration: Duration::from_secs(duration),
},
|| {
/// Substitute actual benchmarked call
timer::Delay::new(Instant::now() + ms)
.map_err(|err| panic!("Failed to set delay: {:?}", err))
},
)
.map_err(|err| panic!("Benchamrking error: {:?}", err)),
)
.expect("Runtime error");
println!("{} iters/sec", iters as u64 / duration);
}
}
Однако результат этого теста и потребление памяти ухудшаются с увеличением продолжительности теста, например на моем компьютере:
cargo run --release 1
~ 900 тыс. Итераций / сек cargo run --release 2
~ 700 тыс. Итераций / сек cargo run --release 10
~ 330 тыс. Итераций / сек
Кроме того, использование памяти быстро растет по мере выполнения функции тестирования. Я попытался использовать valgrind
для поиска утечки памяти, но он сообщает только о том, что вся выделенная память все еще доступна.
Как я могу исправить проблему?
iters as u64 / duration
, который просто не имеет для меня смысла - person Stargateur   schedule 11.07.2019Box
, возвращаемыйcycle
, не освобождается до концаfuture::select_all
, и это объясняет увеличение потребления памяти. - person Grégory OBANOS   schedule 11.07.2019