1 /* Copyright 2016-2017 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/poly_collection for library home page.
9 /* Boost.PolyCollection performance tests */
17 std::chrono::high_resolution_clock::time_point measure_start
,measure_pause
;
22 using namespace std::chrono
;
24 static const int num_trials
=10;
25 static const milliseconds
min_time_per_trial(200);
26 std::array
<double,num_trials
> trials
;
27 volatile decltype(f()) res
; /* to avoid optimizing f() away */
29 for(int i
=0;i
<num_trials
;++i
){
31 high_resolution_clock::time_point t2
;
33 measure_start
=high_resolution_clock::now();
37 t2
=high_resolution_clock::now();
38 }while(t2
-measure_start
<min_time_per_trial
);
39 trials
[i
]=duration_cast
<duration
<double>>(t2
-measure_start
).count()/runs
;
41 (void)res
; /* var not used warn */
43 std::sort(trials
.begin(),trials
.end());
44 return std::accumulate(
45 trials
.begin()+2,trials
.end()-2,0.0)/(trials
.size()-4);
49 double measure(unsigned int n
,F f
)
57 measure_pause
=std::chrono::high_resolution_clock::now();
62 measure_start
+=std::chrono::high_resolution_clock::now()-measure_pause
;
67 #include <boost/poly_collection/algorithm.hpp>
68 #include <boost/poly_collection/any_collection.hpp>
69 #include <boost/poly_collection/base_collection.hpp>
70 #include <boost/poly_collection/function_collection.hpp>
71 #include <boost/ptr_container/ptr_container.hpp>
72 #include <boost/type_erasure/any.hpp>
73 #include <boost/type_erasure/callable.hpp>
74 #include <boost/type_erasure/builtin.hpp>
75 #include <boost/type_erasure/operators.hpp>
76 #include <boost/type_erasure/typeid_of.hpp>
86 virtual ~base()=default;
87 virtual int operator()(int)const=0;
90 struct derived1 final
:base
92 derived1(int n
):n
{n
}{}
93 virtual int operator()(int)const{return n
;}
98 struct derived2 final
:base
100 derived2(int n
):n
{n
}{}
101 virtual int operator()(int x
)const{return x
*n
;}
106 struct derived3 final
:base
108 derived3(int n
):n
{n
}{}
109 virtual int operator()(int x
)const{return x
*x
*n
;}
115 //[perf_function_types
118 concrete1(int n
):n
{n
}{}
119 int operator()(int)const{return n
;}
126 concrete2(int n
):n
{n
}{}
127 int operator()(int x
)const{return x
*n
;}
134 concrete3(int n
):n
{n
}{}
135 int operator()(int x
)const{return x
*x
*n
;}
141 template<typename Base
>
142 struct ptr_vector
:boost::ptr_vector
<Base
>
146 void insert(const T
& x
)
148 this->push_back(new T
{x
});
154 std::for_each(this->begin(),this->end(),f
);
157 void prepare_for_for_each(){}
160 template<typename Base
>
161 struct sorted_ptr_vector
:ptr_vector
<Base
>
163 void prepare_for_for_each()
166 this->c_array(),this->c_array()+this->size(),
167 [](Base
* x
,Base
* y
){return typeid(*x
).before(typeid(*y
));});
171 template<typename Base
>
172 struct shuffled_ptr_vector
:ptr_vector
<Base
>
174 void prepare_for_for_each()
177 this->c_array(),this->c_array()+this->size(),std::mt19937(1));
181 template<typename Base
>
182 struct base_collection
:boost::base_collection
<Base
>
187 std::for_each(this->begin(),this->end(),f
);
190 void prepare_for_for_each(){}
193 template<typename Base
,typename
... T
>
194 struct poly_for_each_base_collection
:base_collection
<Base
>
199 boost::poly_collection::for_each
<T
...>(this->begin(),this->end(),f
);
203 template<typename Signature
>
204 struct func_vector
:std::vector
<std::function
<Signature
>>
206 template<typename T
> void insert(const T
& x
)
214 std::for_each(this->begin(),this->end(),f
);
217 void prepare_for_for_each(){}
220 template<typename Signature
>
221 struct sorted_func_vector
:func_vector
<Signature
>
223 void prepare_for_for_each()
225 using value_type
=typename
sorted_func_vector::value_type
;
227 this->begin(),this->end(),[](const value_type
& x
,const value_type
& y
){
228 return x
.target_type().before(y
.target_type());
233 template<typename Signature
>
234 struct shuffled_func_vector
:func_vector
<Signature
>
236 void prepare_for_for_each()
238 std::shuffle(this->begin(),this->end(),std::mt19937(1));
242 template<typename Signature
>
243 struct func_collection
:boost::function_collection
<Signature
>
248 std::for_each(this->begin(),this->end(),f
);
251 void prepare_for_for_each(){}
254 template<typename Signature
,typename
... T
>
255 struct poly_for_each_func_collection
:func_collection
<Signature
>
260 boost::poly_collection::for_each
<T
...>(this->begin(),this->end(),f
);
264 template<typename Concept
>
265 struct any_vector
:std::vector
<boost::type_erasure::any
<Concept
>>
267 template<typename T
> void insert(const T
& x
)
275 std::for_each(this->begin(),this->end(),f
);
278 void prepare_for_for_each(){}
281 template<typename Concept
>
282 struct sorted_any_vector
:any_vector
<Concept
>
284 void prepare_for_for_each()
286 using value_type
=typename
sorted_any_vector::value_type
;
288 this->begin(),this->end(),[](const value_type
& x
,const value_type
& y
){
289 return typeid_of(x
).before(typeid_of(y
));
294 template<typename Concept
>
295 struct shuffled_any_vector
:any_vector
<Concept
>
297 void prepare_for_for_each()
299 std::shuffle(this->begin(),this->end(),std::mt19937(1));
303 template<typename Concept
>
304 struct any_collection
:boost::any_collection
<Concept
>
309 std::for_each(this->begin(),this->end(),f
);
312 void prepare_for_for_each(){}
315 template<typename Concept
,typename
... T
>
316 struct poly_for_each_any_collection
:any_collection
<Concept
>
321 boost::poly_collection::for_each
<T
...>(this->begin(),this->end(),f
);
327 template<typename
... Printables
>
328 void print(Printables
... ps
)
330 const char* delim
="";
331 using seq
=int[1+sizeof...(ps
)];
332 (void)seq
{0,(std::cout
<<delim
<<ps
,delim
=";",0)...};
339 label(const char* str
):str
{str
}{}
340 operator const char*()const{return str
;}
344 template<typename
... T
>
345 struct element_sequence
{};
351 void container_fill(unsigned int n
,element_sequence
<Element
...>,Container
& c
)
353 auto m
=n
/sizeof...(Element
);
354 for(unsigned int i
=0;i
!=m
;++i
){
355 using seq
=int[sizeof...(Element
)];
356 (void)seq
{(c
.insert(Element(i
)),0)...};
360 struct insert_perf_functor
366 std::size_t operator()(
367 unsigned int n
,element_sequence
<Element
...> elements
,label
<Container
>)const
374 container_fill(n
,elements
,c
);
388 unsigned int n
,element_sequence
<Element
...> elements
,label
<Container
> label
)
390 return measure(n
,std::bind(insert_perf_functor
{},n
,elements
,label
));
395 typename
... Container
398 unsigned int n0
,unsigned int n1
,unsigned int dsav
,
399 element_sequence
<Element
...> elements
,label
<Container
>... labels
)
401 std::cout
<<"insert:\n";
402 print("n",labels
...);
404 for(unsigned int s
=0,n
=n0
;
405 (n
=(unsigned int)std::round(n0
*std::pow(10.0,s
/1000.0)))<=n1
;
407 unsigned int m
=(unsigned int)std::round(n
/sizeof...(Element
)),
408 nn
=m
*sizeof...(Element
);
409 print(nn
,insert_perf(nn
,elements
,labels
)...);
413 struct for_each_perf_functor
415 template<typename F
,typename Container
>
416 auto operator()(F f
,Container
& c
)const->decltype(f
.res
)
418 c
.for_each(std::ref(f
));
428 double for_each_perf(
430 element_sequence
<Element
...> elements
,F f
,label
<Container
>)
433 container_fill(n
,elements
,c
);
434 c
.prepare_for_for_each();
435 return measure(n
,std::bind(for_each_perf_functor
{},f
,std::ref(c
)));
441 typename
... Container
444 unsigned int n0
,unsigned int n1
,unsigned int dsav
,
445 element_sequence
<Element
...> elements
,F f
,label
<Container
>... labels
)
447 std::cout
<<"for_each:\n";
448 print("n",labels
...);
450 for(unsigned int s
=0,n
=n0
;
451 (n
=(unsigned int)std::round(n0
*std::pow(10.0,s
/1000.0)))<=n1
;
453 unsigned int m
=(unsigned int)std::round(n
/sizeof...(Element
)),
454 nn
=m
*sizeof...(Element
);
455 print(nn
,for_each_perf(nn
,elements
,f
,labels
)...);
459 //[perf_for_each_callable
460 struct for_each_callable
462 for_each_callable():res
{0}{}
465 void operator()(T
& x
){
473 //[perf_for_each_incrementable
474 struct for_each_incrementable
476 for_each_incrementable():res
{0}{}
479 void operator()(T
& x
){
488 int main(int argc
, char *argv
[])
490 using test
=std::pair
<std::string
,bool&>;
495 insert_function
=false,
496 for_each_function
=false,
499 std::array
<test
,7> tests
={{
501 {"insert_base",insert_base
},
502 {"for_each_base",for_each_base
},
503 {"insert_function",insert_function
},
504 {"for_each_function",for_each_function
},
505 {"insert_any",insert_any
},
506 {"for_each_any",for_each_any
}
510 std::cout
<<"specify one or more tests to execute:\n";
511 for(const auto& p
:tests
)std::cout
<<" "<<p
.first
<<"\n";
515 for(int arg
=1;arg
<argc
;++arg
){
516 auto it
=std::find_if(tests
.begin(),tests
.end(),[&](test
& t
){
517 return t
.first
==argv
[arg
];
520 std::cout
<<"invalid test name\n";
526 unsigned int n0
=100,n1
=10000000,dsav
=50; /* sav for savart */
529 auto seq
= element_sequence
<
530 derived1
,derived1
,derived2
,derived2
,derived3
>{};
531 auto f
= for_each_callable
{};
532 auto pv
= label
<ptr_vector
<base
>>
534 auto spv
= label
<sorted_ptr_vector
<base
>>
535 {"sorted ptr_vector"};
536 auto shpv
= label
<shuffled_ptr_vector
<base
>>
537 {"shuffled ptr_vector"};
538 auto bc
= label
<base_collection
<base
>>
540 auto fbc
= label
<poly_for_each_base_collection
<base
>>
541 {"base_collection (poly::for_each)"};
543 poly_for_each_base_collection
<base
,derived1
,derived2
,derived2
>
545 {"base_collection (restituted poly::for_each)"};
547 if(all
||insert_base
)insert_perf(n0
,n1
,dsav
,seq
,pv
,bc
);
548 if(all
||for_each_base
)for_each_perf(
549 n0
,n1
,dsav
,seq
,f
,pv
,spv
,shpv
,bc
,fbc
,rfbc
);
552 using signature
=int(int);
554 auto seq
= element_sequence
<
555 concrete1
,concrete1
,concrete2
,concrete2
,concrete3
>{};
556 auto f
= for_each_callable
{};
557 auto fv
= label
<func_vector
<signature
>>
559 auto sfv
= label
<sorted_func_vector
<signature
>>
560 {"sorted func_vector"};
561 auto shfv
= label
<shuffled_func_vector
<signature
>>
562 {"shuffled func_vector"};
563 auto fc
= label
<func_collection
<signature
>>
564 {"function_collection"};
565 auto ffc
= label
<poly_for_each_func_collection
<signature
>>
566 {"function_collection (poly::for_each)"};
567 auto rffc
= label
<poly_for_each_func_collection
<
568 signature
,concrete1
,concrete2
,concrete3
>>
569 {"function_collection (restituted poly::for_each)"};
571 if(all
||insert_function
)insert_perf(n0
,n1
,dsav
,seq
,fv
,fc
);
572 if(all
||for_each_function
)for_each_perf(
573 n0
,n1
,dsav
,seq
,f
,fv
,sfv
,shfv
,fc
,ffc
,rffc
);
577 using concept_
=boost::mpl::vector
<
578 boost::type_erasure::copy_constructible
<>,
579 boost::type_erasure::relaxed
,
580 boost::type_erasure::typeid_
<>,
581 boost::type_erasure::incrementable
<>
585 auto seq
= element_sequence
<int,int,double,double,char>{};
586 auto f
= for_each_incrementable
{};
587 auto av
= label
<any_vector
<concept_
>>
589 auto sav
= label
<sorted_any_vector
<concept_
>>
590 {"sorted any_vector"};
591 auto shav
= label
<shuffled_any_vector
<concept_
>>
592 {"shuffled any_vector"};
593 auto ac
= label
<any_collection
<concept_
>>
595 auto fac
= label
<poly_for_each_any_collection
<concept_
>>
596 {"any_collection (poly::for_each)"};
597 auto rfac
= label
<poly_for_each_any_collection
<concept_
,int,double,char>>
598 {"any_collection (restituted poly::for_each)"};
600 if(all
||insert_any
)insert_perf(n0
,n1
,dsav
,seq
,av
,ac
);
601 if(all
||for_each_any
)for_each_perf(
602 n0
,n1
,dsav
,seq
,f
,av
,sav
,shav
,ac
,fac
,rfac
);