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