Created
August 30, 2023 11:09
-
-
Save ti-kamlesh/002df094dd522422c6cb62069e15c40d to your computer and use it in GitHub Desktop.
crc32 with mmap from userspace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE /* See feature_test_macros(7) */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <errno.h> | |
#include <stdarg.h> | |
#include <limits.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/un.h> | |
#include <sys/vfs.h> | |
#include <sys/mount.h> | |
#include <sys/syscall.h> | |
#include <sys/sendfile.h> | |
#include <sys/resource.h> | |
#include <sys/mman.h> | |
#include <time.h> | |
#include <linux/if_alg.h> | |
#include <arpa/inet.h> | |
#include <fcntl.h> | |
#define BUFSIZE 1024*1024 | |
#define SECTOR 4096 | |
#define CRC32X(crc, value) __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32W(crc, value) __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32H(crc, value) __asm__("crc32h %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32B(crc, value) __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32CX(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32CW(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32CH(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
#define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) | |
struct timespec start, end; | |
struct timespec start_mmap, end_mmap,start_crc, end_crc; | |
struct timespec diff_mmap, diff_crc, diff; | |
struct timespec timetest; | |
double accum; | |
uint32_t crc32_arm64_le_hw(uint32_t crc, const uint8_t *p, unsigned int len) | |
{ | |
int64_t length = len; | |
while ((length -= sizeof(uint64_t)) >= 0) { | |
CRC32X(crc, *((uint64_t *)p)); | |
p += sizeof(uint64_t); | |
} | |
if (length & sizeof(uint32_t)) { | |
CRC32W(crc, *((uint32_t *)p)); | |
p += sizeof(uint32_t); | |
} | |
if (length & sizeof(uint16_t)) { | |
CRC32H(crc, *((uint16_t *)p)); | |
p += sizeof(uint16_t); | |
} | |
if (length & sizeof(uint8_t)) | |
CRC32B(crc, *p); | |
return crc; | |
} | |
static void time_diff_total(struct timespec *res, const struct timespec *start, const struct timespec *end) | |
{ | |
res->tv_sec += end->tv_sec - start->tv_sec; | |
res->tv_nsec += end->tv_nsec - start->tv_nsec; | |
if (res->tv_nsec < 0) { | |
res->tv_sec--; | |
res->tv_nsec += 1000000000; | |
} | |
} | |
static void time_diff(struct timespec *res, const struct timespec *start, const struct timespec *end) | |
{ | |
res->tv_sec = end->tv_sec - start->tv_sec; | |
res->tv_nsec = end->tv_nsec - start->tv_nsec; | |
if (res->tv_nsec < 0) { | |
res->tv_sec--; | |
res->tv_nsec += 1000000000; | |
} | |
/* printf("diff = %lf\r\n", accum); */ | |
} | |
static int obj_hash(const char *object, uint8_t *out, size_t len) | |
{ | |
uint8_t *buf; | |
uint32_t crc=~0; | |
struct sockaddr_alg alg = { | |
.salg_family = AF_ALG, | |
.salg_type = "hash", | |
.salg_name = "crc32", | |
}; | |
int ret, cfd, ofd, ffd; | |
struct stat stbuff; | |
size_t size = 0; | |
off_t offset = 0; | |
if (!object || len != 4) | |
return -EINVAL; | |
ffd = open(object, O_RDONLY ); | |
if (ffd < 0) { | |
fprintf(stderr, "Error opening object %s: %s\n", | |
object, strerror(errno)); | |
ret = ffd; | |
goto out_ofd; | |
} | |
ret = fstat(ffd, &stbuff); | |
if (ret < 0) { | |
fprintf(stderr, "Error doing fstat: %s\n", | |
strerror(errno)); | |
goto out_ffd; | |
} | |
clock_gettime(CLOCK_MONOTONIC, &start); | |
size_t file_size = stbuff.st_size; | |
clock_gettime(CLOCK_MONOTONIC, &start_mmap); | |
buf = mmap(NULL,stbuff.st_size, | |
PROT_READ,MAP_SHARED /* MAP_HUGETLB|MAP_PRIVATE|MAP_ANONYMOUS */, | |
ffd,0); | |
size = stbuff.st_size; | |
clock_gettime(CLOCK_MONOTONIC, &end_mmap); | |
time_diff_total(&diff_mmap, &start_mmap, &end_mmap); | |
if(buf == MAP_FAILED){ | |
fprintf(stderr, "Error doing mmap: %s\n", | |
strerror(errno)); | |
goto out_ffd; | |
} | |
while(stbuff.st_size) { | |
stbuff.st_size -= size; | |
if( size < 0) { | |
fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n", | |
size, stbuff.st_size, strerror(errno)); | |
ret = -1; | |
goto out_ffd; | |
} | |
if(size > 0){ | |
clock_gettime(CLOCK_MONOTONIC, &start_crc); | |
crc=crc32_arm64_le_hw(crc,buf,size); | |
clock_gettime(CLOCK_MONOTONIC, &end_crc); | |
time_diff_total(&diff_crc, &start_crc, &end_crc); | |
} | |
} | |
ret = clock_gettime(CLOCK_MONOTONIC, &end); | |
*(unsigned int*)out = crc; | |
struct timespec diff; | |
time_diff(&diff, &start, &end); | |
double t_hash = ((double)file_size) / (diff.tv_sec + (diff.tv_nsec * 0.000000001 )); | |
printf("Speed: %.02f Mb/s\n", t_hash / (1024 * 1024)); | |
accum = (diff_mmap.tv_sec) + (double)(diff_mmap.tv_nsec) / (double)1000000000L; | |
printf("diff_mmap = %lf\n", accum); | |
accum = (diff_crc.tv_sec) + (double)(diff_crc.tv_nsec) / (double)1000000000L; | |
printf("diff_crc = %lf\n", accum); | |
out_ffd: | |
close(ffd); | |
out_ofd: | |
close(ofd); | |
out_cfd: | |
close(cfd); | |
return ret; | |
} | |
int main(int ac, char **av) | |
{ | |
uint8_t hash[4] = {}; | |
if (ac != 2) { | |
fprintf(stderr, "%s file\n", av[0]); | |
return 1; | |
} | |
printf("\n"); | |
obj_hash(av[1], hash, sizeof(hash)); | |
printf("hash %x\n", ~(*(unsigned int *)hash)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment