#include #include #include #include #include #include #include #include #include #include #include #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:\n"); printf("------------------\n"); 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:\n"); printf("------------------\n"); 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); } /* * Print human readable numbers * * @width: spaces * @bytes: value in bytes */ static void printsize(size_t width, off_t bytes) { /* * Reserve one space before the size and allocate room for * the trailing '\0'. */ char buf[5]; humanize_number(buf, sizeof(buf), (int64_t)bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); (void)printf("%*s", (u_int)width, buf); } 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"); printsize(8, statbuf.st_size); puts(".\n"); 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: %6.3f ms\n", c, 1000.0 * (double)(t1 - t0) / CLOCKS_PER_SEC); printf("\n"); c = crc32c_hw(addr, (size_t)statbuf.st_size); t0 = clock(); printf("CRC32C => %08x: %6.3f ms\n", c, 1000.0 * (double)(t0 - t1) / CLOCKS_PER_SEC); munmap(addr, (size_t)statbuf.st_size); return EXIT_SUCCESS; }