123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /* Copyright 2016-2017 Joaquin M Lopez Munoz.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See http://www.boost.org/libs/poly_collection for library home page.
- */
-
- /* Boost.PolyCollection performance tests */
- #include <algorithm>
- #include <array>
- #include <chrono>
- #include <cmath>
- #include <numeric>
- std::chrono::high_resolution_clock::time_point measure_start,measure_pause;
-
- template<typename F>
- double measure(F f)
- {
- using namespace std::chrono;
-
- static const int num_trials=10;
- static const milliseconds min_time_per_trial(200);
- std::array<double,num_trials> trials;
- volatile decltype(f()) res; /* to avoid optimizing f() away */
-
- for(int i=0;i<num_trials;++i){
- int runs=0;
- high_resolution_clock::time_point t2;
-
- measure_start=high_resolution_clock::now();
- do{
- res=f();
- ++runs;
- t2=high_resolution_clock::now();
- }while(t2-measure_start<min_time_per_trial);
- trials[i]=duration_cast<duration<double>>(t2-measure_start).count()/runs;
- }
- (void)res; /* var not used warn */
-
- std::sort(trials.begin(),trials.end());
- return std::accumulate(
- trials.begin()+2,trials.end()-2,0.0)/(trials.size()-4);
- }
- template<typename F>
- double measure(unsigned int n,F f)
- {
- double t=measure(f);
- return (t/n)*10E9;
- }
- void pause_timing()
- {
- measure_pause=std::chrono::high_resolution_clock::now();
- }
-
- void resume_timing()
- {
- measure_start+=std::chrono::high_resolution_clock::now()-measure_pause;
- }
- #include <algorithm>
- #include <array>
- #include <boost/poly_collection/algorithm.hpp>
- #include <boost/poly_collection/any_collection.hpp>
- #include <boost/poly_collection/base_collection.hpp>
- #include <boost/poly_collection/function_collection.hpp>
- #include <boost/ptr_container/ptr_container.hpp>
- #include <boost/type_erasure/any.hpp>
- #include <boost/type_erasure/callable.hpp>
- #include <boost/type_erasure/builtin.hpp>
- #include <boost/type_erasure/operators.hpp>
- #include <boost/type_erasure/typeid_of.hpp>
- #include <functional>
- #include <random>
- #include <string>
- #include <utility>
- #include <vector>
- //[perf_base_types
- struct base
- {
- virtual ~base()=default;
- virtual int operator()(int)const=0;
- };
- struct derived1 final:base
- {
- derived1(int n):n{n}{}
- virtual int operator()(int)const{return n;}
-
- int n;
- };
- struct derived2 final:base
- {
- derived2(int n):n{n}{}
- virtual int operator()(int x)const{return x*n;}
-
- int unused,n;
- };
- struct derived3 final:base
- {
- derived3(int n):n{n}{}
- virtual int operator()(int x)const{return x*x*n;}
-
- int unused,n;
- };
- //]
- //[perf_function_types
- struct concrete1
- {
- concrete1(int n):n{n}{}
- int operator()(int)const{return n;}
-
- int n;
- };
- struct concrete2
- {
- concrete2(int n):n{n}{}
- int operator()(int x)const{return x*n;}
-
- int unused,n;
- };
- struct concrete3
- {
- concrete3(int n):n{n}{}
- int operator()(int x)const{return x*x*n;}
-
- int unused,n;
- };
- //]
- template<typename Base>
- struct ptr_vector:boost::ptr_vector<Base>
- {
- public:
- template<typename T>
- void insert(const T& x)
- {
- this->push_back(new T{x});
- }
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Base>
- struct sorted_ptr_vector:ptr_vector<Base>
- {
- void prepare_for_for_each()
- {
- std::sort(
- this->c_array(),this->c_array()+this->size(),
- [](Base* x,Base* y){return typeid(*x).before(typeid(*y));});
- }
- };
- template<typename Base>
- struct shuffled_ptr_vector:ptr_vector<Base>
- {
- void prepare_for_for_each()
- {
- std::shuffle(
- this->c_array(),this->c_array()+this->size(),std::mt19937(1));
- }
- };
- template<typename Base>
- struct base_collection:boost::base_collection<Base>
- {
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Base,typename... T>
- struct poly_for_each_base_collection:base_collection<Base>
- {
- template<typename F>
- void for_each(F f)
- {
- boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
- }
- };
- template<typename Signature>
- struct func_vector:std::vector<std::function<Signature>>
- {
- template<typename T> void insert(const T& x)
- {
- this->push_back(x);
- }
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Signature>
- struct sorted_func_vector:func_vector<Signature>
- {
- void prepare_for_for_each()
- {
- using value_type=typename sorted_func_vector::value_type;
- std::sort(
- this->begin(),this->end(),[](const value_type& x,const value_type& y){
- return x.target_type().before(y.target_type());
- });
- }
- };
- template<typename Signature>
- struct shuffled_func_vector:func_vector<Signature>
- {
- void prepare_for_for_each()
- {
- std::shuffle(this->begin(),this->end(),std::mt19937(1));
- }
- };
- template<typename Signature>
- struct func_collection:boost::function_collection<Signature>
- {
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Signature,typename... T>
- struct poly_for_each_func_collection:func_collection<Signature>
- {
- template<typename F>
- void for_each(F f)
- {
- boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
- }
- };
- template<typename Concept>
- struct any_vector:std::vector<boost::type_erasure::any<Concept>>
- {
- template<typename T> void insert(const T& x)
- {
- this->push_back(x);
- }
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Concept>
- struct sorted_any_vector:any_vector<Concept>
- {
- void prepare_for_for_each()
- {
- using value_type=typename sorted_any_vector::value_type;
- std::sort(
- this->begin(),this->end(),[](const value_type& x,const value_type& y){
- return typeid_of(x).before(typeid_of(y));
- });
- }
- };
- template<typename Concept>
- struct shuffled_any_vector:any_vector<Concept>
- {
- void prepare_for_for_each()
- {
- std::shuffle(this->begin(),this->end(),std::mt19937(1));
- }
- };
- template<typename Concept>
- struct any_collection:boost::any_collection<Concept>
- {
- template<typename F>
- void for_each(F f)
- {
- std::for_each(this->begin(),this->end(),f);
- }
- void prepare_for_for_each(){}
- };
- template<typename Concept,typename... T>
- struct poly_for_each_any_collection:any_collection<Concept>
- {
- template<typename F>
- void for_each(F f)
- {
- boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
- }
- };
- #include <iostream>
- template<typename... Printables>
- void print(Printables... ps)
- {
- const char* delim="";
- using seq=int[1+sizeof...(ps)];
- (void)seq{0,(std::cout<<delim<<ps,delim=";",0)...};
- std::cout<<"\n";
- }
- template<typename T>
- struct label
- {
- label(const char* str):str{str}{}
- operator const char*()const{return str;}
- const char* str;
- };
- template<typename... T>
- struct element_sequence{};
- template<
- typename... Element,
- typename Container
- >
- void container_fill(unsigned int n,element_sequence<Element...>,Container& c)
- {
- auto m=n/sizeof...(Element);
- for(unsigned int i=0;i!=m;++i){
- using seq=int[sizeof...(Element)];
- (void)seq{(c.insert(Element(i)),0)...};
- }
- }
- struct insert_perf_functor
- {
- template<
- typename... Element,
- typename Container
- >
- std::size_t operator()(
- unsigned int n,element_sequence<Element...> elements,label<Container>)const
- {
- pause_timing();
- std::size_t res=0;
- {
- Container c;
- resume_timing();
- container_fill(n,elements,c);
- pause_timing();
- res=c.size();
- }
- resume_timing();
- return res;
- }
- };
- template<
- typename... Element,
- typename Container
- >
- double insert_perf(
- unsigned int n,element_sequence<Element...> elements,label<Container> label)
- {
- return measure(n,std::bind(insert_perf_functor{},n,elements,label));
- }
- template<
- typename... Element,
- typename... Container
- >
- void insert_perf(
- unsigned int n0,unsigned int n1,unsigned int dsav,
- element_sequence<Element...> elements,label<Container>... labels)
- {
- std::cout<<"insert:\n";
- print("n",labels...);
-
- for(unsigned int s=0,n=n0;
- (n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
- s+=dsav){
- unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
- nn=m*sizeof...(Element);
- print(nn,insert_perf(nn,elements,labels)...);
- }
- }
- struct for_each_perf_functor
- {
- template<typename F,typename Container>
- auto operator()(F f,Container& c)const->decltype(f.res)
- {
- c.for_each(std::ref(f));
- return f.res;
- }
- };
- template<
- typename... Element,
- typename F,
- typename Container
- >
- double for_each_perf(
- unsigned int n,
- element_sequence<Element...> elements,F f,label<Container>)
- {
- Container c;
- container_fill(n,elements,c);
- c.prepare_for_for_each();
- return measure(n,std::bind(for_each_perf_functor{},f,std::ref(c)));
- }
- template<
- typename... Element,
- typename F,
- typename... Container
- >
- void for_each_perf(
- unsigned int n0,unsigned int n1,unsigned int dsav,
- element_sequence<Element...> elements,F f,label<Container>... labels)
- {
- std::cout<<"for_each:\n";
- print("n",labels...);
-
- for(unsigned int s=0,n=n0;
- (n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
- s+=dsav){
- unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
- nn=m*sizeof...(Element);
- print(nn,for_each_perf(nn,elements,f,labels)...);
- }
- }
- //[perf_for_each_callable
- struct for_each_callable
- {
- for_each_callable():res{0}{}
- template<typename T>
- void operator()(T& x){
- res+=x(2);
- }
- int res;
- };
- //]
- //[perf_for_each_incrementable
- struct for_each_incrementable
- {
- for_each_incrementable():res{0}{}
- template<typename T>
- void operator()(T& x){
- ++x;
- ++res;
- }
- int res;
- };
- //]
- int main(int argc, char *argv[])
- {
- using test=std::pair<std::string,bool&>;
- bool all=false,
- insert_base=false,
- for_each_base=false,
- insert_function=false,
- for_each_function=false,
- insert_any=false,
- for_each_any=false;
- std::array<test,7> tests={{
- {"all",all},
- {"insert_base",insert_base},
- {"for_each_base",for_each_base},
- {"insert_function",insert_function},
- {"for_each_function",for_each_function},
- {"insert_any",insert_any},
- {"for_each_any",for_each_any}
- }};
- if(argc<2){
- std::cout<<"specify one or more tests to execute:\n";
- for(const auto& p:tests)std::cout<<" "<<p.first<<"\n";
- return 1;
- }
- for(int arg=1;arg<argc;++arg){
- auto it=std::find_if(tests.begin(),tests.end(),[&](test& t){
- return t.first==argv[arg];
- });
- if(it==tests.end()){
- std::cout<<"invalid test name\n";
- return 1;
- }
- it->second=true;
- }
- unsigned int n0=100,n1=10000000,dsav=50; /* sav for savart */
- {
- auto seq= element_sequence<
- derived1,derived1,derived2,derived2,derived3>{};
- auto f= for_each_callable{};
- auto pv= label<ptr_vector<base>>
- {"ptr_vector"};
- auto spv= label<sorted_ptr_vector<base>>
- {"sorted ptr_vector"};
- auto shpv= label<shuffled_ptr_vector<base>>
- {"shuffled ptr_vector"};
- auto bc= label<base_collection<base>>
- {"base_collection"};
- auto fbc= label<poly_for_each_base_collection<base>>
- {"base_collection (poly::for_each)"};
- auto rfbc= label<
- poly_for_each_base_collection<base,derived1,derived2,derived2>
- >
- {"base_collection (restituted poly::for_each)"};
- if(all||insert_base)insert_perf(n0,n1,dsav,seq,pv,bc);
- if(all||for_each_base)for_each_perf(
- n0,n1,dsav,seq,f,pv,spv,shpv,bc,fbc,rfbc);
- }
- {
- using signature=int(int);
- auto seq= element_sequence<
- concrete1,concrete1,concrete2,concrete2,concrete3>{};
- auto f = for_each_callable{};
- auto fv= label<func_vector<signature>>
- {"func_vector"};
- auto sfv= label<sorted_func_vector<signature>>
- {"sorted func_vector"};
- auto shfv= label<shuffled_func_vector<signature>>
- {"shuffled func_vector"};
- auto fc= label<func_collection<signature>>
- {"function_collection"};
- auto ffc= label<poly_for_each_func_collection<signature>>
- {"function_collection (poly::for_each)"};
- auto rffc= label<poly_for_each_func_collection<
- signature,concrete1,concrete2,concrete3>>
- {"function_collection (restituted poly::for_each)"};
- if(all||insert_function)insert_perf(n0,n1,dsav,seq,fv,fc);
- if(all||for_each_function)for_each_perf(
- n0,n1,dsav,seq,f,fv,sfv,shfv,fc,ffc,rffc);
- }
- {
- //[perf_any_types
- using concept_=boost::mpl::vector<
- boost::type_erasure::copy_constructible<>,
- boost::type_erasure::relaxed,
- boost::type_erasure::typeid_<>,
- boost::type_erasure::incrementable<>
- >;
- //]
- auto seq= element_sequence<int,int,double,double,char>{};
- auto f= for_each_incrementable{};
- auto av= label<any_vector<concept_>>
- {"any_vector"};
- auto sav= label<sorted_any_vector<concept_>>
- {"sorted any_vector"};
- auto shav= label<shuffled_any_vector<concept_>>
- {"shuffled any_vector"};
- auto ac= label<any_collection<concept_>>
- {"any_collection"};
- auto fac= label<poly_for_each_any_collection<concept_>>
- {"any_collection (poly::for_each)"};
- auto rfac= label<poly_for_each_any_collection<concept_,int,double,char>>
- {"any_collection (restituted poly::for_each)"};
- if(all||insert_any)insert_perf(n0,n1,dsav,seq,av,ac);
- if(all||for_each_any)for_each_perf(
- n0,n1,dsav,seq,f,av,sav,shav,ac,fac,rfac);
- }
- }
|