crc32c.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. Copyright (c) 2013 - 2014 Mark Adler, Robert Vazan
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the author be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely, subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not
  10. claim that you wrote the original software. If you use this software
  11. in a product, an acknowledgment in the product documentation would be
  12. appreciated but is not required.
  13. 2. Altered source versions must be plainly marked as such, and must not be
  14. misrepresented as being the original software.
  15. 3. This notice may not be removed or altered from any source distribution.
  16. */
  17. #ifndef _CRT_SECURE_NO_WARNINGS
  18. #define _CRT_SECURE_NO_WARNINGS
  19. #endif
  20. #include "crc32c.h"
  21. #define NOMINMAX
  22. #include <windows.h>
  23. #include <nmmintrin.h>
  24. #include <stdio.h>
  25. #include <random>
  26. #include <algorithm>
  27. typedef const uint8_t *buffer;
  28. #include "generated-constants.cpp"
  29. static uint32_t append_trivial(uint32_t crc, buffer input, size_t length)
  30. {
  31. for (size_t i = 0; i < length; ++i)
  32. {
  33. crc = crc ^ input[i];
  34. for (int j = 0; j < 8; j++)
  35. crc = (crc >> 1) ^ 0x80000000 ^ ((~crc & 1) * POLY);
  36. }
  37. return crc;
  38. }
  39. /* Table-driven software version as a fall-back. This is about 15 times slower
  40. than using the hardware instructions. This assumes little-endian integers,
  41. as is the case on Intel processors that the assembler code here is for. */
  42. static uint32_t append_adler_table(uint32_t crci, buffer input, size_t length)
  43. {
  44. buffer next = input;
  45. uint64_t crc;
  46. crc = crci ^ 0xffffffff;
  47. while (length && ((uintptr_t)next & 7) != 0)
  48. {
  49. crc = table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
  50. --length;
  51. }
  52. while (length >= 8)
  53. {
  54. crc ^= *(uint64_t *)next;
  55. crc = table[7][crc & 0xff]
  56. ^ table[6][(crc >> 8) & 0xff]
  57. ^ table[5][(crc >> 16) & 0xff]
  58. ^ table[4][(crc >> 24) & 0xff]
  59. ^ table[3][(crc >> 32) & 0xff]
  60. ^ table[2][(crc >> 40) & 0xff]
  61. ^ table[1][(crc >> 48) & 0xff]
  62. ^ table[0][crc >> 56];
  63. next += 8;
  64. length -= 8;
  65. }
  66. while (length)
  67. {
  68. crc = table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
  69. --length;
  70. }
  71. return (uint32_t)crc ^ 0xffffffff;
  72. }
  73. /* Table-driven software version as a fall-back. This is about 15 times slower
  74. than using the hardware instructions. This assumes little-endian integers,
  75. as is the case on Intel processors that the assembler code here is for. */
  76. static uint32_t append_table(uint32_t crci, buffer input, size_t length)
  77. {
  78. buffer next = input;
  79. #ifdef _M_X64
  80. uint64_t crc;
  81. #else
  82. uint32_t crc;
  83. #endif
  84. crc = crci ^ 0xffffffff;
  85. #ifdef _M_X64
  86. while (length && ((uintptr_t)next & 7) != 0)
  87. {
  88. crc = table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
  89. --length;
  90. }
  91. while (length >= 16)
  92. {
  93. crc ^= *(uint64_t *)next;
  94. uint64_t high = *(uint64_t *)(next + 8);
  95. crc = table[15][crc & 0xff]
  96. ^ table[14][(crc >> 8) & 0xff]
  97. ^ table[13][(crc >> 16) & 0xff]
  98. ^ table[12][(crc >> 24) & 0xff]
  99. ^ table[11][(crc >> 32) & 0xff]
  100. ^ table[10][(crc >> 40) & 0xff]
  101. ^ table[9][(crc >> 48) & 0xff]
  102. ^ table[8][crc >> 56]
  103. ^ table[7][high & 0xff]
  104. ^ table[6][(high >> 8) & 0xff]
  105. ^ table[5][(high >> 16) & 0xff]
  106. ^ table[4][(high >> 24) & 0xff]
  107. ^ table[3][(high >> 32) & 0xff]
  108. ^ table[2][(high >> 40) & 0xff]
  109. ^ table[1][(high >> 48) & 0xff]
  110. ^ table[0][high >> 56];
  111. next += 16;
  112. length -= 16;
  113. }
  114. #else
  115. while (length && ((uintptr_t)next & 3) != 0)
  116. {
  117. crc = table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
  118. --length;
  119. }
  120. while (length >= 12)
  121. {
  122. crc ^= *(uint32_t *)next;
  123. uint32_t high = *(uint32_t *)(next + 4);
  124. uint32_t high2 = *(uint32_t *)(next + 8);
  125. crc = table[11][crc & 0xff]
  126. ^ table[10][(crc >> 8) & 0xff]
  127. ^ table[9][(crc >> 16) & 0xff]
  128. ^ table[8][crc >> 24]
  129. ^ table[7][high & 0xff]
  130. ^ table[6][(high >> 8) & 0xff]
  131. ^ table[5][(high >> 16) & 0xff]
  132. ^ table[4][high >> 24]
  133. ^ table[3][high2 & 0xff]
  134. ^ table[2][(high2 >> 8) & 0xff]
  135. ^ table[1][(high2 >> 16) & 0xff]
  136. ^ table[0][high2 >> 24];
  137. next += 12;
  138. length -= 12;
  139. }
  140. #endif
  141. while (length)
  142. {
  143. crc = table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
  144. --length;
  145. }
  146. return (uint32_t)crc ^ 0xffffffff;
  147. }
  148. /* Apply the zeros operator table to crc. */
  149. static inline uint32_t shift_crc(uint32_t shift_table[][256], uint32_t crc)
  150. {
  151. return shift_table[0][crc & 0xff]
  152. ^ shift_table[1][(crc >> 8) & 0xff]
  153. ^ shift_table[2][(crc >> 16) & 0xff]
  154. ^ shift_table[3][crc >> 24];
  155. }
  156. /* Compute CRC-32C using the Intel hardware instruction. */
  157. static uint32_t append_hw(uint32_t crc, buffer buf, size_t len)
  158. {
  159. buffer next = buf;
  160. buffer end;
  161. #ifdef _M_X64
  162. uint64_t crc0, crc1, crc2; /* need to be 64 bits for crc32q */
  163. #else
  164. uint32_t crc0, crc1, crc2;
  165. #endif
  166. /* pre-process the crc */
  167. crc0 = crc ^ 0xffffffff;
  168. /* compute the crc for up to seven leading bytes to bring the data pointer
  169. to an eight-byte boundary */
  170. while (len && ((uintptr_t)next & 7) != 0)
  171. {
  172. crc0 = _mm_crc32_u8(static_cast<uint32_t>(crc0), *next);
  173. ++next;
  174. --len;
  175. }
  176. #ifdef _M_X64
  177. /* compute the crc on sets of LONG_SHIFT*3 bytes, executing three independent crc
  178. instructions, each on LONG_SHIFT bytes -- this is optimized for the Nehalem,
  179. Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a
  180. throughput of one crc per cycle, but a latency of three cycles */
  181. while (len >= 3 * LONG_SHIFT)
  182. {
  183. crc1 = 0;
  184. crc2 = 0;
  185. end = next + LONG_SHIFT;
  186. do
  187. {
  188. crc0 = _mm_crc32_u64(crc0, *reinterpret_cast<const uint64_t *>(next));
  189. crc1 = _mm_crc32_u64(crc1, *reinterpret_cast<const uint64_t *>(next + LONG_SHIFT));
  190. crc2 = _mm_crc32_u64(crc2, *reinterpret_cast<const uint64_t *>(next + 2 * LONG_SHIFT));
  191. next += 8;
  192. } while (next < end);
  193. crc0 = shift_crc(long_shifts, static_cast<uint32_t>(crc0)) ^ crc1;
  194. crc0 = shift_crc(long_shifts, static_cast<uint32_t>(crc0)) ^ crc2;
  195. next += 2 * LONG_SHIFT;
  196. len -= 3 * LONG_SHIFT;
  197. }
  198. /* do the same thing, but now on SHORT_SHIFT*3 blocks for the remaining data less
  199. than a LONG_SHIFT*3 block */
  200. while (len >= 3 * SHORT_SHIFT)
  201. {
  202. crc1 = 0;
  203. crc2 = 0;
  204. end = next + SHORT_SHIFT;
  205. do
  206. {
  207. crc0 = _mm_crc32_u64(crc0, *reinterpret_cast<const uint64_t *>(next));
  208. crc1 = _mm_crc32_u64(crc1, *reinterpret_cast<const uint64_t *>(next + SHORT_SHIFT));
  209. crc2 = _mm_crc32_u64(crc2, *reinterpret_cast<const uint64_t *>(next + 2 * SHORT_SHIFT));
  210. next += 8;
  211. } while (next < end);
  212. crc0 = shift_crc(short_shifts, static_cast<uint32_t>(crc0)) ^ crc1;
  213. crc0 = shift_crc(short_shifts, static_cast<uint32_t>(crc0)) ^ crc2;
  214. next += 2 * SHORT_SHIFT;
  215. len -= 3 * SHORT_SHIFT;
  216. }
  217. /* compute the crc on the remaining eight-byte units less than a SHORT_SHIFT*3
  218. block */
  219. end = next + (len - (len & 7));
  220. while (next < end)
  221. {
  222. crc0 = _mm_crc32_u64(crc0, *reinterpret_cast<const uint64_t *>(next));
  223. next += 8;
  224. }
  225. #else
  226. /* compute the crc on sets of LONG_SHIFT*3 bytes, executing three independent crc
  227. instructions, each on LONG_SHIFT bytes -- this is optimized for the Nehalem,
  228. Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a
  229. throughput of one crc per cycle, but a latency of three cycles */
  230. while (len >= 3 * LONG_SHIFT)
  231. {
  232. crc1 = 0;
  233. crc2 = 0;
  234. end = next + LONG_SHIFT;
  235. do
  236. {
  237. crc0 = _mm_crc32_u32(crc0, *reinterpret_cast<const uint32_t *>(next));
  238. crc1 = _mm_crc32_u32(crc1, *reinterpret_cast<const uint32_t *>(next + LONG_SHIFT));
  239. crc2 = _mm_crc32_u32(crc2, *reinterpret_cast<const uint32_t *>(next + 2 * LONG_SHIFT));
  240. next += 4;
  241. } while (next < end);
  242. crc0 = shift_crc(long_shifts, static_cast<uint32_t>(crc0)) ^ crc1;
  243. crc0 = shift_crc(long_shifts, static_cast<uint32_t>(crc0)) ^ crc2;
  244. next += 2 * LONG_SHIFT;
  245. len -= 3 * LONG_SHIFT;
  246. }
  247. /* do the same thing, but now on SHORT_SHIFT*3 blocks for the remaining data less
  248. than a LONG_SHIFT*3 block */
  249. while (len >= 3 * SHORT_SHIFT)
  250. {
  251. crc1 = 0;
  252. crc2 = 0;
  253. end = next + SHORT_SHIFT;
  254. do
  255. {
  256. crc0 = _mm_crc32_u32(crc0, *reinterpret_cast<const uint32_t *>(next));
  257. crc1 = _mm_crc32_u32(crc1, *reinterpret_cast<const uint32_t *>(next + SHORT_SHIFT));
  258. crc2 = _mm_crc32_u32(crc2, *reinterpret_cast<const uint32_t *>(next + 2 * SHORT_SHIFT));
  259. next += 4;
  260. } while (next < end);
  261. crc0 = shift_crc(short_shifts, static_cast<uint32_t>(crc0)) ^ crc1;
  262. crc0 = shift_crc(short_shifts, static_cast<uint32_t>(crc0)) ^ crc2;
  263. next += 2 * SHORT_SHIFT;
  264. len -= 3 * SHORT_SHIFT;
  265. }
  266. /* compute the crc on the remaining eight-byte units less than a SHORT_SHIFT*3
  267. block */
  268. end = next + (len - (len & 7));
  269. while (next < end)
  270. {
  271. crc0 = _mm_crc32_u32(crc0, *reinterpret_cast<const uint32_t *>(next));
  272. next += 4;
  273. }
  274. #endif
  275. len &= 7;
  276. /* compute the crc for up to seven trailing bytes */
  277. while (len)
  278. {
  279. crc0 = _mm_crc32_u8(static_cast<uint32_t>(crc0), *next);
  280. ++next;
  281. --len;
  282. }
  283. /* return a post-processed crc */
  284. return static_cast<uint32_t>(crc0) ^ 0xffffffff;
  285. }
  286. static bool detect_hw()
  287. {
  288. int info[4];
  289. __cpuid(info, 1);
  290. return (info[2] & (1 << 20)) != 0;
  291. }
  292. static bool hw_available = detect_hw();
  293. extern "C" CRC32C_API uint32_t crc32c_append(uint32_t crc, buffer input, size_t length)
  294. {
  295. if (hw_available)
  296. return append_hw(crc, input, length);
  297. else
  298. return append_table(crc, input, length);
  299. }
  300. #define TEST_BUFFER 65536
  301. #define TEST_SLICES 1000000
  302. static int benchmark(const char *name, uint32_t(*function)(uint32_t, buffer, size_t), buffer input, int *offsets, int *lengths, uint32_t *crcs)
  303. {
  304. uint64_t startTime = GetTickCount64();
  305. int slice = 0;
  306. uint64_t totalBytes = 0;
  307. bool first = true;
  308. int iterations = 0;
  309. uint32_t crc = 0;
  310. while (GetTickCount64() - startTime < 1000)
  311. {
  312. crc = function(crc, input + offsets[slice], lengths[slice]);
  313. totalBytes += lengths[slice];
  314. if (first)
  315. crcs[slice] = crc;
  316. ++slice;
  317. ++iterations;
  318. if (slice == TEST_SLICES)
  319. {
  320. slice = 0;
  321. first = false;
  322. }
  323. }
  324. int time = static_cast<int>(GetTickCount64() - startTime);
  325. double throughput = totalBytes * 1000.0 / time;
  326. printf("%s: ", name);
  327. if (throughput > 1024.0 * 1024.0 * 1024.0)
  328. printf("%.1f GB/s\n", throughput / 1024 / 1024 / 1024);
  329. else
  330. printf("%.0f MB/s\n", throughput / 1024 / 1024);
  331. return std::min(TEST_SLICES, iterations);
  332. }
  333. static void compare_crcs(const char *leftName, uint32_t *left, const char *rightName, uint32_t *right, int count)
  334. {
  335. for (int i = 0; i < count; ++i)
  336. if (left[i] != right[i])
  337. {
  338. printf("CRC mismatch between algorithms %s and %s at offset %d: %x vs %x\n", leftName, rightName, i, left[i], right[i]);
  339. exit(1);
  340. }
  341. }
  342. extern "C" CRC32C_API void crc32c_unittest()
  343. {
  344. std::random_device rd;
  345. std::uniform_int_distribution<int> byteDist(0, 255);
  346. uint8_t *input = new uint8_t[TEST_BUFFER];
  347. for (int i = 0; i < TEST_BUFFER; ++i)
  348. input[i] = byteDist(rd);
  349. int *offsets = new int[TEST_SLICES];
  350. int *lengths = new int[TEST_SLICES];
  351. std::uniform_int_distribution<int> lengthDist(0, TEST_BUFFER);
  352. for (int i = 0; i < TEST_SLICES; ++i)
  353. {
  354. lengths[i] = lengthDist(rd);
  355. std::uniform_int_distribution<int> offsetDist(0, TEST_BUFFER - lengths[i]);
  356. offsets[i] = offsetDist(rd);
  357. }
  358. uint32_t *crcsTrivial = new uint32_t[TEST_SLICES];
  359. uint32_t *crcsAdlerTable = new uint32_t[TEST_SLICES];
  360. uint32_t *crcsTable = new uint32_t[TEST_SLICES];
  361. uint32_t *crcsHw = new uint32_t[TEST_SLICES];
  362. int iterationsTrivial = benchmark("trivial", append_trivial, input, offsets, lengths, crcsTrivial);
  363. int iterationsAdlerTable = benchmark("adler_table", append_adler_table, input, offsets, lengths, crcsAdlerTable);
  364. compare_crcs("trivial", crcsTrivial, "adler_table", crcsAdlerTable, std::min(iterationsTrivial, iterationsAdlerTable));
  365. int iterationsTable = benchmark("table", append_table, input, offsets, lengths, crcsTable);
  366. compare_crcs("adler_table", crcsAdlerTable, "table", crcsTable, std::min(iterationsAdlerTable, iterationsTable));
  367. if (hw_available)
  368. {
  369. int iterationsHw = benchmark("hw", append_hw, input, offsets, lengths, crcsHw);
  370. compare_crcs("table", crcsTable, "hw", crcsHw, std::min(iterationsTable, iterationsHw));
  371. }
  372. else
  373. printf("HW doesn't have crc instruction\n");
  374. benchmark("auto", crc32c_append, input, offsets, lengths, crcsHw);
  375. }