1
2 // Copyright Oliver Kowalke 2009.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #define BOOST_PP_LIMIT_MAG 10
8
9 #include <cstdio>
10 #include <cstdlib>
11 #include <iostream>
12 #include <stdexcept>
13
14 #include <boost/assert.hpp>
15 #include <boost/bind.hpp>
16 #include <boost/function.hpp>
17 #include <boost/config.hpp>
18 #include <boost/context/all.hpp>
19 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
20 #include <boost/program_options.hpp>
21
22 #include "../example/simple_stack_allocator.hpp"
23
24 #ifdef BOOST_USE_UCONTEXT
25 #include <ucontext.h>
26 #endif
27
28 #include "bind_processor.hpp"
29 #include "cycle.hpp"
30
31 #if _POSIX_C_SOURCE >= 199309L
32 #include "zeit.hpp"
33 #endif
34
35 namespace ctx = boost::context;
36
37 typedef ctx::simple_stack_allocator<
38 8 * 1024 * 1024, // 8MB
39 64 * 1024, // 64kB
40 8 * 1024 // 8kB
41 > stack_allocator;
42
43 bool pres_fpu = false;
44
45 #define CALL_FCONTEXT(z,n,unused) ctx::jump_fcontext( & fcm, fc, 7, pres_fpu);
46
47 #ifdef BOOST_USE_UCONTEXT
48 # define CALL_UCONTEXT(z,n,unused) ::swapcontext( & ucm, & uc);
49 #endif
50
51 #define CALL_FUNCTION(z,n,unused) fn();
52
53
54 ctx::fcontext_t fcm, * fc;
55
56 #ifdef BOOST_USE_UCONTEXT
57 ucontext_t uc, ucm;
58 #endif
59
60
f1(intptr_t)61 static void f1( intptr_t)
62 { while ( true) ctx::jump_fcontext( fc, & fcm, 7, pres_fpu); }
63
64 #ifdef BOOST_USE_UCONTEXT
f2()65 static void f2()
66 { while ( true) ::swapcontext( & uc, & ucm); }
67 #endif
68
f3()69 static void f3()
70 {}
71
72
73 #ifdef BOOST_CONTEXT_CYCLE
test_fcontext_cycle(cycle_t ov)74 cycle_t test_fcontext_cycle( cycle_t ov)
75 {
76 stack_allocator alloc;
77 fc = ctx::make_fcontext(
78 alloc.allocate(stack_allocator::default_stacksize()),
79 stack_allocator::default_stacksize(),
80 f1);
81
82 ctx::jump_fcontext( & fcm, fc, 7, pres_fpu);
83
84 // cache warum-up
85 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~)
86
87 cycle_t start( cycles() );
88 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~)
89 cycle_t total( cycles() - start);
90
91 // we have two jumps and two measuremt-overheads
92 total -= ov; // overhead of measurement
93 total /= BOOST_PP_LIMIT_MAG; // per call
94 total /= 2; // 2x jump_to c1->c2 && c2->c1
95
96 return total;
97 }
98
99 # ifdef BOOST_USE_UCONTEXT
test_ucontext_cycle(cycle_t ov)100 cycle_t test_ucontext_cycle( cycle_t ov)
101 {
102 stack_allocator alloc;
103
104 ::getcontext( & uc);
105 uc.uc_stack.ss_sp = alloc.allocate(stack_allocator::default_stacksize());
106 uc.uc_stack.ss_size = stack_allocator::default_stacksize();
107 ::makecontext( & uc, f2, 7);
108
109 // cache warum-up
110 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~)
111
112 cycle_t start( cycles() );
113 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~)
114 cycle_t total( cycles() - start);
115
116 // we have two jumps and two measuremt-overheads
117 total -= ov; // overhead of measurement
118 total /= BOOST_PP_LIMIT_MAG; // per call
119 total /= 2; // 2x jump_to c1->c2 && c2->c1
120
121 return total;
122 }
123 # endif
124
test_function_cycle(cycle_t ov)125 cycle_t test_function_cycle( cycle_t ov)
126 {
127 boost::function< void() > fn( boost::bind( f3) );
128 // cache warum-up
129 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~)
130
131 cycle_t start( cycles() );
132 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~)
133 cycle_t total( cycles() - start);
134
135 // we have two jumps and two measuremt-overheads
136 total -= ov; // overhead of measurement
137 total /= BOOST_PP_LIMIT_MAG; // per call
138 total /= 2; // 2x jump_to c1->c2 && c2->c1
139
140 return total;
141 }
142 #endif
143
144
145 #if _POSIX_C_SOURCE >= 199309L
test_fcontext_zeit(zeit_t ov)146 zeit_t test_fcontext_zeit( zeit_t ov)
147 {
148 stack_allocator alloc;
149 fc = ctx::make_fcontext(
150 alloc.allocate(stack_allocator::default_stacksize()),
151 stack_allocator::default_stacksize(),
152 f1);
153
154 ctx::jump_fcontext( & fcm, fc, 7, pres_fpu);
155
156 // cache warum-up
157 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~)
158
159 zeit_t start( zeit() );
160 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~)
161 zeit_t total( zeit() - start);
162
163 // we have two jumps and two measuremt-overheads
164 total -= ov; // overhead of measurement
165 total /= BOOST_PP_LIMIT_MAG; // per call
166 total /= 2; // 2x jump_to c1->c2 && c2->c1
167
168 return total;
169 }
170
171 # ifdef BOOST_USE_UCONTEXT
test_ucontext_zeit(zeit_t ov)172 zeit_t test_ucontext_zeit( zeit_t ov)
173 {
174 stack_allocator alloc;
175
176 ::getcontext( & uc);
177 uc.uc_stack.ss_sp = alloc.allocate(stack_allocator::default_stacksize());
178 uc.uc_stack.ss_size = stack_allocator::default_stacksize();
179 ::makecontext( & uc, f2, 7);
180
181 // cache warum-up
182 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~)
183
184 zeit_t start( zeit() );
185 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~)
186 zeit_t total( zeit() - start);
187
188 // we have two jumps and two measuremt-overheads
189 total -= ov; // overhead of measurement
190 total /= BOOST_PP_LIMIT_MAG; // per call
191 total /= 2; // 2x jump_to c1->c2 && c2->c1
192
193 return total;
194 }
195 # endif
196
test_function_zeit(zeit_t ov)197 zeit_t test_function_zeit( zeit_t ov)
198 {
199 boost::function< void() > fn( boost::bind( f3) );
200 // cache warum-up
201 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~)
202
203 zeit_t start( zeit() );
204 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~)
205 zeit_t total( zeit() - start);
206
207 // we have two jumps and two measuremt-overheads
208 total -= ov; // overhead of measurement
209 total /= BOOST_PP_LIMIT_MAG; // per call
210 total /= 2; // 2x jump_to c1->c2 && c2->c1
211
212 return total;
213 }
214 #endif
215
main(int argc,char * argv[])216 int main( int argc, char * argv[])
217 {
218 try
219 {
220 bind_to_processor( 0);
221
222 #ifdef BOOST_CONTEXT_CYCLE
223 {
224 cycle_t ov( overhead_cycles() );
225 std::cout << "overhead for rdtsc == " << ov << " cycles" << std::endl;
226
227 unsigned int res = test_fcontext_cycle( ov);
228 std::cout << "fcontext: average of " << res << " cycles per switch" << std::endl;
229 # ifdef BOOST_USE_UCONTEXT
230 res = test_ucontext_cycle( ov);
231 std::cout << "ucontext: average of " << res << " cycles per switch" << std::endl;
232 # endif
233 res = test_function_cycle( ov);
234 std::cout << "boost::function: average of " << res << " cycles per switch" << std::endl;
235 }
236 #endif
237
238 #if _POSIX_C_SOURCE >= 199309L
239 {
240 zeit_t ov( overhead_zeit() );
241 std::cout << "\noverhead for clock_gettime() == " << ov << " ns" << std::endl;
242
243 unsigned int res = test_fcontext_zeit( ov);
244 std::cout << "fcontext: average of " << res << " ns per switch" << std::endl;
245 # ifdef BOOST_USE_UCONTEXT
246 res = test_ucontext_zeit( ov);
247 std::cout << "ucontext: average of " << res << " ns per switch" << std::endl;
248 # endif
249 res = test_function_zeit( ov);
250 std::cout << "boost::function: average of " << res << " ns per switch" << std::endl;
251 }
252 #endif
253
254 return EXIT_SUCCESS;
255 }
256 catch ( std::exception const& e)
257 { std::cerr << "exception: " << e.what() << std::endl; }
258 catch (...)
259 { std::cerr << "unhandled exception" << std::endl; }
260 return EXIT_FAILURE;
261 }
262
263 #undef CALL_FCONTEXT
264 #undef CALL_UCONTEXT
265