perf.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* Boost.Flyweight example of performance comparison.
  2. *
  3. * Copyright 2006-2008 Joaquin M Lopez Munoz.
  4. * Distributed under the Boost Software License, Version 1.0.
  5. * (See accompanying file LICENSE_1_0.txt or copy at
  6. * http://www.boost.org/LICENSE_1_0.txt)
  7. *
  8. * See http://www.boost.org/libs/flyweight for library home page.
  9. */
  10. #include <boost/flyweight/flyweight.hpp>
  11. #include <boost/flyweight/hashed_factory.hpp>
  12. #include <boost/flyweight/set_factory.hpp>
  13. #include <boost/flyweight/static_holder.hpp>
  14. #include <boost/flyweight/simple_locking.hpp>
  15. #include <boost/flyweight/refcounted.hpp>
  16. #include <boost/flyweight/no_tracking.hpp>
  17. #include <boost/mpl/bool.hpp>
  18. #include <boost/tokenizer.hpp>
  19. #include <algorithm>
  20. #include <cstddef>
  21. #include <cstdlib>
  22. #include <ctime>
  23. #include <fstream>
  24. #include <iostream>
  25. #include <numeric>
  26. #include <sstream>
  27. #include <string>
  28. #include <vector>
  29. #if defined(BOOST_NO_STDC_NAMESPACE)
  30. namespace std{
  31. using ::clock;
  32. using ::clock_t;
  33. using ::exit;
  34. }
  35. #endif
  36. using namespace boost::flyweights;
  37. /* Instrumented allocator family keeping track of the memory in
  38. * current use.
  39. */
  40. std::size_t count_allocator_mem=0;
  41. template<typename T>
  42. class count_allocator
  43. {
  44. public:
  45. typedef std::size_t size_type;
  46. typedef std::ptrdiff_t difference_type;
  47. typedef T* pointer;
  48. typedef const T* const_pointer;
  49. typedef T& reference;
  50. typedef const T& const_reference;
  51. typedef T value_type;
  52. template<class U>struct rebind{typedef count_allocator<U> other;};
  53. count_allocator(){}
  54. count_allocator(const count_allocator<T>&){}
  55. template<class U>count_allocator(const count_allocator<U>&,int=0){}
  56. pointer address(reference x)const{return &x;}
  57. const_pointer address(const_reference x)const{return &x;}
  58. pointer allocate(size_type n,const void* =0)
  59. {
  60. pointer p=(T*)(new char[n*sizeof(T)]);
  61. count_allocator_mem+=n*sizeof(T);
  62. return p;
  63. }
  64. void deallocate(void* p,size_type n)
  65. {
  66. count_allocator_mem-=n*sizeof(T);
  67. delete [](char *)p;
  68. }
  69. size_type max_size() const{return (size_type )(-1);}
  70. void construct(pointer p,const T& val){new(p)T(val);}
  71. void destroy(pointer p){p->~T();}
  72. friend bool operator==(const count_allocator&,const count_allocator&)
  73. {
  74. return true;
  75. }
  76. friend bool operator!=(const count_allocator&,const count_allocator&)
  77. {
  78. return false;
  79. }
  80. };
  81. template<>
  82. class count_allocator<void>
  83. {
  84. public:
  85. typedef void* pointer;
  86. typedef const void* const_pointer;
  87. typedef void value_type;
  88. template<class U>struct rebind{typedef count_allocator<U> other;};
  89. };
  90. /* Define some count_allocator-based types and Boost.Flyweight components */
  91. typedef std::basic_string<
  92. char,std::char_traits<char>,count_allocator<char>
  93. > count_string;
  94. typedef hashed_factory<
  95. boost::hash<boost::mpl::_2>,
  96. std::equal_to<boost::mpl::_2>,
  97. count_allocator<boost::mpl::_1>
  98. > count_hashed_factory;
  99. typedef set_factory<
  100. std::less<boost::mpl::_2>,
  101. count_allocator<boost::mpl::_1>
  102. > count_set_factory;
  103. /* Some additional utilities used by the test routine */
  104. class timer
  105. {
  106. public:
  107. timer(){restart();}
  108. void restart(){t=std::clock();}
  109. void time(const char* str)
  110. {
  111. std::cout<<str<<": "<<(double)(std::clock()-t)/CLOCKS_PER_SEC<<" s\n";
  112. }
  113. private:
  114. std::clock_t t;
  115. };
  116. template<typename T>
  117. struct is_flyweight:
  118. boost::mpl::false_{};
  119. template<
  120. typename T,
  121. typename Arg1,typename Arg2,typename Arg3,typename Arg4,typename Arg5
  122. >
  123. struct is_flyweight<flyweight<T,Arg1,Arg2,Arg3,Arg4,Arg5> >:
  124. boost::mpl::true_{};
  125. struct length_adder
  126. {
  127. std::size_t operator()(std::size_t n,const count_string& x)const
  128. {
  129. return n+x.size();
  130. }
  131. };
  132. /* Measure time and memory performance for a String, which is assumed
  133. * to be either a plain string type or a string flyweight.
  134. */
  135. template<typename String>
  136. struct test
  137. {
  138. static std::size_t run(const std::string& file)
  139. {
  140. typedef std::vector<String,count_allocator<String> > count_vector;
  141. /* Define a tokenizer on std::istreambuf. */
  142. typedef std::istreambuf_iterator<char> char_iterator;
  143. typedef boost::tokenizer<
  144. boost::char_separator<char>,
  145. char_iterator
  146. > tokenizer;
  147. std::ifstream ifs(file.c_str());
  148. if(!ifs){
  149. std::cout<<"can't open "<<file<<std::endl;
  150. std::exit(EXIT_FAILURE);
  151. }
  152. /* Initialization; tokenize using space and common punctuaction as
  153. * separators, and keeping the separators.
  154. */
  155. timer t;
  156. tokenizer tok=tokenizer(
  157. char_iterator(ifs),char_iterator(),
  158. boost::char_separator<char>(
  159. "",
  160. "\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"));
  161. count_vector txt;
  162. for(tokenizer::iterator it=tok.begin();it!=tok.end();++it){
  163. txt.push_back(String(it->c_str()));
  164. }
  165. t.time("initialization time");
  166. /* Assignment */
  167. t.restart();
  168. count_vector txt2;
  169. for(int i=0;i<10;++i){
  170. txt2.insert(txt2.end(),txt.begin(),txt.end());
  171. }
  172. t.time("assignment time");
  173. /* Equality comparison */
  174. t.restart();
  175. std::size_t c=0;
  176. for(int i=0;i<100;++i){
  177. c+=std::count(txt.begin(),txt.end(),txt[c%txt.size()]);
  178. }
  179. t.time("equality comparison time");
  180. /* Value access */
  181. t.restart();
  182. std::size_t s=0;
  183. for(int i=0;i<20;++i){
  184. s+=std::accumulate(txt2.begin(),txt2.end(),s,length_adder());
  185. }
  186. t.time("value access time");
  187. std::cout<<"bytes used: "<<count_allocator_mem;
  188. if(is_flyweight<String>::value){
  189. std::size_t flyweight_mem=(txt.capacity()+txt2.capacity())*sizeof(String);
  190. std::cout<<"= flyweights("<<flyweight_mem
  191. <<")+values("<<count_allocator_mem-flyweight_mem<<")";
  192. }
  193. std::cout<<"\n";
  194. return c+s;
  195. }
  196. };
  197. /* table of test cases for the user to select from */
  198. struct test_case
  199. {
  200. const char* name;
  201. std::size_t (*test)(const std::string&);
  202. };
  203. test_case test_table[]=
  204. {
  205. {
  206. "simple string",
  207. test<count_string>::run
  208. },
  209. {
  210. "flyweight, hashed factory",
  211. test<flyweight<count_string,count_hashed_factory> >::run
  212. },
  213. {
  214. "flyweight, hashed factory, no tracking",
  215. test<flyweight<count_string,count_hashed_factory,no_tracking> >::run
  216. },
  217. {
  218. "flyweight, set-based factory",
  219. test<flyweight<count_string,count_set_factory> >::run
  220. },
  221. {
  222. "flyweight, set-based factory, no tracking",
  223. test<flyweight<count_string,count_set_factory,no_tracking> >::run
  224. }
  225. };
  226. const int num_test_cases=sizeof(test_table)/sizeof(test_case);
  227. int main()
  228. {
  229. try{
  230. for(int i=0;i<num_test_cases;++i){
  231. std::cout<<i+1<<". "<<test_table[i].name<<"\n";
  232. }
  233. int option=-1;
  234. for(;;){
  235. std::cout<<"select option, enter to exit: ";
  236. std::string str;
  237. std::getline(std::cin,str);
  238. if(str.empty())std::exit(EXIT_SUCCESS);
  239. std::istringstream istr(str);
  240. istr>>option;
  241. if(option>=1&&option<=num_test_cases){
  242. --option; /* pass from 1-based menu to 0-based test_table */
  243. break;
  244. }
  245. }
  246. std::cout<<"enter file name: ";
  247. std::string file;
  248. std::getline(std::cin,file);
  249. std::size_t result=0;
  250. result=test_table[option].test(file);
  251. }
  252. catch(const std::exception& e){
  253. std::cout<<"error: "<<e.what()<<"\n";
  254. }
  255. return 0;
  256. }