/* 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 #include #include #include #include std::chrono::high_resolution_clock::time_point measure_start,measure_pause; template double measure(F f) { using namespace std::chrono; static const int num_trials=10; static const milliseconds min_time_per_trial(200); std::array trials; volatile decltype(f()) res; /* to avoid optimizing f() away */ for(int i=0;i>(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 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //[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 struct ptr_vector:boost::ptr_vector { public: template void insert(const T& x) { this->push_back(new T{x}); } template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct sorted_ptr_vector:ptr_vector { 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 struct shuffled_ptr_vector:ptr_vector { void prepare_for_for_each() { std::shuffle( this->c_array(),this->c_array()+this->size(),std::mt19937(1)); } }; template struct base_collection:boost::base_collection { template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct poly_for_each_base_collection:base_collection { template void for_each(F f) { boost::poly_collection::for_each(this->begin(),this->end(),f); } }; template struct func_vector:std::vector> { template void insert(const T& x) { this->push_back(x); } template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct sorted_func_vector:func_vector { 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 struct shuffled_func_vector:func_vector { void prepare_for_for_each() { std::shuffle(this->begin(),this->end(),std::mt19937(1)); } }; template struct func_collection:boost::function_collection { template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct poly_for_each_func_collection:func_collection { template void for_each(F f) { boost::poly_collection::for_each(this->begin(),this->end(),f); } }; template struct any_vector:std::vector> { template void insert(const T& x) { this->push_back(x); } template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct sorted_any_vector:any_vector { 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 struct shuffled_any_vector:any_vector { void prepare_for_for_each() { std::shuffle(this->begin(),this->end(),std::mt19937(1)); } }; template struct any_collection:boost::any_collection { template void for_each(F f) { std::for_each(this->begin(),this->end(),f); } void prepare_for_for_each(){} }; template struct poly_for_each_any_collection:any_collection { template void for_each(F f) { boost::poly_collection::for_each(this->begin(),this->end(),f); } }; #include template void print(Printables... ps) { const char* delim=""; using seq=int[1+sizeof...(ps)]; (void)seq{0,(std::cout< struct label { label(const char* str):str{str}{} operator const char*()const{return str;} const char* str; }; template struct element_sequence{}; template< typename... Element, typename Container > void container_fill(unsigned int n,element_sequence,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 elements,label)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 elements,label 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 elements,label... 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 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 elements,F f,label) { 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 elements,F f,label... 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 void operator()(T& x){ res+=x(2); } int res; }; //] //[perf_for_each_incrementable struct for_each_incrementable { for_each_incrementable():res{0}{} template void operator()(T& x){ ++x; ++res; } int res; }; //] int main(int argc, char *argv[]) { using test=std::pair; 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 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<<" "<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"}; auto spv= label> {"sorted ptr_vector"}; auto shpv= label> {"shuffled ptr_vector"}; auto bc= label> {"base_collection"}; auto fbc= label> {"base_collection (poly::for_each)"}; auto rfbc= label< poly_for_each_base_collection > {"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"}; auto sfv= label> {"sorted func_vector"}; auto shfv= label> {"shuffled func_vector"}; auto fc= label> {"function_collection"}; auto ffc= label> {"function_collection (poly::for_each)"}; auto rffc= label> {"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{}; auto f= for_each_incrementable{}; auto av= label> {"any_vector"}; auto sav= label> {"sorted any_vector"}; auto shav= label> {"shuffled any_vector"}; auto ac= label> {"any_collection"}; auto fac= label> {"any_collection (poly::for_each)"}; auto rfac= label> {"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); } }