|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r55083 - in trunk/libs/spirit/benchmarks: . qi
From: joel_at_[hidden]
Date: 2009-07-22 12:54:20
Author: djowel
Date: 2009-07-22 12:54:20 EDT (Wed, 22 Jul 2009)
New Revision: 55083
URL: http://svn.boost.org/trac/boost/changeset/55083
Log:
Updates to boilerplate benchmark code
Text files modified:
trunk/libs/spirit/benchmarks/boiler_plate.cpp | 38 ++++--
trunk/libs/spirit/benchmarks/measure.hpp | 77 ++++++++------
trunk/libs/spirit/benchmarks/qi/uint_parser.cpp | 220 ++++-----------------------------------
3 files changed, 93 insertions(+), 242 deletions(-)
Modified: trunk/libs/spirit/benchmarks/boiler_plate.cpp
==============================================================================
--- trunk/libs/spirit/benchmarks/boiler_plate.cpp (original)
+++ trunk/libs/spirit/benchmarks/boiler_plate.cpp 2009-07-22 12:54:20 EDT (Wed, 22 Jul 2009)
@@ -4,8 +4,11 @@
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)
==============================================================================*/
+
+// determine the type of the live_code. we can use this to test the
+// result of the code we are benchmarking
+#define BOOST_SPIRIT_TEST_LIVE_CODE_TYPE long long
#include "measure.hpp"
-#include <iostream>
namespace
{
@@ -13,12 +16,17 @@
{
typedef int type;
- void operator()(int x)
+ void benchmark(int x)
{
- this->val ^= x; // here is where you put code that you want
+ this->val += x; // Here is where you put code that you want
// to benchmark. Make sure it returns something.
// Anything.
}
+
+ static int initial()
+ {
+ return 1; // our initial value
+ }
int val; // this is where the value is accumulated
};
@@ -26,17 +34,15 @@
int main()
{
- int result;
- double base_time;
- int ret = test::run<f>(result, base_time, 100);
-
- std::cout
- << "f accumulated result: "
- << result
- << std::endl
- << "f time: "
- << base_time
- << std::endl;
-
- return ret;
+ BOOST_SPIRIT_TEST_BENCHMARK(
+ 1000000, // This is the maximum repetitions to execute
+ (f) // Place your tests here. For now, we have only one test: (f)
+ // If you have 3 tests a, b and c, this line will contain (a)(b)(c)
+ )
+
+ // This is ultimately responsible for preventing all the test code
+ // from being optimized away. Change this to return 0 and you
+ // unplug the whole test's life support system.
+ return test::live_code != 0;
}
+
Modified: trunk/libs/spirit/benchmarks/measure.hpp
==============================================================================
--- trunk/libs/spirit/benchmarks/measure.hpp (original)
+++ trunk/libs/spirit/benchmarks/measure.hpp 2009-07-22 12:54:20 EDT (Wed, 22 Jul 2009)
@@ -2,6 +2,8 @@
// 2005. 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)
+#if !defined(BOOST_SPIRIT_TEST_BENCHMARK_HPP)
+#define BOOST_SPIRIT_TEST_BENCHMARK_HPP
#ifdef _MSC_VER
// inline aggressively
@@ -10,11 +12,14 @@
# define _SECURE_SCL 0
#endif
-#if !defined(LIVE_CODE_TYPE)
-# define LIVE_CODE_TYPE int
+#if !defined(BOOST_SPIRIT_TEST_LIVE_CODE_TYPE)
+# define BOOST_SPIRIT_TEST_LIVE_CODE_TYPE int
#endif
#include "high_resolution_timer.hpp"
+#include <iostream>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include <boost/preprocessor/stringize.hpp>
namespace test
{
@@ -22,12 +27,12 @@
// code elimination doesn't optimize away anything we're testing.
// We'll use it to compute the return code of the executable to make
// sure it's needed.
- LIVE_CODE_TYPE live_code;
+ BOOST_SPIRIT_TEST_LIVE_CODE_TYPE live_code;
// Call objects of the given Accumulator type repeatedly with x as
// an argument.
- template <class Accumulator, class Arg>
- void hammer(Arg const& x, long const repeats)
+ template <class Accumulator>
+ void hammer(long const repeats)
{
// Strategy: because the sum in an accumulator after each call
// depends on the previous value of the sum, the CPU's pipeline
@@ -50,6 +55,8 @@
// or L3 cache, or main memory, you can increase the size of
// this array. 1024 is an upper limit on the pipeline depth of
// current vector machines.
+
+ typename Accumulator::type x = Accumulator::initial();
const std::size_t number_of_accumulators = 1024;
live_code = 0; // reset to zero
@@ -59,7 +66,7 @@
{
for (Accumulator* ap = a; ap < a + number_of_accumulators; ++ap)
{
- (*ap)(x);
+ ap->benchmark(x);
}
}
@@ -73,42 +80,46 @@
// Measure the time required to hammer accumulators of the given
// type with the argument x.
- template <class Accumulator, class T>
- double measure(T const& x, long const repeats)
+ template <class Accumulator>
+ double measure(long const repeats)
{
// Hammer accumulators a couple of times to ensure the
// instruction cache is full of our test code, and that we don't
// measure the cost of a page fault for accessing the data page
// containing the memory where the accumulators will be
// allocated
- hammer<Accumulator>(x, repeats);
- hammer<Accumulator>(x, repeats);
+ hammer<Accumulator>(repeats);
+ hammer<Accumulator>(repeats);
// Now start a timer
util::high_resolution_timer time;
- hammer<Accumulator>(x, repeats); // This time, we'll measure
+ hammer<Accumulator>(repeats); // This time, we'll measure
return time.elapsed() / repeats; // return the time of one iteration
}
-
- template <typename Accumulator>
- static int run(typename Accumulator::type& result, double& base_time, long repeats = 100)
- {
- double measured = 0;
- while (measured < 2.0 && repeats <= 10000000)
- {
- repeats *= 10;
- util::high_resolution_timer time;
- test::hammer<Accumulator>(0, repeats);
- measured = time.elapsed();
- }
-
- test::measure<Accumulator>(1, 1);
- result = test::live_code;
- base_time = test::measure<Accumulator>(1, repeats);
-
- // This is ultimately responsible for preventing all the test code
- // from being optimized away. Change this to return 0 and you
- // unplug the whole test's life support system.
- return test::live_code != 0;
- }
+
+#define BOOST_SPIRIT_TEST_HAMMER(r, data, elem) \
+ test::hammer<elem>(repeats);
+ /***/
+
+#define BOOST_SPIRIT_TEST_MEASURE(r, data, elem) \
+ std::cout \
+ << BOOST_PP_STRINGIZE(elem) << ": " \
+ << test::measure<elem>(repeats) \
+ << std::endl;
+ /***/
+
+#define BOOST_SPIRIT_TEST_BENCHMARK(max_repeats, FSeq) \
+ long repeats = 100; \
+ double measured = 0; \
+ while (measured < 2.0 && repeats <= max_repeats) \
+ { \
+ repeats *= 10; \
+ util::high_resolution_timer time; \
+ BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_TEST_HAMMER, _, FSeq) \
+ measured = time.elapsed(); \
+ } \
+ BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_TEST_MEASURE, _, FSeq) \
+ /***/
}
+
+#endif
\ No newline at end of file
Modified: trunk/libs/spirit/benchmarks/qi/uint_parser.cpp
==============================================================================
--- trunk/libs/spirit/benchmarks/qi/uint_parser.cpp (original)
+++ trunk/libs/spirit/benchmarks/qi/uint_parser.cpp 2009-07-22 12:54:20 EDT (Wed, 22 Jul 2009)
@@ -3,206 +3,40 @@
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)
-=============================================================================*/
-#if defined(BOOST_MSVC)
-#pragma inline_depth(255)
-#pragma inline_recursion(on)
-#define _SECURE_SCL 0
-#endif // defined(BOOST_MSVC)
-
-#include "../high_resolution_timer.hpp"
-#include <boost/spirit/include/qi.hpp>
-#include <boost/lexical_cast.hpp>
-#include <climits>
-#include <cstdlib>
-#include <string>
-#include <vector>
-#include <sstream>
+==============================================================================*/
+#include "measure.hpp"
+#include <iostream>
-#define MAX_ITERATION 1000000
-
-void check(int a, int b)
+namespace
{
- if (a != b)
- {
- std::cout << "Parse Error, got: " << a << " and " << b << std::endl;
- abort();
- }
-}
-
-int main()
-{
- namespace qi = boost::spirit::qi;
- using qi::int_;
-
- std::cout << "initializing input strings..." << std::endl;
- std::vector<int> src(MAX_ITERATION);
- std::vector<std::string> src_str(MAX_ITERATION);
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- src[i] = std::rand() * std::rand();
- if (std::rand() % 2)
- src[i] = -src[i];
- src_str[i] = boost::lexical_cast<std::string>(src[i]);
- }
-
- // test the C libraries atoi function (the most low level function for
- // string conversion available)
- {
- std::vector<int> v(MAX_ITERATION);
- std::vector<char const*> f(MAX_ITERATION);
-
- // get the C string
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- f[i] = src_str[i].c_str();
- }
-
- util::high_resolution_timer t;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- v[i] = atoi(f[i]);
- }
-
- std::cout << "atoi: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
-
- // test the C libraries strtol function (the most low level function for
- // string conversion available)
- {
- std::vector<int> v(MAX_ITERATION);
- std::vector<char const*> f(MAX_ITERATION);
-
- // get the C string
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- f[i] = src_str[i].c_str();
- }
-
- util::high_resolution_timer t;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- v[i] = strtol(f[i], 0, 10);
- }
-
- std::cout << "strtol: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
-
- // test sscanf
- {
- std::vector<int> v(MAX_ITERATION);
- std::vector<char const*> f(MAX_ITERATION);
-
- // get the C string
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- f[i] = src_str[i].c_str();
- }
-
- util::high_resolution_timer t;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- sscanf(f[i], "%d", &v[i]);
- }
-
- std::cout << "sscanf: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
-
- // test iostream
+ struct f
{
- std::istringstream ss;
- std::vector<int> v(MAX_ITERATION);
- util::high_resolution_timer t;
+ typedef int type;
- for (int i = 0; i < MAX_ITERATION; ++i)
+ void operator()(int x)
{
- ss.clear();
- ss.str(src_str[i]);
- ss >> v[i];
+ this->val ^= x; // here is where you put code that you want
+ // to benchmark. Make sure it returns something.
+ // Anything.
}
- std::cout << "std::iostream: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
-
- // test boost::lexical_cast
- {
- std::vector<int> v(MAX_ITERATION);
- std::vector<char const*> f(MAX_ITERATION);
-
- // get the C string
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- f[i] = src_str[i].c_str();
- }
-
- util::high_resolution_timer t;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- v[i] = boost::lexical_cast<int>(src[i]);
- }
-
- std::cout << "boost::lexical_cast: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
-
- // test the Qi int_ parser routines
- {
- std::vector<int> v(MAX_ITERATION);
- std::vector<char const*> f(MAX_ITERATION);
- std::vector<char const*> l(MAX_ITERATION);
-
- // get the first/last iterators
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- f[i] = src_str[i].c_str();
- l[i] = f[i];
- while (*l[i])
- l[i]++;
- }
-
- util::high_resolution_timer t;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- qi::parse(f[i], l[i], int_, v[i]);
- }
+ int val; // this is where the value is accumulated
+ };
+}
- std::cout << "spirit int_: " << t.elapsed() << " [s]" << std::flush << std::endl;
-
- for (int i = 0; i < MAX_ITERATION; ++i)
- {
- check(v[i], src[i]);
- }
- }
+int main()
+{
+ int result;
+ double base_time;
+ int ret = test::run<f>(result, base_time, 100);
+
+ std::cout
+ << "f accumulated result: "
+ << result
+ << std::endl
+ << "f time: "
+ << base_time
+ << std::endl;
- return 0;
+ return ret;
}
-
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk