fork download
  1. #include <algorithm>
  2. #include <array>
  3. #include <cassert>
  4. #include <cxxabi.h>
  5. #include <cstring>
  6. #include <fstream>
  7. #include <iomanip>
  8. #include <iostream>
  9. #include <sstream>
  10. #include <typeinfo>
  11.  
  12. template<typename T> uint8_t* get_nonconst_binary(T & t);
  13. template<typename T> const uint8_t* get_const_binary(const T & t);
  14.  
  15. template<typename T>
  16. std::string make_hex(const T & t)
  17. {
  18. std::stringstream ss;
  19. const uint8_t* c = get_const_binary(t);
  20. for (unsigned i = 0; i < sizeof(t); ++i)
  21. {
  22. if (i != 0)
  23. {
  24. ss << " ";
  25. }
  26. ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c[i]);
  27. }
  28. return ss.str();
  29. }
  30.  
  31. std::string make_string(uint8_t n) { return static_cast<std::stringstream&>(std::stringstream() << n).str(); }
  32. std::string make_string(uint16_t n) { return static_cast<std::stringstream&>(std::stringstream() << n).str(); }
  33. std::string make_string(uint32_t n) { return static_cast<std::stringstream&>(std::stringstream() << n).str(); }
  34. std::string make_string(uint64_t n) { return static_cast<std::stringstream&>(std::stringstream() << n).str(); }
  35.  
  36. template<typename T>
  37. std::string make_string(const T & t)
  38. {
  39. return make_hex(t);
  40. }
  41.  
  42.  
  43. template<typename T>
  44. const uint8_t* get_const_binary(const T & t)
  45. {
  46. return static_cast<const uint8_t*>(static_cast<const void*>(&t));
  47. }
  48.  
  49.  
  50. template<typename T>
  51. uint8_t* get_nonconst_binary(T & t)
  52. {
  53. return const_cast<uint8_t*>(get_const_binary(t));
  54. }
  55.  
  56.  
  57. template<typename Destination, unsigned Index, unsigned Size>
  58. struct copy_impl;
  59.  
  60. template<typename Destination, unsigned Index, unsigned Size>
  61. struct copy_impl
  62. {
  63. void operator()(uint8_t* dst, const uint8_t* src)
  64. {
  65. dst[Index] = src[Index];
  66. copy_impl<Destination, Index + 1, Size>()(dst, src);
  67. }
  68. };
  69.  
  70. template<typename Destination, unsigned I>
  71. struct copy_impl<Destination, I, I>
  72. {
  73. void operator()(uint8_t*, const uint8_t*) { }
  74. };
  75.  
  76. template<typename Destination>
  77. void pod_copy(Destination & dst, const uint8_t* data)
  78. {
  79. uint8_t* bytes = get_nonconst_binary(dst);
  80. copy_impl<Destination, 0, sizeof(Destination)>()(bytes, data);
  81.  
  82. }
  83.  
  84. template<typename T>
  85. T make(const uint8_t* data)
  86. {
  87. T result;
  88. pod_copy(result, data);
  89. return result;
  90. }
  91.  
  92.  
  93. template<typename T>
  94. void assert_eq(const T & a, const T & b)
  95. {
  96. std::cout << "assert_eq:\n\t" << make_string(a) << "\n\t" << make_string(b) << std::endl;
  97. std::cout << ((0 == memcmp(&a, &b, sizeof(T))) ? " => PASS" : " => FAIL") << std::endl << std::endl;
  98. }
  99.  
  100.  
  101.  
  102. struct Header
  103. {
  104. uint32_t i[3];
  105. uint16_t s[2];
  106. uint8_t c[4];
  107. };
  108.  
  109. static_assert(sizeof(Header) == 20, "");
  110.  
  111. Header make_header()
  112. {
  113. Header result;
  114. uint8_t* c = reinterpret_cast<uint8_t*>(&result);
  115. for (unsigned i = 0; i < sizeof(result); ++i)
  116. {
  117. c[i] = i;
  118. }
  119. return result;
  120. }
  121.  
  122.  
  123.  
  124. #include <sys/time.h>
  125.  
  126.  
  127. double GetCurrentTime()
  128. {
  129. timeval tv;
  130. gettimeofday(&tv, NULL);
  131. return double (tv.tv_sec) + 0.000001 * tv.tv_usec;
  132. }
  133.  
  134.  
  135.  
  136. static const uint64_t iterations = 10000;
  137. static const uint64_t ns = uint64_t(1000) * uint64_t(1000) * uint64_t(1000);
  138.  
  139.  
  140.  
  141.  
  142. double test_unrolled_copy()
  143. {
  144. double t = GetCurrentTime();
  145. for (std::size_t i = 0; i != iterations; ++i)
  146. {
  147. Header header;
  148. const uint8_t * data = get_const_binary(make_header());
  149. pod_copy(header, data);
  150. }
  151.  
  152. return ns * (GetCurrentTime() - t) / iterations;
  153. }
  154.  
  155. double test_std_copy()
  156. {
  157. double t = GetCurrentTime();
  158. for (std::size_t i = 0; i != iterations; ++i)
  159. {
  160. Header header;
  161. const uint8_t * data = get_const_binary(make_header());
  162. std::copy(data, data + sizeof(Header), get_nonconst_binary(header));
  163. }
  164. return ns * (GetCurrentTime() - t) / iterations;
  165. }
  166.  
  167. double test_memcpy()
  168. {
  169. double t = GetCurrentTime();
  170. for (std::size_t i = 0; i != iterations; ++i)
  171. {
  172. Header header;
  173. const uint8_t * data = get_const_binary(make_header());
  174. memcpy(&header, data, sizeof(header));
  175. }
  176. return ns * (GetCurrentTime() - t) / iterations;
  177. }
  178.  
  179.  
  180. int main()
  181. {
  182. std::cout << "unrolled : " << test_unrolled_copy() << " ns per copy" << std::endl;
  183. std::cout << "std::copy: " << test_std_copy() << " ns per copy" << std::endl;
  184. std::cout << "memcpy : " << test_memcpy() << " ns per copy" << std::endl;
  185. std::cout << std::endl;
  186.  
  187. std::cout << "std::copy: " << test_std_copy() << " ns per copy" << std::endl;
  188. std::cout << "unrolled : " << test_unrolled_copy() << " ns per copy" << std::endl;
  189. std::cout << "memcpy : " << test_memcpy() << " ns per copy" << std::endl;
  190. std::cout << std::endl;
  191.  
  192. std::cout << "std::copy: " << test_std_copy() << " ns per copy" << std::endl;
  193. std::cout << "memcpy : " << test_memcpy() << " ns per copy" << std::endl;
  194. std::cout << "unrolled : " << test_unrolled_copy() << " ns per copy" << std::endl;
  195. std::cout << std::endl;
  196.  
  197. std::cout << "memcpy : " << test_memcpy() << " ns per copy" << std::endl;
  198. std::cout << "std::copy: " << test_std_copy() << " ns per copy" << std::endl;
  199. std::cout << "unrolled : " << test_unrolled_copy() << " ns per copy" << std::endl;
  200. std::cout << std::endl;
  201. }
  202.  
  203.  
Success #stdin #stdout 0s 2896KB
stdin
Standard input is empty
stdout
unrolled : 45.6883 ns per copy
std::copy: 45.401 ns per copy
memcpy   : 26.5948 ns per copy

std::copy: 42.9984 ns per copy
unrolled : 43.4956 ns per copy
memcpy   : 24.9908 ns per copy

std::copy: 42.9919 ns per copy
memcpy   : 24.8884 ns per copy
unrolled : 44.2008 ns per copy

memcpy   : 25.4091 ns per copy
std::copy: 43.8063 ns per copy
unrolled : 43.9922 ns per copy