Advertisement
mtrenkmann

bitmapslow2.cpp

Feb 26th, 2012
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.79 KB | None | 0 0
  1. /**
  2. *
  3. * Daniel Lemire, February 2012, http://lemire.me/
  4. *
  5. * Suppose that you want to copy an array over
  6. * another, except for some exceptions.
  7. * What is faster?
  8. *
  9. *  g++ -Ofast bitmapslow bitmapslow.cpp
  10. *
  11. *
  12. * Published on blog.
  13. *
  14. * ------------------------------------------------------------------------------
  15. * This is an updated version of the original code (Feb 26 2012).
  16. * Martin Trenkmann, martin.trenkmann@googlemail.com
  17. *
  18. * $ uname -a
  19. * Linux 2.6.32-5-amd64 #1 SMP Mon Jan 9 20:49:59 UTC 2012 x86_64 GNU/Linux
  20. *
  21. * $ cat /proc/cpuinfo | grep name
  22. * model name : Intel(R) Core(TM)2 CPU 6300 @ 1.86GHz
  23. *
  24. * $ g++ --version
  25. * g++ (Debian 4.4.5-8) 4.4.5
  26. * ------------------------------------------------------------------------------
  27. */
  28.  
  29. #include <iostream>
  30. #include <vector>
  31. #include <cassert>
  32. #include <cstdlib>
  33. #include <cstring>
  34. #include <iomanip>
  35. #include <algorithm>
  36. #include <sys/stat.h>
  37. #include <sys/time.h>
  38. #include <sys/types.h>
  39.  
  40. using namespace std;
  41.  
  42. typedef unsigned int uint;
  43. typedef unsigned char byte;
  44.  
  45. // mtrenkmann
  46. size_t NUMBER_OF_UPDATES;
  47.  
  48. // mtrenkmann
  49. inline void
  50. init_num_updates()
  51. {
  52.   assert((NUMBER_OF_UPDATES = 0, true));
  53. }
  54.  
  55. // mtrenkmann
  56. inline void
  57. increment_num_updates()
  58. {
  59.   assert(++NUMBER_OF_UPDATES);
  60. }
  61.  
  62. // mtrenkmann
  63. inline size_t
  64. num_updates()
  65. {
  66.   return NUMBER_OF_UPDATES;
  67. }
  68.  
  69.  
  70. class ZTimer
  71. {
  72. public:
  73.     struct timeval t1, t2;
  74. public:
  75.     ZTimer() :  t1(), t2() { gettimeofday(&t1,0); t2 = t1; }
  76.     void reset() {gettimeofday(&t1,0); t2 = t1;}
  77.     int elapsed() { return ((t2.tv_sec - t1.tv_sec) * 1000) + ((t2.tv_usec - t1.tv_usec) / 1000); }
  78.     int split() { gettimeofday(&t2,0); return elapsed(); }
  79. };
  80.  
  81. // mtrenkmann
  82. // Copies num elements of uint from src to dst.
  83. void
  84. memcopy(const vector<uint>& src, vector<uint>& dst)
  85. {
  86.   memcpy(dst.data(), src.data(), src.size() * sizeof(uint));
  87. }
  88.  
  89. /**
  90. * This copies the data from begin to end. We write to "out".
  91. * mtrenkmann: justcopy -> loopcopy
  92. */
  93. void
  94. loopcopy(
  95.   const uint * const begin,
  96.   const uint * const end,
  97.   uint * out)
  98. {
  99.   for(const uint * i = begin; i!=end; ++i) {
  100.     *(out++) = *i;
  101.   }
  102.   /* we could use this instead of the previous loop, but it is no faster:
  103.    memcpy ( out, begin, (end-begin)*sizeof(uint) );
  104.    at least under gcc 4.6
  105.   */
  106. }
  107.  
  108. /**
  109. * This copies the data from begin to end, except at some locations
  110. * given by exceptionbitmap where it must use the values from
  111. * exceptionval. We write to "out".
  112. */
  113. void
  114. bitmapcopy(
  115.   const uint * const begin,
  116.   const uint * const end,
  117.   const uint * exceptionval,
  118.   const vector<uint> & exceptionbitmap,
  119.   uint * out)
  120. {
  121.   init_num_updates();
  122.   vector<uint>::const_iterator j = exceptionbitmap.begin();
  123.   for(const uint * i = begin; i<end; ++i) {
  124.     for(uint k = 0; k<32; ++k, ++i)
  125.     {
  126.       *(out++) = ((*j) & (1U<<k))? (increment_num_updates(), *(exceptionval++)) : *i;
  127.     }
  128.     --i; // mtrenkmann: off by one error
  129.     ++j;
  130.   }
  131. }
  132.  
  133. /**
  134. * This copies the data from begin to end, except at some locations
  135. * given by exceptionbitmap where it must use the values from
  136. * exceptionval. We write to "out".
  137. */
  138. void
  139. bitmapcopy8bits(
  140.   const uint * const begin,
  141.   const uint * const end,
  142.   const uint * exceptionval,
  143.   const vector<uint> & exceptionbitmap,
  144.   uint * out)
  145. {
  146.   init_num_updates();
  147.   const byte * j = reinterpret_cast<const byte *>(&exceptionbitmap[0]);
  148.   for(const uint * i = begin; i<end; ++i) {
  149.     for(uint k = 0; k<8; ++k, ++i)
  150.     {
  151.       *(out++) = ((*j) & (1U<<k))? (increment_num_updates(), *(exceptionval++)) : *i;
  152.     }
  153.     --i; // mtrenkmann: off by one error
  154.     ++j;
  155.   }
  156. }
  157.  
  158. /**
  159. * This copies the data from begin to end, except at some locations
  160. * given by exceptionpos where it must use the values from
  161. * exceptionval. We write to "out".
  162. */
  163. void
  164. patchedcopy(
  165.   const uint * const begin,
  166.   const uint * const end,
  167.   const uint * exceptionval,
  168.   const vector<uint> & exceptionpos,
  169.   uint * out)
  170. {
  171.   init_num_updates();
  172.   uint * tmpout = out;
  173.   for(const uint * i = begin; i!=end; ++i) {
  174.     *(tmpout++) = *i;
  175.   }
  176.   for(vector<uint>::const_iterator pos = exceptionpos.begin(); pos!= exceptionpos.end(); ++pos) {
  177.     *(out + *pos) = *(exceptionval++);
  178.     increment_num_updates();
  179.   }
  180. }
  181.  
  182. /**
  183. * This copies the data from begin to end, except at some locations
  184. * given by exceptionpos where it must use the values from
  185. * exceptionval. We write to "out".
  186. *
  187. * Proposed by Luc Golden
  188. */
  189. void
  190. patchedcopy2(
  191.   const uint * const begin,
  192.   const uint * const end,
  193.   const uint * exceptionval,
  194.   const vector<uint> & exceptionpos,
  195.   uint * out)
  196. {
  197.   init_num_updates();
  198.   vector<uint>::const_iterator pos = exceptionpos.begin();
  199.   const uint * i = begin;
  200.   for(; i!=end;++i) {
  201.     if(i-begin == *pos) {
  202.       increment_num_updates();
  203.       *(out++) = *(exceptionval++);
  204.       ++pos;
  205.       if(pos==exceptionpos.end()) {
  206.         // no more exceptions
  207.         for(;i!=end;++i) {
  208.         *(out++) = *i;
  209.         }
  210.         break;
  211.       }
  212.     } else
  213.       *(out++) = *i;
  214.   }
  215. }
  216.  
  217. // mtrenkmann
  218. // Copies values from src vector to dst vector with updates.
  219. // Preconditions:
  220. //  - !positions.empty()
  221. //  - positions.size() <= replacements.size()
  222. //  - is_sorted_in_ascending_order(positions)
  223. void
  224. updatingcopy(
  225.   const vector<uint>& src,
  226.         vector<uint>& dst,
  227.   const vector<uint>& positions,
  228.   const vector<uint>& replacements)
  229. {
  230.   init_num_updates();
  231.   vector<uint>::const_iterator pos = positions.begin();
  232.   vector<uint>::const_iterator rep = replacements.begin();
  233.   for (size_t i = 0; i != src.size(); ++i)
  234.   {
  235.     if (i == *pos)
  236.     {
  237.       increment_num_updates();
  238.       dst[i] = *rep;
  239.       ++pos;
  240.       ++rep;
  241.     }
  242.     else
  243.     {
  244.       dst[i] = src[i];
  245.     }
  246.   }
  247. }
  248.  
  249. // mtrenkmann
  250. // Copies values from src vector to dst vector with updates.
  251. // Position and replacement values are together for better locality.
  252. // Preconditions:
  253. //  - !updates.empty()
  254. //  - is_sorted_in_ascending_order(updates.first)
  255. void
  256. updatingcopy2(
  257.   const vector<uint>& src,
  258.         vector<uint>& dst,
  259.   const vector<pair<uint, uint> >& updates)
  260. {
  261.   init_num_updates();
  262.   vector<pair<uint, uint> >::const_iterator uit = updates.begin();
  263.   for (size_t i = 0; i != src.size(); ++i)
  264.   {
  265.     if (i == uit->first)
  266.     {
  267.       increment_num_updates();
  268.       dst[i] = uit->second;
  269.       ++uit;
  270.     }
  271.     else
  272.     {
  273.       dst[i] = src[i];
  274.     }
  275.   }
  276. }
  277.  
  278. // mtrenkmann
  279. // Copies values from src vector to dst vector with updates.
  280. // To avoid branching the update vector becomes an outer loop.
  281. // Preconditions:
  282. //  - is_sorted_in_ascending_order(updates.first)
  283. void
  284. updatingcopy3(
  285.   const vector<uint>& src,
  286.         vector<uint>& dst,
  287.   const vector<pair<uint, uint> >& updates)
  288. {
  289.   init_num_updates();
  290.   size_t i = 0;
  291.   for (vector<pair<uint, uint> >::const_iterator it = updates.begin(); it != updates.end(); ++it)
  292.   {
  293.     for (; i != it->first; ++i)
  294.     {
  295.       dst[i] = src[i];
  296.     }
  297.     increment_num_updates();
  298.     dst[i] = it->second;
  299.     ++i;
  300.   }
  301.   for (; i != src.size(); ++i)
  302.   {
  303.     dst[i] = src[i];
  304.   }
  305. }
  306.  
  307. // mtrenkmann
  308. // Generates a vector with pairs containing update information.
  309. // pair.first indicates the index to be updated.
  310. // pair.second stores the replacement value.
  311. const vector<pair<uint, uint> >
  312. generate_update_pairs(uint n, uint density)
  313. {
  314.   vector<pair<uint, uint> > updates;
  315.   for (uint i = 0; i < n; i += density)
  316.   {
  317.     updates.push_back(make_pair(i, rand()));
  318.   }
  319.   return updates;
  320. }
  321.  
  322. vector<uint>
  323. generateArray(uint N)
  324. {
  325.   vector<uint> ans(N);
  326.   for(uint k = 0; k<N; ++k)
  327.     ans[k] = rand();
  328.   return ans;
  329. }
  330.  
  331. pair<vector<uint>, vector<uint> >
  332. generateExceptLocations(uint N, uint density)
  333. {
  334.   vector<uint> positions;
  335.   vector<uint> bitmap(N/32);
  336.   for(uint k = 0; k<N; k+= density) {
  337.     positions.push_back(k);
  338.  
  339. #ifdef FIXME
  340.     bitmap[k/32] |= (1<<(k%32)); // mtrenkmann: correct
  341. #else
  342.     bitmap[k/32] &= (1<<(k%32)); // mtrenkmann: incorrect
  343. #endif
  344.   }
  345.   return pair<vector<uint>, vector<uint> >(positions,bitmap);
  346. }
  347.  
  348. // mtrenkmann
  349. template <typename ContainerT> void
  350. check_equal(const ContainerT& lhs, const ContainerT& rhs)
  351. {
  352.   assert(lhs.size() == rhs.size());
  353.   assert(std::equal(lhs.begin(), lhs.end(), rhs.begin()));
  354. }
  355.  
  356. // mtrenkmann
  357. template <typename T> void
  358. print(const T& value, size_t width = 16)
  359. {
  360.   cout << setw(width) << left << value;
  361. }
  362.  
  363. // mtrenkmann
  364. template <typename T1, typename T2> void
  365. print(const T1& v1, size_t w1, const T2& v2, size_t w2)
  366. {
  367.   cout << setw(w1) << right << v1 << ' ' << setw(w2) << left << v2;
  368. }
  369.  
  370.  
  371. int main()
  372. {
  373.   const uint N = 1000000*32;//1024*1024*100;
  374.   // uint density = 100; // unused
  375.   const vector<uint> data = generateArray(N);
  376.   vector<uint> out(N);
  377.   ZTimer z;
  378.  
  379.   print("density(%)", 12);
  380.   print("memcopy", 9);
  381.   print("loopcopy", 10);
  382.   print("bitmapcopy");
  383.   print("bitmapcopy8bits");
  384.   print("patchedcopy");
  385.   print("patchedcopy2");
  386.   print("updatingcopy");
  387.   print("updatingcopy2");
  388.   print("updatingcopy3");
  389.   cout << endl;
  390.  
  391.   const vector<uint> exceptionvals = generateArray(N);// more than we need
  392.   for(uint density = 1; density<50; density+=5) {
  393.     const pair<vector<uint>, vector<uint> > exceptionpos = generateExceptLocations(N, density);
  394.    
  395.     // mtrenkmann
  396.     const vector<pair<uint, uint> > updates = generate_update_pairs(N, density);
  397.  
  398.     print(100.0 / density, 12);
  399.    
  400.     z.reset();
  401.     memcopy(data, out);
  402.     print(z.split(), 9);
  403.     check_equal(data, out);
  404.    
  405.     z.reset();
  406.     loopcopy(&data[0], (&data[0]) + N, &out[0]);
  407.     print(z.split(), 10);
  408.     check_equal(data, out);
  409.    
  410.     z.reset();
  411.     bitmapcopy(&data[0], (&data[0]) + N, &exceptionvals[0],  exceptionpos.second, &out[0]);  
  412.     print(z.split(), 3, num_updates(), 12);
  413.     // check_equal(data, out);
  414.  
  415.     z.reset();
  416.     bitmapcopy8bits(&data[0], (&data[0]) + N,  &exceptionvals[0], exceptionpos.second, &out[0]);  
  417.     print(z.split(), 3, num_updates(), 12);
  418.     // check_equal(data, out);
  419.    
  420.     z.reset();
  421.     patchedcopy(&data[0], (&data[0]) + N,  &exceptionvals[0], exceptionpos.first, &out[0]);
  422.     print(z.split(), 3, num_updates(), 12);
  423.  
  424.     z.reset();
  425.     patchedcopy2(&data[0], (&data[0]) + N, &exceptionvals[0], exceptionpos.first,  &out[0]);
  426.     print(z.split(), 3, num_updates(), 12);
  427.    
  428.     z.reset();
  429.     updatingcopy(data, out, exceptionpos.first, exceptionvals);
  430.     print(z.split(), 3, num_updates(), 12);
  431.    
  432.     z.reset();
  433.     updatingcopy2(data, out, updates);
  434.     print(z.split(), 3, num_updates(), 12);
  435.    
  436.     z.reset();
  437.     updatingcopy3(data, out, updates);
  438.     print(z.split(), 3, num_updates(), 12);
  439.  
  440.     cout << endl;
  441.   }
  442.   return 0;
  443. }
  444.  
  445. /*
  446. --------------------------------------------------------------------------------
  447. TEST RUN 1
  448. --------------------------------------------------------------------------------
  449. $ g++ -Wall -O3 -o bitmapslow2 bitmapslow2.cpp
  450.  
  451. density(%)  memcopy  loopcopy  bitmapcopy      bitmapcopy8bits patchedcopy     patchedcopy2    updatingcopy    updatingcopy2   updatingcopy3  
  452. 100         52       82         87 0            85 0           232 32000000    125 32000000    111 32000000    109 32000000    109 32000000    
  453. 16.6667     53       82         89 0            86 0           152 5333334      99 5333334      95 5333334      94 5333334      93 5333334    
  454. 9.09091     52       82         88 0            85 0           148 2909091      94 2909091      92 2909091      91 2909091      91 2909091    
  455. 6.25        52       81         88 0            86 0           148 2000000      92 2000000      89 2000000      89 2000000      89 2000000    
  456. 4.7619      52       82         88 0            86 0           135 1523810      91 1523810      90 1523810      89 1523810      88 1523810    
  457. 3.84615     52       82         89 0            86 0           129 1230770      91 1230770      89 1230770      88 1230770      87 1230770    
  458. 3.22581     52       82         88 0            85 0           116 1032259      90 1032259      88 1032259      88 1032259      88 1032259    
  459. 2.77778     52       82         88 0            85 0           111 888889       90 888889       88 888889       89 888889       87 888889      
  460. 2.43902     52       82         87 0            87 0           108 780488       90 780488       88 780488       88 780488       86 780488      
  461. 2.17391     52       82         88 0            85 0           104 695653       94 695653       89 695653       87 695653       86 695653
  462.  
  463. -> memcopy is indeed faster than loopcopy
  464. -> the bitmapcopy versions do not update anything at all (bug)
  465. -> the updatingcopy versions beat the patchedcopy versions
  466.  
  467. --------------------------------------------------------------------------------
  468. TEST RUN 2
  469. --------------------------------------------------------------------------------
  470. $ g++ -Wall -O3 -DFIXME -o bitmapslow2 bitmapslow2.cpp
  471.  
  472. density(%)  memcopy  loopcopy  bitmapcopy      bitmapcopy8bits patchedcopy     patchedcopy2    updatingcopy    updatingcopy2   updatingcopy3  
  473. 100         52       82        102 32000000     91 32000000    232 32000000    125 32000000    111 32000000    109 32000000    109 32000000    
  474. 16.6667     52       82         93 5333334      90 5333334     153 5333334      99 5333334      95 5333334      94 5333334      93 5333334    
  475. 9.09091     52       83         91 2909091      88 2909091     148 2909091      95 2909091      91 2909091      91 2909091      91 2909091    
  476. 6.25        52       82         90 2000000      88 2000000     147 2000000      92 2000000      90 2000000      89 2000000      89 2000000    
  477. 4.7619      52       83         90 1523810      87 1523810     135 1523810      93 1523810      89 1523810      89 1523810      88 1523810    
  478. 3.84615     52       82         89 1230770      87 1230770     129 1230770      90 1230770      89 1230770      88 1230770      87 1230770    
  479. 3.22581     52       82         89 1032259      86 1032259     117 1032259      90 1032259      88 1032259      90 1032259      87 1032259    
  480. 2.77778     52       82         89 888889       88 888889      110 888889       90 888889       89 888889       88 888889       87 888889      
  481. 2.43902     52       82         89 780488       86 780488      107 780488       90 780488       88 780488       88 780488       86 780488      
  482. 2.17391     52       83         89 695653       86 695653      105 695653       90 695653       89 695653       88 695653       86 695653
  483.  
  484. -> -DFIXME: now the bitmapcopy versions perform updates and are quite fast for high density
  485. -> the updatingcopy and bitmapcopy version have equal performance for low density
  486. -> raw pointer arithmetic does not perform better than operator[]
  487. -> (iterators were tested as well with same performance results)
  488.  
  489. --------------------------------------------------------------------------------
  490. TEST RUN 3
  491. --------------------------------------------------------------------------------
  492. $ g++ -Wall -O3 -DFIXME -DNDEBUG -o bitmapslow2 bitmapslow2.cpp
  493.  
  494. density(%)  memcopy  loopcopy  bitmapcopy      bitmapcopy8bits patchedcopy     patchedcopy2    updatingcopy    updatingcopy2   updatingcopy3  
  495. 100         52       83         87 0            85 0           233 0           117 0           111 0           109 0           109 0          
  496. 16.6667     53       82         94 0            89 0           152 0            98 0            94 0            95 0            93 0          
  497. 9.09091     52       82         93 0            88 0           148 0            93 0            91 0            92 0            90 0          
  498. 6.25        53       82         89 0            87 0           147 0            92 0            90 0            89 0            90 0          
  499. 4.7619      52       83         93 0            87 0           135 0            91 0            89 0            88 0            89 0          
  500. 3.84615     52       82         92 0            90 0           128 0            90 0            89 0            89 0            88 0          
  501. 3.22581     52       83         90 0            86 0           118 0            90 0            88 0            88 0            88 0          
  502. 2.77778     52       82         91 0            86 0           110 0            90 0            88 0            88 0            87 0          
  503. 2.43902     52       82         91 0            86 0           109 0            89 0            88 0            88 0            87 0          
  504. 2.17391     52       82         91 0            86 0           105 0            89 0            89 0            87 0            87 0    
  505.  
  506. -> -DNDEBUG: the update operation counter is disabled to get real performance, although it makes no difference
  507. -> the bitmapcopy versions are not to beat for high density, but the approach is more error-prone
  508. --------------------------------------------------------------------------------
  509. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement