From 04f441e989ef073a69334ae313ee53c78724c348 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 7 Feb 2012 17:20:03 +0000 Subject: [PATCH] Commited sources of performance testing program and Jamfile.v2 to build and run it [SVN r76936] --- perf/Jamfile.v2 | 29 ++++ perf/performance_test.cpp | 309 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 perf/Jamfile.v2 create mode 100644 perf/performance_test.cpp diff --git a/perf/Jamfile.v2 b/perf/Jamfile.v2 new file mode 100644 index 0000000..78176be --- /dev/null +++ b/perf/Jamfile.v2 @@ -0,0 +1,29 @@ +#============================================================================== +# Copyright (c) 2012 Antony Polukhin +# +# 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) +#============================================================================== + +# performance tests +import testing ; +import path ; + +path-constant TEST_DIR : . ; + +project performance/test + : source-location ./ + : requirements +# /boost/chrono//boost_chrono +# /boost/system//boost_system + static + freebsd:"-lrt" + linux:"-lrt" + gcc:-fvisibility=hidden + intel-linux:-fvisibility=hidden + sun:-xldscope=hidden + : default-build release + ; + +run performance_test.cpp : $(TEST_DIR) ; + diff --git a/perf/performance_test.cpp b/perf/performance_test.cpp new file mode 100644 index 0000000..ff1eb1d --- /dev/null +++ b/perf/performance_test.cpp @@ -0,0 +1,309 @@ +// (C) Copyright Antony Polukhin 2012. +// Use, modification and distribution are subject to 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) + +// See http://www.boost.org/libs/config for most recent version. + +// +// Testing lexical_cast<> performance +// + +#define BOOST_ERROR_CODE_HEADER_ONLY +#define BOOST_CHRONO_HEADER_ONLY + +#include +#include +#include +#include + +// File to output data +std::fstream fout; + +template +static inline void test_lexical(const InT& in_val) { + OutT out_val = boost::lexical_cast(in_val); + (void)out_val; +} + +template +static inline void test_ss_constr(const InT& in_val) { + OutT out_val; + std::stringstream ss; + ss << in_val; + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); +} + +template +static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) { + OutT out_val; + ss << in_val; // ss is an instance of std::stringstream + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); + /* reseting std::stringstream to use it again */ + ss.str(std::string()); + ss.clear(); +} + +struct structure_sprintf { + template + static inline void test(BufferT* buffer, const InT& in_val, const char* const conv) { + sprintf(buffer, conv, in_val); + OutT out_val(buffer); + } + + template + static inline void test(BufferT* buffer, const std::string& in_val, const char* const conv) { + sprintf(buffer, conv, in_val.c_str()); + OutT out_val(buffer); + } +}; + +struct structure_sscanf { + template + static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) { + OutT out_val; + sscanf(reinterpret_cast(in_val), conv, &out_val); + } + + template + static inline void test(BufferT* /*buffer*/, const std::string& in_val, const char* const conv) { + OutT out_val; + sscanf(in_val.c_str(), conv, &out_val); + } +}; + +struct structure_fake { + template + static inline void test(BufferT* /*buffer*/, const InT& /*in_val*/, const char* const /*conv*/) {} +}; + +static const int fake_test_value = 9999; + +template +static inline void min_fancy_output(T v1, T v2, T v3, T v4) { + const char beg_mark[] = "!!! *"; + const char end_mark[] = "* !!!"; + const char no_mark[] = ""; + + unsigned int res = 4; + if (v1 < v2 && v1 < v3 && v1 < v4) res = 1; + if (v2 < v1 && v2 < v3 && v2 < v4) res = 2; + if (v3 < v1 && v3 < v2 && v3 < v4) res = 3; + + fout << "[ " + << (res == 1 ? beg_mark : no_mark) + ; + + if (v1) fout << v1; + else fout << "<1"; + + fout << (res == 1 ? end_mark : no_mark) + << " ][ " + << (res == 2 ? beg_mark : no_mark) + ; + + if (v2) fout << v2; + else fout << "<1"; + + fout << (res == 2 ? end_mark : no_mark) + << " ][ " + << (res == 3 ? beg_mark : no_mark) + ; + + if (v3) fout << v3; + else fout << "<1"; + + fout << (res == 3 ? end_mark : no_mark) + << " ][ " + << (res == 4 ? beg_mark : no_mark) + ; + + if (!v4) fout << "<1"; + else if (v4 == fake_test_value) fout << "---"; + else fout << v4; + + fout + << (res == 4 ? end_mark : no_mark) + << " ]"; +} + +template +static inline void perf_test_impl(const FromT& in_val, const char* const conv) { + + typedef boost::chrono::steady_clock test_clock; + test_clock::time_point start; + typedef boost::chrono::milliseconds duration_t; + duration_t lexical_cast_time, ss_constr_time, ss_noconstr_time, printf_time; + + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_lexical(in_val); + test_lexical(in_val); + test_lexical(in_val); + test_lexical(in_val); + } + lexical_cast_time = boost::chrono::duration_cast(test_clock::now() - start); + + + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_ss_constr(in_val); + test_ss_constr(in_val); + test_ss_constr(in_val); + test_ss_constr(in_val); + } + ss_constr_time = boost::chrono::duration_cast(test_clock::now() - start); + + std::stringstream ss; + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + } + ss_noconstr_time = boost::chrono::duration_cast(test_clock::now() - start); + + + char buffer[128]; + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + } + printf_time = boost::chrono::duration_cast(test_clock::now() - start); + + min_fancy_output( + lexical_cast_time.count(), + ss_constr_time.count(), + ss_noconstr_time.count(), + boost::is_same::value ? fake_test_value : printf_time.count() + ); +} + +template +static inline void perf_test(const std::string& test_name, const FromT& in_val, const char* const conv) { + const unsigned int ITERATIONSCOUNT = 100000; + fout << " [[ " << test_name << " ]"; + + perf_test_impl(in_val, conv); + + fout << "]\n"; +} + + +template +void string_like_test_set(const std::string& from) { + typedef structure_sscanf ssc_t; + ConverterT conv; + + perf_test(from + "->char", conv("c"), "%c"); + perf_test(from + "->signed char", conv("c"), "%hhd"); + perf_test(from + "->unsigned char", conv("c"), "%hhu"); + + perf_test(from + "->int", conv("100"), "%d"); + perf_test(from + "->short", conv("100"), "%hd"); + perf_test(from + "->long int", conv("100"), "%ld"); + perf_test(from + "->long long", conv("100"), "%lld"); + + perf_test(from + "->unsigned int", conv("100"), "%u"); + perf_test(from + "->unsigned short", conv("100"), "%hu"); + perf_test(from + "->unsigned long int", conv("100"), "%lu"); + perf_test(from + "->unsigned long long", conv("100"), "%llu"); + + // perf_test(from + "->bool", conv("1"), "%"); + + perf_test(from + "->float", conv("1.123"), "%f"); + perf_test(from + "->double", conv("1.123"), "%lf"); + perf_test(from + "->long double", conv("1.123"), "%Lf"); + + + perf_test(from + "->string", conv("string"), "%Lf"); + perf_test(from + "->container::string" + , conv("string"), "%Lf"); + +} + +struct to_string_conv { + std::string operator()(const char* const c) const { + return c; + } +}; + +struct to_char_conv { + const char* operator()(const char* const c) const { + return c; + } +}; + +struct to_uchar_conv { + const unsigned char* operator()(const char* const c) const { + return reinterpret_cast(c); + } +}; + + +struct to_schar_conv { + const signed char* operator()(const char* const c) const { + return reinterpret_cast(c); + } +}; + +int main(int argc, char** argv) { + BOOST_ASSERT(argc >= 2); + std::string output_path(argv[1]); + output_path += "/results.txt"; + fout.open(output_path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app); + BOOST_ASSERT(fout); + + fout << "[section " << BOOST_COMPILER << "]\n" + << "[table:id Performance Table ( "<< BOOST_COMPILER << ")\n" + << "[[From->To] [lexical_cast] [std::stringstream with construction] " + << "[std::stringstream without construction][scanf/printf]]\n"; + + + // From std::string to ... + string_like_test_set("string"); + + // From ... to std::string + perf_test("string->char", 'c', "%c"); + perf_test("string->signed char", static_cast('c'), "%hhd"); + perf_test("string->unsigned char", static_cast('c'), "%hhu"); + + perf_test("int->string", 100, "%d"); + perf_test("short->string", static_cast(100), "%hd"); + perf_test("long int->string", 100l, "%ld"); + perf_test("long long->string", 100ll, "%lld"); + + perf_test("unsigned int->string", static_cast(100u), "%u"); + perf_test("unsigned short->string", 100u, "%hu"); + perf_test("unsigned long int->string", 100ul, "%lu"); + perf_test("unsigned long long->string", static_cast(100), "%llu"); + + // perf_test("bool->string", std::string("1"), "%"); + + perf_test("float->string", 1.123f, "%f"); + perf_test("double->string", 1.123, "%lf"); + perf_test("long double->string", 1.123L, "%Lf"); + + + string_like_test_set("char*"); + string_like_test_set("unsigned char*"); + string_like_test_set("signed char*"); + + perf_test("int->int", 100, ""); + perf_test("float->double", 100.0f, ""); + perf_test("char->signed char", 'c', ""); + + fout << "]\n" + << "[endsect]\n\n"; + return 0; +} + +