perf.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  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)
  5. *
  6. * See http://www.boost.org/libs/poly_collection for library home page.
  7. */
  8. /* Boost.PolyCollection performance tests */
  9. #include <algorithm>
  10. #include <array>
  11. #include <chrono>
  12. #include <cmath>
  13. #include <numeric>
  14. std::chrono::high_resolution_clock::time_point measure_start,measure_pause;
  15. template<typename F>
  16. double measure(F f)
  17. {
  18. using namespace std::chrono;
  19. static const int num_trials=10;
  20. static const milliseconds min_time_per_trial(200);
  21. std::array<double,num_trials> trials;
  22. volatile decltype(f()) res; /* to avoid optimizing f() away */
  23. for(int i=0;i<num_trials;++i){
  24. int runs=0;
  25. high_resolution_clock::time_point t2;
  26. measure_start=high_resolution_clock::now();
  27. do{
  28. res=f();
  29. ++runs;
  30. t2=high_resolution_clock::now();
  31. }while(t2-measure_start<min_time_per_trial);
  32. trials[i]=duration_cast<duration<double>>(t2-measure_start).count()/runs;
  33. }
  34. (void)res; /* var not used warn */
  35. std::sort(trials.begin(),trials.end());
  36. return std::accumulate(
  37. trials.begin()+2,trials.end()-2,0.0)/(trials.size()-4);
  38. }
  39. template<typename F>
  40. double measure(unsigned int n,F f)
  41. {
  42. double t=measure(f);
  43. return (t/n)*10E9;
  44. }
  45. void pause_timing()
  46. {
  47. measure_pause=std::chrono::high_resolution_clock::now();
  48. }
  49. void resume_timing()
  50. {
  51. measure_start+=std::chrono::high_resolution_clock::now()-measure_pause;
  52. }
  53. #include <algorithm>
  54. #include <array>
  55. #include <boost/poly_collection/algorithm.hpp>
  56. #include <boost/poly_collection/any_collection.hpp>
  57. #include <boost/poly_collection/base_collection.hpp>
  58. #include <boost/poly_collection/function_collection.hpp>
  59. #include <boost/ptr_container/ptr_container.hpp>
  60. #include <boost/type_erasure/any.hpp>
  61. #include <boost/type_erasure/callable.hpp>
  62. #include <boost/type_erasure/builtin.hpp>
  63. #include <boost/type_erasure/operators.hpp>
  64. #include <boost/type_erasure/typeid_of.hpp>
  65. #include <functional>
  66. #include <random>
  67. #include <string>
  68. #include <utility>
  69. #include <vector>
  70. //[perf_base_types
  71. struct base
  72. {
  73. virtual ~base()=default;
  74. virtual int operator()(int)const=0;
  75. };
  76. struct derived1 final:base
  77. {
  78. derived1(int n):n{n}{}
  79. virtual int operator()(int)const{return n;}
  80. int n;
  81. };
  82. struct derived2 final:base
  83. {
  84. derived2(int n):n{n}{}
  85. virtual int operator()(int x)const{return x*n;}
  86. int unused,n;
  87. };
  88. struct derived3 final:base
  89. {
  90. derived3(int n):n{n}{}
  91. virtual int operator()(int x)const{return x*x*n;}
  92. int unused,n;
  93. };
  94. //]
  95. //[perf_function_types
  96. struct concrete1
  97. {
  98. concrete1(int n):n{n}{}
  99. int operator()(int)const{return n;}
  100. int n;
  101. };
  102. struct concrete2
  103. {
  104. concrete2(int n):n{n}{}
  105. int operator()(int x)const{return x*n;}
  106. int unused,n;
  107. };
  108. struct concrete3
  109. {
  110. concrete3(int n):n{n}{}
  111. int operator()(int x)const{return x*x*n;}
  112. int unused,n;
  113. };
  114. //]
  115. template<typename Base>
  116. struct ptr_vector:boost::ptr_vector<Base>
  117. {
  118. public:
  119. template<typename T>
  120. void insert(const T& x)
  121. {
  122. this->push_back(new T{x});
  123. }
  124. template<typename F>
  125. void for_each(F f)
  126. {
  127. std::for_each(this->begin(),this->end(),f);
  128. }
  129. void prepare_for_for_each(){}
  130. };
  131. template<typename Base>
  132. struct sorted_ptr_vector:ptr_vector<Base>
  133. {
  134. void prepare_for_for_each()
  135. {
  136. std::sort(
  137. this->c_array(),this->c_array()+this->size(),
  138. [](Base* x,Base* y){return typeid(*x).before(typeid(*y));});
  139. }
  140. };
  141. template<typename Base>
  142. struct shuffled_ptr_vector:ptr_vector<Base>
  143. {
  144. void prepare_for_for_each()
  145. {
  146. std::shuffle(
  147. this->c_array(),this->c_array()+this->size(),std::mt19937(1));
  148. }
  149. };
  150. template<typename Base>
  151. struct base_collection:boost::base_collection<Base>
  152. {
  153. template<typename F>
  154. void for_each(F f)
  155. {
  156. std::for_each(this->begin(),this->end(),f);
  157. }
  158. void prepare_for_for_each(){}
  159. };
  160. template<typename Base,typename... T>
  161. struct poly_for_each_base_collection:base_collection<Base>
  162. {
  163. template<typename F>
  164. void for_each(F f)
  165. {
  166. boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
  167. }
  168. };
  169. template<typename Signature>
  170. struct func_vector:std::vector<std::function<Signature>>
  171. {
  172. template<typename T> void insert(const T& x)
  173. {
  174. this->push_back(x);
  175. }
  176. template<typename F>
  177. void for_each(F f)
  178. {
  179. std::for_each(this->begin(),this->end(),f);
  180. }
  181. void prepare_for_for_each(){}
  182. };
  183. template<typename Signature>
  184. struct sorted_func_vector:func_vector<Signature>
  185. {
  186. void prepare_for_for_each()
  187. {
  188. using value_type=typename sorted_func_vector::value_type;
  189. std::sort(
  190. this->begin(),this->end(),[](const value_type& x,const value_type& y){
  191. return x.target_type().before(y.target_type());
  192. });
  193. }
  194. };
  195. template<typename Signature>
  196. struct shuffled_func_vector:func_vector<Signature>
  197. {
  198. void prepare_for_for_each()
  199. {
  200. std::shuffle(this->begin(),this->end(),std::mt19937(1));
  201. }
  202. };
  203. template<typename Signature>
  204. struct func_collection:boost::function_collection<Signature>
  205. {
  206. template<typename F>
  207. void for_each(F f)
  208. {
  209. std::for_each(this->begin(),this->end(),f);
  210. }
  211. void prepare_for_for_each(){}
  212. };
  213. template<typename Signature,typename... T>
  214. struct poly_for_each_func_collection:func_collection<Signature>
  215. {
  216. template<typename F>
  217. void for_each(F f)
  218. {
  219. boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
  220. }
  221. };
  222. template<typename Concept>
  223. struct any_vector:std::vector<boost::type_erasure::any<Concept>>
  224. {
  225. template<typename T> void insert(const T& x)
  226. {
  227. this->push_back(x);
  228. }
  229. template<typename F>
  230. void for_each(F f)
  231. {
  232. std::for_each(this->begin(),this->end(),f);
  233. }
  234. void prepare_for_for_each(){}
  235. };
  236. template<typename Concept>
  237. struct sorted_any_vector:any_vector<Concept>
  238. {
  239. void prepare_for_for_each()
  240. {
  241. using value_type=typename sorted_any_vector::value_type;
  242. std::sort(
  243. this->begin(),this->end(),[](const value_type& x,const value_type& y){
  244. return typeid_of(x).before(typeid_of(y));
  245. });
  246. }
  247. };
  248. template<typename Concept>
  249. struct shuffled_any_vector:any_vector<Concept>
  250. {
  251. void prepare_for_for_each()
  252. {
  253. std::shuffle(this->begin(),this->end(),std::mt19937(1));
  254. }
  255. };
  256. template<typename Concept>
  257. struct any_collection:boost::any_collection<Concept>
  258. {
  259. template<typename F>
  260. void for_each(F f)
  261. {
  262. std::for_each(this->begin(),this->end(),f);
  263. }
  264. void prepare_for_for_each(){}
  265. };
  266. template<typename Concept,typename... T>
  267. struct poly_for_each_any_collection:any_collection<Concept>
  268. {
  269. template<typename F>
  270. void for_each(F f)
  271. {
  272. boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
  273. }
  274. };
  275. #include <iostream>
  276. template<typename... Printables>
  277. void print(Printables... ps)
  278. {
  279. const char* delim="";
  280. using seq=int[1+sizeof...(ps)];
  281. (void)seq{0,(std::cout<<delim<<ps,delim=";",0)...};
  282. std::cout<<"\n";
  283. }
  284. template<typename T>
  285. struct label
  286. {
  287. label(const char* str):str{str}{}
  288. operator const char*()const{return str;}
  289. const char* str;
  290. };
  291. template<typename... T>
  292. struct element_sequence{};
  293. template<
  294. typename... Element,
  295. typename Container
  296. >
  297. void container_fill(unsigned int n,element_sequence<Element...>,Container& c)
  298. {
  299. auto m=n/sizeof...(Element);
  300. for(unsigned int i=0;i!=m;++i){
  301. using seq=int[sizeof...(Element)];
  302. (void)seq{(c.insert(Element(i)),0)...};
  303. }
  304. }
  305. struct insert_perf_functor
  306. {
  307. template<
  308. typename... Element,
  309. typename Container
  310. >
  311. std::size_t operator()(
  312. unsigned int n,element_sequence<Element...> elements,label<Container>)const
  313. {
  314. pause_timing();
  315. std::size_t res=0;
  316. {
  317. Container c;
  318. resume_timing();
  319. container_fill(n,elements,c);
  320. pause_timing();
  321. res=c.size();
  322. }
  323. resume_timing();
  324. return res;
  325. }
  326. };
  327. template<
  328. typename... Element,
  329. typename Container
  330. >
  331. double insert_perf(
  332. unsigned int n,element_sequence<Element...> elements,label<Container> label)
  333. {
  334. return measure(n,std::bind(insert_perf_functor{},n,elements,label));
  335. }
  336. template<
  337. typename... Element,
  338. typename... Container
  339. >
  340. void insert_perf(
  341. unsigned int n0,unsigned int n1,unsigned int dsav,
  342. element_sequence<Element...> elements,label<Container>... labels)
  343. {
  344. std::cout<<"insert:\n";
  345. print("n",labels...);
  346. for(unsigned int s=0,n=n0;
  347. (n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
  348. s+=dsav){
  349. unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
  350. nn=m*sizeof...(Element);
  351. print(nn,insert_perf(nn,elements,labels)...);
  352. }
  353. }
  354. struct for_each_perf_functor
  355. {
  356. template<typename F,typename Container>
  357. auto operator()(F f,Container& c)const->decltype(f.res)
  358. {
  359. c.for_each(std::ref(f));
  360. return f.res;
  361. }
  362. };
  363. template<
  364. typename... Element,
  365. typename F,
  366. typename Container
  367. >
  368. double for_each_perf(
  369. unsigned int n,
  370. element_sequence<Element...> elements,F f,label<Container>)
  371. {
  372. Container c;
  373. container_fill(n,elements,c);
  374. c.prepare_for_for_each();
  375. return measure(n,std::bind(for_each_perf_functor{},f,std::ref(c)));
  376. }
  377. template<
  378. typename... Element,
  379. typename F,
  380. typename... Container
  381. >
  382. void for_each_perf(
  383. unsigned int n0,unsigned int n1,unsigned int dsav,
  384. element_sequence<Element...> elements,F f,label<Container>... labels)
  385. {
  386. std::cout<<"for_each:\n";
  387. print("n",labels...);
  388. for(unsigned int s=0,n=n0;
  389. (n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
  390. s+=dsav){
  391. unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
  392. nn=m*sizeof...(Element);
  393. print(nn,for_each_perf(nn,elements,f,labels)...);
  394. }
  395. }
  396. //[perf_for_each_callable
  397. struct for_each_callable
  398. {
  399. for_each_callable():res{0}{}
  400. template<typename T>
  401. void operator()(T& x){
  402. res+=x(2);
  403. }
  404. int res;
  405. };
  406. //]
  407. //[perf_for_each_incrementable
  408. struct for_each_incrementable
  409. {
  410. for_each_incrementable():res{0}{}
  411. template<typename T>
  412. void operator()(T& x){
  413. ++x;
  414. ++res;
  415. }
  416. int res;
  417. };
  418. //]
  419. int main(int argc, char *argv[])
  420. {
  421. using test=std::pair<std::string,bool&>;
  422. bool all=false,
  423. insert_base=false,
  424. for_each_base=false,
  425. insert_function=false,
  426. for_each_function=false,
  427. insert_any=false,
  428. for_each_any=false;
  429. std::array<test,7> tests={{
  430. {"all",all},
  431. {"insert_base",insert_base},
  432. {"for_each_base",for_each_base},
  433. {"insert_function",insert_function},
  434. {"for_each_function",for_each_function},
  435. {"insert_any",insert_any},
  436. {"for_each_any",for_each_any}
  437. }};
  438. if(argc<2){
  439. std::cout<<"specify one or more tests to execute:\n";
  440. for(const auto& p:tests)std::cout<<" "<<p.first<<"\n";
  441. return 1;
  442. }
  443. for(int arg=1;arg<argc;++arg){
  444. auto it=std::find_if(tests.begin(),tests.end(),[&](test& t){
  445. return t.first==argv[arg];
  446. });
  447. if(it==tests.end()){
  448. std::cout<<"invalid test name\n";
  449. return 1;
  450. }
  451. it->second=true;
  452. }
  453. unsigned int n0=100,n1=10000000,dsav=50; /* sav for savart */
  454. {
  455. auto seq= element_sequence<
  456. derived1,derived1,derived2,derived2,derived3>{};
  457. auto f= for_each_callable{};
  458. auto pv= label<ptr_vector<base>>
  459. {"ptr_vector"};
  460. auto spv= label<sorted_ptr_vector<base>>
  461. {"sorted ptr_vector"};
  462. auto shpv= label<shuffled_ptr_vector<base>>
  463. {"shuffled ptr_vector"};
  464. auto bc= label<base_collection<base>>
  465. {"base_collection"};
  466. auto fbc= label<poly_for_each_base_collection<base>>
  467. {"base_collection (poly::for_each)"};
  468. auto rfbc= label<
  469. poly_for_each_base_collection<base,derived1,derived2,derived2>
  470. >
  471. {"base_collection (restituted poly::for_each)"};
  472. if(all||insert_base)insert_perf(n0,n1,dsav,seq,pv,bc);
  473. if(all||for_each_base)for_each_perf(
  474. n0,n1,dsav,seq,f,pv,spv,shpv,bc,fbc,rfbc);
  475. }
  476. {
  477. using signature=int(int);
  478. auto seq= element_sequence<
  479. concrete1,concrete1,concrete2,concrete2,concrete3>{};
  480. auto f = for_each_callable{};
  481. auto fv= label<func_vector<signature>>
  482. {"func_vector"};
  483. auto sfv= label<sorted_func_vector<signature>>
  484. {"sorted func_vector"};
  485. auto shfv= label<shuffled_func_vector<signature>>
  486. {"shuffled func_vector"};
  487. auto fc= label<func_collection<signature>>
  488. {"function_collection"};
  489. auto ffc= label<poly_for_each_func_collection<signature>>
  490. {"function_collection (poly::for_each)"};
  491. auto rffc= label<poly_for_each_func_collection<
  492. signature,concrete1,concrete2,concrete3>>
  493. {"function_collection (restituted poly::for_each)"};
  494. if(all||insert_function)insert_perf(n0,n1,dsav,seq,fv,fc);
  495. if(all||for_each_function)for_each_perf(
  496. n0,n1,dsav,seq,f,fv,sfv,shfv,fc,ffc,rffc);
  497. }
  498. {
  499. //[perf_any_types
  500. using concept_=boost::mpl::vector<
  501. boost::type_erasure::copy_constructible<>,
  502. boost::type_erasure::relaxed,
  503. boost::type_erasure::typeid_<>,
  504. boost::type_erasure::incrementable<>
  505. >;
  506. //]
  507. auto seq= element_sequence<int,int,double,double,char>{};
  508. auto f= for_each_incrementable{};
  509. auto av= label<any_vector<concept_>>
  510. {"any_vector"};
  511. auto sav= label<sorted_any_vector<concept_>>
  512. {"sorted any_vector"};
  513. auto shav= label<shuffled_any_vector<concept_>>
  514. {"shuffled any_vector"};
  515. auto ac= label<any_collection<concept_>>
  516. {"any_collection"};
  517. auto fac= label<poly_for_each_any_collection<concept_>>
  518. {"any_collection (poly::for_each)"};
  519. auto rfac= label<poly_for_each_any_collection<concept_,int,double,char>>
  520. {"any_collection (restituted poly::for_each)"};
  521. if(all||insert_any)insert_perf(n0,n1,dsav,seq,av,ac);
  522. if(all||for_each_any)for_each_perf(
  523. n0,n1,dsav,seq,f,av,sav,shav,ac,fac,rfac);
  524. }
  525. }