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