1 //  benchmark.cpp  ---------------------------------------------------------------------//
2 
3 //  Copyright Beman Dawes 2011
4 
5 //  Distributed under the Boost Software License, Version 1.0.
6 //  http://www.boost.org/LICENSE_1_0.txt
7 
8 #ifndef _SCL_SECURE_NO_WARNINGS
9 # define _SCL_SECURE_NO_WARNINGS
10 #endif
11 
12 #ifndef _CRT_SECURE_NO_WARNINGS
13 # define _CRT_SECURE_NO_WARNINGS
14 #endif
15 
16 #include <cstdlib>
17 #include <boost/endian/conversion.hpp>
18 #include <boost/random.hpp>
19 #include <boost/cstdint.hpp>
20 #include <boost/timer/timer.hpp>
21 #include <iostream>
22 #include <string>
23 
24 using namespace boost;
25 using std::cout;
26 using std::cerr;
27 using std::endl;
28 using std::vector;
29 
30 namespace
31 {
32   std::string command_args;
33   long long n_cases;
34   int places = 2;
35   bool verbose (false);
36 
37 #ifndef BOOST_TWO_ARG
38   typedef int32_t (*timee_func)(int32_t);
39 #else
40   typedef void (*timee_func)(int32_t, int32_t&);
41 #endif
42 
43   typedef  boost::timer::nanosecond_type nanosecond_t;
44 
45 //--------------------------------------------------------------------------------------//
46 
benchmark(timee_func timee,const char * msg,nanosecond_t overhead=0)47   nanosecond_t benchmark(timee_func timee, const char* msg,
48     nanosecond_t overhead = 0)
49   //  Returns: total cpu time (i.e. system time + user time)
50   {
51     if (verbose)
52       cout << "\nRunning benchmark..." << endl;
53     int64_t sum = 0;
54     boost::timer::cpu_times times;
55     nanosecond_t cpu_time;
56     boost::timer::auto_cpu_timer t(places);
57 
58     for (long long i = n_cases; i; --i)
59     {
60 #   ifndef BOOST_TWO_ARG
61       sum += timee(static_cast<int32_t>(i)) ;
62 #   else
63       int32_t y;
64       timee(static_cast<int32_t>(i), y);
65       sum += y;
66 #   endif
67     }
68     t.stop();
69     times = t.elapsed();
70     cpu_time = (times.system + times.user) - overhead;
71     const long double sec = 1000000000.0L;
72     cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
73     cout.precision(places);
74     cout << msg << " " << cpu_time / sec << endl;
75 
76     if (verbose)
77     {
78       t.report();
79       cout << "  Benchmark complete\n"
80               "    sum is " << sum << endl;
81     }
82     return cpu_time;
83   }
84 
process_command_line(int argc,char * argv[])85   void process_command_line(int argc, char * argv[])
86   {
87     for (int a = 0; a < argc; ++a)
88     {
89       command_args += argv[a];
90       if (a != argc-1)
91         command_args += ' ';
92     }
93 
94     cout << command_args << '\n';;
95 
96     if (argc >=2)
97 #ifndef _MSC_VER
98       n_cases = std::atoll(argv[1]);
99 #else
100       n_cases = _atoi64(argv[1]);
101 #endif
102 
103     for (; argc > 2; ++argv, --argc)
104     {
105       if ( *(argv[2]+1) == 'p' )
106         places = atoi( argv[2]+2 );
107       else if ( *(argv[2]+1) == 'v' )
108         verbose = true;
109       else
110       {
111         cout << "Error - unknown option: " << argv[2] << "\n\n";
112         argc = -1;
113         break;
114       }
115     }
116 
117     if (argc < 2)
118     {
119       cout << "Usage: benchmark n [Options]\n"
120               "  The argument n specifies the number of test cases to run\n"
121               "  Options:\n"
122               "   -v       Verbose messages\n"
123               "   -p#      Decimal places for times; default -p" << places << "\n";
124       return std::exit(1);
125     }
126   }
127 
inplace(int32_t & x)128   inline void inplace(int32_t& x)
129   {
130     x =  (static_cast<uint32_t>(x) << 24)
131       | ((static_cast<uint32_t>(x) << 8) & 0x00ff0000)
132       | ((static_cast<uint32_t>(x) >> 8) & 0x0000ff00)
133       | (static_cast<uint32_t>(x) >> 24);
134   }
135 
by_return(int32_t x)136   inline int32_t by_return(int32_t x)
137   {
138     return (static_cast<uint32_t>(x) << 24)
139       | ((static_cast<uint32_t>(x) << 8) & 0x00ff0000)
140       | ((static_cast<uint32_t>(x) >> 8) & 0x0000ff00)
141       | (static_cast<uint32_t>(x) >> 24);
142   }
143 
by_return_intrinsic(int32_t x)144   inline int32_t by_return_intrinsic(int32_t x)
145   {
146     return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast<uint32_t>(x));
147   }
148 
by_return_pyry(int32_t x)149   inline int32_t by_return_pyry(int32_t x)
150   {
151     uint32_t step16;
152     step16 = static_cast<uint32_t>(x) << 16 | static_cast<uint32_t>(x) >> 16;
153     return
154         ((static_cast<uint32_t>(step16) << 8) & 0xff00ff00)
155       | ((static_cast<uint32_t>(step16) >> 8) & 0x00ff00ff);
156   }
157 
two_operand(int32_t x,int32_t & y)158   inline int32_t two_operand(int32_t x, int32_t& y)
159   {
160     return y = ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 24) & 0x000000ff)
161       | ((x >> 8) & 0x0000ff00);
162   }
163 
modify_noop(int32_t x)164   inline int32_t modify_noop(int32_t x)
165   {
166     int32_t v(x);
167     return v;
168   }
169 
modify_inplace(int32_t x)170   inline int32_t modify_inplace(int32_t x)
171   {
172     int32_t v(x);
173     inplace(v);
174     return v;
175   }
176 
modify_by_return(int32_t x)177   inline int32_t modify_by_return(int32_t x)
178   {
179     int32_t v(x);
180     return by_return(v);
181   }
182 
modify_by_return_pyry(int32_t x)183   inline int32_t modify_by_return_pyry(int32_t x)
184   {
185     int32_t v(x);
186     return by_return_pyry(v);
187   }
188 
modify_by_return_intrinsic(int32_t x)189   inline int32_t modify_by_return_intrinsic(int32_t x)
190   {
191     int32_t v(x);
192     return by_return_intrinsic(v);
193   }
194 
non_modify_assign(int32_t x,int32_t & y)195   inline void non_modify_assign(int32_t x, int32_t& y)
196   {
197     y = x;
198   }
199 
non_modify_two_operand(int32_t x,int32_t & y)200   inline void non_modify_two_operand(int32_t x, int32_t& y)
201   {
202     two_operand(x, y);
203   }
204 
non_modify_by_return(int32_t x,int32_t & y)205   inline void non_modify_by_return(int32_t x, int32_t& y)
206   {
207     y = by_return(x);
208   }
209 
210 } // unnamed namespace
211 
212 //-------------------------------------- main()  ---------------------------------------//
213 
main(int argc,char * argv[])214 int main(int argc, char * argv[])
215 {
216   process_command_line(argc, argv);
217 
218   nanosecond_t overhead;
219 
220 #ifndef BOOST_TWO_ARG
221   overhead = benchmark(modify_noop, "modify no-op");
222   benchmark(modify_inplace, "modify in place"/*, overhead*/);
223   benchmark(modify_by_return, "modify by return"/*, overhead*/);
224   benchmark(modify_by_return_pyry, "modify by return_pyry"/*, overhead*/);
225   benchmark(modify_by_return_intrinsic, "modify by return_intrinsic"/*, overhead*/);
226 #else
227   overhead = benchmark(non_modify_assign, "non_modify_assign     ");
228   benchmark(non_modify_two_operand,       "non_modify_two_operand", overhead);
229   benchmark(non_modify_by_return,         "non_modify_by_return  ", overhead);
230 #endif
231 
232   return 0;
233 }
234