diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c62a7cf..0c6dacc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Version 51 * Fix file_body::get() not setting the more flag correctly * Use BOOST_FALLTHROUGH * Use BOOST_STRINGIZE +* DynamicBuffer benchmarks API Changes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 02fb33ea..6bd5c950 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,28 +111,16 @@ endfunction() if ("${VARIANT}" STREQUAL "coverage") set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_BUILD_TYPE RELWITHDEBINFO) + "${CMAKE_CXX_FLAGS} -DBEAST_NO_BUFFER_BENCH=1 -fprofile-arcs -ftest-coverage") + set (CMAKE_BUILD_TYPE RELWITHDEBINFO) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") elseif ("${VARIANT}" STREQUAL "ubasan") set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/scripts/blacklist.supp") + "${CMAKE_CXX_FLAGS} -DBEAST_NO_BUFFER_BENCH=1 -funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/scripts/blacklist.supp") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined") set(CMAKE_BUILD_TYPE RELWITHDEBINFO) -elseif ("${VARIANT}" STREQUAL "asan") - set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -funsigned-char -fsanitize=address -fno-omit-frame-pointer") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - set(CMAKE_BUILD_TYPE RELWITHDEBINFO) - -elseif ("${VARIANT}" STREQUAL "usan") - set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/scripts/blacklist.supp -fno-omit-frame-pointer") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined") - set(CMAKE_BUILD_TYPE RELWITHDEBINFO) - elseif ("${VARIANT}" STREQUAL "debug") set(CMAKE_BUILD_TYPE DEBUG) diff --git a/Jamroot b/Jamroot index f3234aef..d3c513e3 100644 --- a/Jamroot +++ b/Jamroot @@ -54,9 +54,9 @@ if [ os.name ] = MACOSX variant coverage : - debug + release : - "-fprofile-arcs -ftest-coverage" + "-DBEAST_NO_BUFFER_BENCH=1 -fprofile-arcs -ftest-coverage" "-lgcov" ; @@ -64,34 +64,10 @@ variant ubasan : release : - "-funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fsanitize-blacklist=scripts/blacklist.supp" + "-DBEAST_NO_BUFFER_BENCH=1 -funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fsanitize-blacklist=scripts/blacklist.supp" "-fsanitize=address,undefined" ; -variant asan - : - release - : - "-funsigned-char -fsanitize=address -fno-omit-frame-pointer" - "-fsanitize=address" - ; - -variant msan - : - debug - : - "-fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-memory-use-after-dtor -fno-omit-frame-pointer" - "-fsanitize=memory" - ; - -variant usan - : - debug - : - "-fsanitize=undefined -fsanitize-blacklist=scripts/blacklist.supp -fno-omit-frame-pointer" - "-fsanitize=undefined" - ; - project beast : requirements . diff --git a/test/Jamfile b/test/Jamfile index a669bab2..9136c85b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -18,6 +18,7 @@ unit-test core-tests : ../extras/beast/unit_test/main.cpp core/async_result.cpp core/bind_handler.cpp + core/buffer_bench.cpp core/buffer_cat.cpp core/buffer_prefix.cpp core/buffered_read_stream.cpp diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index 9b012af0..76bc6c22 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable (core-tests ../../extras/beast/unit_test/main.cpp async_result.cpp bind_handler.cpp + buffer_bench.cpp buffer_cat.cpp buffer_prefix.cpp buffer_test.hpp diff --git a/test/core/buffer_bench.cpp b/test/core/buffer_bench.cpp new file mode 100644 index 00000000..aaa31068 --- /dev/null +++ b/test/core/buffer_bench.cpp @@ -0,0 +1,241 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { + +class buffer_bench_test : public beast::unit_test::suite +{ +public: + using size_type = std::uint64_t; + + class timer + { + using clock_type = + std::chrono::system_clock; + + clock_type::time_point when_; + + public: + using duration = + clock_type::duration; + + timer() + : when_(clock_type::now()) + { + } + + duration + elapsed() const + { + return clock_type::now() - when_; + } + }; + + inline + size_type + throughput(std::chrono::duration< + double> const& elapsed, std::size_t items) + { + using namespace std::chrono; + return static_cast( + 1 / (elapsed/items).count()); + } + + template + static + std::size_t + fill(MutableBufferSequence const& buffers) + { + std::size_t n = 0; + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + for(auto const& buffer : buffers) + { + std::fill( + buffer_cast(buffer), + buffer_cast(buffer) + + buffer_size(buffer), 0); + n += buffer_size(buffer); + } + return n; + } + + template + size_type + do_prepares(std::size_t repeat, + std::size_t count, std::size_t size) + { + timer t; + size_type total = 0; + for(auto i = repeat; i--;) + { + DynamicBuffer b; + for(auto j = count; j--;) + { + auto const n = fill(b.prepare(size)); + b.commit(n); + total += n; + } + } + return throughput(t.elapsed(), total); + } + + template + size_type + do_hints(std::size_t repeat, + std::size_t count, std::size_t size) + { + timer t; + size_type total = 0; + for(auto i = repeat; i--;) + { + DynamicBuffer b; + for(auto j = count; j--;) + { + for(auto remain = size; remain;) + { + using beast::detail::read_size_helper; + auto const n = fill(b.prepare( + read_size_helper(b, remain))); + b.commit(n); + remain -= n; + total += n; + } + } + } + return throughput(t.elapsed(), total); + } + + template + size_type + do_random(std::size_t repeat, + std::size_t count, std::size_t size) + { + timer t; + size_type total = 0; + for(auto i = repeat; i--;) + { + DynamicBuffer b; + for(auto j = count; j--;) + { + auto const n = fill(b.prepare( + 1 + (rand()%(2*size)))); + b.commit(n); + total += n; + } + } + return throughput(t.elapsed(), total); + } + + static + inline + void + do_trials_1(bool) + { + } + + template + void + do_trials_1(bool print, F0&& f, FN... fn) + { + timer t; + using namespace std::chrono; + static size_type constexpr den = 1024 * 1024; + if(print) + { + log << std::right << std::setw(10) << + ((f() + (den / 2)) / den) << " MB/s"; + log.flush(); + } + else + { + f(); + } + do_trials_1(print, fn...); + } + + template + void + do_trials(string_view name, + std::size_t trials, F0&& f0, FN... fn) + { + using namespace std::chrono; + // warm-up + do_trials_1(false, f0, fn...); + do_trials_1(false, f0, fn...); + while(trials--) + { + timer t; + log << std::left << std::setw(24) << name << ":"; + log.flush(); + do_trials_1(true, f0, fn...); + log << " " << + duration_cast(t.elapsed()).count() << "ms"; + log << std::endl; + } + } + + void + run() override + { + static std::size_t constexpr trials = 1; + static std::size_t constexpr repeat = 250; + std::vector> params; + params.emplace_back(1024, 1024); + params.emplace_back(512, 4096); + params.emplace_back(256, 32768); + log << std::endl; + for(auto const& param : params) + { + auto const count = param.first; + auto const size = param.second; + auto const s = std::string("count=") + std::to_string(count) + + ", size=" + std::to_string(size); + log << std::left << std::setw(24) << s << " " << + std::right << std::setw(15) << "prepare" << + std::right << std::setw(15) << "with hint" << + std::right << std::setw(15) << "random" << + std::endl; + do_trials("multi_buffer", trials, + [&](){ return do_prepares(repeat, count, size); } + ,[&](){ return do_hints (repeat, count, size); } + ,[&](){ return do_random (repeat, count, size); } + ); + do_trials("flat_buffer", trials, + [&](){ return do_prepares(repeat, count, size); } + ,[&](){ return do_hints (repeat, count, size); } + ,[&](){ return do_random (repeat, count, size); } + ); + do_trials("boost::asio::streambuf", trials, + [&](){ return do_prepares(repeat, count, size); } + ,[&](){ return do_hints (repeat, count, size); } + ,[&](){ return do_random (repeat, count, size); } + ); + log << std::endl; + } + pass(); + } +}; + +#if defined(NDEBUG) && ! BEAST_NO_BUFFER_BENCH +BEAST_DEFINE_TESTSUITE(buffer_bench,core,beast); +#endif + +} // beast