Skip to content

Instantly share code, notes, and snippets.

@ti-kamlesh
Created August 30, 2023 11:09
Show Gist options
  • Save ti-kamlesh/002df094dd522422c6cb62069e15c40d to your computer and use it in GitHub Desktop.
Save ti-kamlesh/002df094dd522422c6cb62069e15c40d to your computer and use it in GitHub Desktop.
crc32 with mmap from userspace
#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