$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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;
 }
-