|
|
@@ -0,0 +1,159 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <sys/mman.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <err.h>
|
|
|
+#include <getopt.h>
|
|
|
+#include <nmmintrin.h>
|
|
|
+#include <time.h>
|
|
|
+
|
|
|
+#define POLY 0x82f63b78
|
|
|
+
|
|
|
+static uint32_t crc32c_poly[256];
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create Poly table
|
|
|
+ */
|
|
|
+static void crc32_table()
|
|
|
+{
|
|
|
+ uint32_t crc;
|
|
|
+ for (uint32_t i = 0; i < 256; i++) {
|
|
|
+ crc = i;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
|
|
|
+ crc32c_poly[i] = crc;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * CRC32C software computing
|
|
|
+ *
|
|
|
+ * @data: buffer
|
|
|
+ * @length: size
|
|
|
+ */
|
|
|
+uint32_t crc32c(const char *data, size_t length)
|
|
|
+{
|
|
|
+ uint32_t crc = ~(0U);
|
|
|
+
|
|
|
+ printf("Software computing:");
|
|
|
+ printf("------------------");
|
|
|
+
|
|
|
+ while (length--) {
|
|
|
+ crc = crc32c_poly[(crc ^ (uint32_t)(*data++)) & 0xFFL] ^ (crc >> 8);
|
|
|
+ }
|
|
|
+ return crc ^ 0xffffffff;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * CRC32C hardware intrinsics
|
|
|
+ *
|
|
|
+ * @data: buffer
|
|
|
+ * @length: size
|
|
|
+ */
|
|
|
+uint32_t crc32c_hw(const char *data, size_t length)
|
|
|
+{
|
|
|
+ uint32_t crc = ~(0U);
|
|
|
+
|
|
|
+ printf("Hardware computing:");
|
|
|
+ printf("------------------");
|
|
|
+ while (length--) {
|
|
|
+ crc = _mm_crc32_u8(crc, (unsigned char)(*data++));
|
|
|
+ }
|
|
|
+ return crc ^ 0xffffffff;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * smart helpers
|
|
|
+ */
|
|
|
+void fd_close(int *fd)
|
|
|
+{
|
|
|
+ close(*fd);
|
|
|
+ *fd = -1;
|
|
|
+}
|
|
|
+#define _smartfd __attribute((cleanup(fd_close)))
|
|
|
+
|
|
|
+void file_close(FILE **fd)
|
|
|
+{
|
|
|
+ fclose(*fd);
|
|
|
+ *fd = NULL;
|
|
|
+}
|
|
|
+#define _smartfile __attribute((cleanup(file_close)))
|
|
|
+
|
|
|
+[[noreturn]] static int usage(void)
|
|
|
+{
|
|
|
+ fputs("crc32c [--input file]\n", stderr);
|
|
|
+ exit (EXIT_SUCCESS);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ static struct option longopts[] = {
|
|
|
+ { "input", required_argument, NULL, 'i' },
|
|
|
+ { NULL, 0, NULL, 0 }
|
|
|
+ };
|
|
|
+
|
|
|
+ int ch;
|
|
|
+ _smartfd int fd = -1;
|
|
|
+ char *inputfile = NULL;
|
|
|
+
|
|
|
+ while ((ch = getopt_long(argc, argv, "hi:", longopts, NULL)) != -1) {
|
|
|
+ switch (ch) {
|
|
|
+ case 'i':
|
|
|
+ inputfile = optarg;
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ /* long option */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ usage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ argc -= optind;
|
|
|
+ argv += optind;
|
|
|
+
|
|
|
+ if (*argv || (inputfile == NULL))
|
|
|
+ usage();
|
|
|
+
|
|
|
+ fd = open(inputfile, O_RDONLY);
|
|
|
+ if (fd < 0) {
|
|
|
+ err(EXIT_FAILURE, "failed to open %s:", inputfile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* File analysis */
|
|
|
+ struct stat statbuf = { 0 };
|
|
|
+ fstat(fd, & statbuf);
|
|
|
+
|
|
|
+ printf("Parsing %zu bytes.\n", statbuf.st_size);
|
|
|
+
|
|
|
+ char *addr = (char *)mmap(NULL, (size_t)statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
+
|
|
|
+ if (addr == NULL)
|
|
|
+ err(EXIT_FAILURE, "Failed to map file %s:\n", inputfile);
|
|
|
+
|
|
|
+
|
|
|
+ /* CRC32C */
|
|
|
+ crc32_table();
|
|
|
+ clock_t t1, t0;
|
|
|
+ t0 = clock();
|
|
|
+ uint32_t c = crc32c(addr, (size_t)statbuf.st_size);
|
|
|
+ t1 = clock();
|
|
|
+ printf("CRC32C => %08x: %d\n", c, (t1 - t0) * CLOCKS_PER_SEC);
|
|
|
+ c = crc32c_hw(addr, (size_t)statbuf.st_size);
|
|
|
+ t0 = clock();
|
|
|
+ printf("CRC32C => %08x: %d\n", c, (t0 - t1) * CLOCKS_PER_SEC);
|
|
|
+
|
|
|
+ munmap(addr, (size_t)statbuf.st_size);
|
|
|
+
|
|
|
+ return EXIT_SUCESS;
|
|
|
+}
|
|
|
+
|