crc32c.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/mman.h>
  5. #include <fcntl.h>
  6. #include <sys/stat.h>
  7. #include <err.h>
  8. #include <getopt.h>
  9. #include <nmmintrin.h>
  10. #include <time.h>
  11. #include <libutil.h>
  12. #define POLY 0x82f63b78
  13. static uint32_t crc32c_poly[256];
  14. /*
  15. * Create Poly table
  16. */
  17. static void crc32_table()
  18. {
  19. uint32_t crc;
  20. for (uint32_t i = 0; i < 256; i++) {
  21. crc = i;
  22. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  23. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  24. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  25. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  26. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  27. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  28. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  29. crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
  30. crc32c_poly[i] = crc;
  31. }
  32. }
  33. /*
  34. * CRC32C software computing
  35. *
  36. * @data: buffer
  37. * @length: size
  38. */
  39. uint32_t crc32c(const char *data, size_t length)
  40. {
  41. uint32_t crc = ~(0U);
  42. printf("Software computing:\n");
  43. printf("------------------\n");
  44. while (length--) {
  45. crc = crc32c_poly[(crc ^ (uint32_t)(*data++)) & 0xFFL] ^ (crc >> 8);
  46. }
  47. return crc ^ 0xffffffff;
  48. }
  49. /*
  50. * CRC32C hardware intrinsics
  51. *
  52. * @data: buffer
  53. * @length: size
  54. */
  55. uint32_t crc32c_hw(const char *data, size_t length)
  56. {
  57. uint32_t crc = ~(0U);
  58. printf("Hardware computing:\n");
  59. printf("------------------\n");
  60. while (length--) {
  61. crc = _mm_crc32_u8(crc, (unsigned char)(*data++));
  62. }
  63. return crc ^ 0xffffffff;
  64. }
  65. /*
  66. * smart helpers
  67. */
  68. void fd_close(int *fd)
  69. {
  70. close(*fd);
  71. *fd = -1;
  72. }
  73. #define _smartfd __attribute((cleanup(fd_close)))
  74. void file_close(FILE **fd)
  75. {
  76. fclose(*fd);
  77. *fd = NULL;
  78. }
  79. #define _smartfile __attribute((cleanup(file_close)))
  80. [[noreturn]] static int usage(void)
  81. {
  82. fputs("crc32c [--input file]\n", stderr);
  83. exit (EXIT_SUCCESS);
  84. }
  85. /*
  86. * Print human readable numbers
  87. *
  88. * @width: spaces
  89. * @bytes: value in bytes
  90. */
  91. static void printsize(size_t width, off_t bytes)
  92. {
  93. /*
  94. * Reserve one space before the size and allocate room for
  95. * the trailing '\0'.
  96. */
  97. char buf[5];
  98. humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
  99. HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
  100. (void)printf("%*s", (u_int)width, buf);
  101. }
  102. int main(int argc, char *argv[])
  103. {
  104. static struct option longopts[] = {
  105. { "input", required_argument, NULL, 'i' },
  106. { NULL, 0, NULL, 0 }
  107. };
  108. int ch;
  109. _smartfd int fd = -1;
  110. char *inputfile = NULL;
  111. while ((ch = getopt_long(argc, argv, "hi:", longopts, NULL)) != -1) {
  112. switch (ch) {
  113. case 'i':
  114. inputfile = optarg;
  115. break;
  116. case 0:
  117. /* long option */
  118. break;
  119. default:
  120. usage();
  121. }
  122. }
  123. argc -= optind;
  124. argv += optind;
  125. if (*argv || (inputfile == NULL))
  126. usage();
  127. fd = open(inputfile, O_RDONLY);
  128. if (fd < 0) {
  129. err(EXIT_FAILURE, "failed to open %s:", inputfile);
  130. }
  131. /* File analysis */
  132. struct stat statbuf = { 0 };
  133. fstat(fd, & statbuf);
  134. printf("Parsing");
  135. printsize(8, statbuf.st_size);
  136. puts(".\n");
  137. char *addr = (char *)mmap(NULL, (size_t)statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  138. if (addr == NULL)
  139. err(EXIT_FAILURE, "Failed to map file %s:\n", inputfile);
  140. /* CRC32C */
  141. crc32_table();
  142. clock_t t1, t0;
  143. t0 = clock();
  144. uint32_t c = crc32c(addr, (size_t)statbuf.st_size);
  145. t1 = clock();
  146. printf("CRC32C => %08x: %6.3f ms\n", c, 1000.0 * (double)(t1 - t0) / CLOCKS_PER_SEC);
  147. printf("\n");
  148. c = crc32c_hw(addr, (size_t)statbuf.st_size);
  149. t0 = clock();
  150. printf("CRC32C => %08x: %6.3f ms\n", c, 1000.0 * (double)(t0 - t1) / CLOCKS_PER_SEC);
  151. munmap(addr, (size_t)statbuf.st_size);
  152. return EXIT_SUCCESS;
  153. }