大数跨境

RISC-V Vector加速实验-memcpy

RISC-V Vector加速实验-memcpy RVBoards
2023-10-14
2
导读:前言您可能听说或者使用过SIMD指令,例如x86的MMX,SSE,AVX-2和AVX-512,ARM的NEO
前言

您可能听说或者使用过SIMD指令,例如x86MMXSSEAVX-2AVX-512ARMNEONSVE这些。而RISC-V为什么采用VectorV向量)扩展呢?David Patterson Andrew Waterman曾发表过一篇《SIMD instruction considered harmful》(中文标题:SIMD指令被认为是有害的)的文章,感兴趣的可以去阅读以下。但,无论是SIMD还是Vector的加速指令集,都是现代处理器极其重要的特性,对提升处理器性能起着非常重要的作用。

RISC-V尚处于发展的早期阶段,由此,我也经常听到一些不准确的测试和评论,例如:
  • 使用GCC编译器进行benchmark,得到一些不准确的处理器性能指标。原因可能是GCC版本并未对RISC-V指令集进行起码的优化,甚至于不支持自动向量化。这有时相当于,一个高手绑住了他的左手进行决斗。
  • RISC-V还没有类似Intel针对自家处理器深度优化的各种基础库,RISC-V所使用的绝大多数开源库都还没有社区进行优化,这制约了RISC-V处理器性能的发挥。

  • 绝大多数软件工程师,欠缺对于SIMDVector加速指令集的理解,忽视了加速指令集的重要性。

所以本系列实验和文章,尽量少讲理论,主要从实践出发,来向大家展示RISC-V Vector如何使用和对性能提升的意义。本系列实验,将聚焦到使用V扩展对一系列经典算法和函数进行加速,以单核为主,也将会忽略掉cache、流水线等因素的影响。同时为了避免编译器带来的不确定性,将使用intrinsic编写代码,并展示出对应的汇编代码(Assembly

测试环境

【硬件参数】

CPU: SOPHGO SG2042

RISC-V CoreC920Vector 0.7.1

L1 Cache: I:64KB and D:64KB

L2 Cache: 1MB/Cluster

L3 Cache: 64MB System Cache

DRAM: DDR4 16Gx4

【软件环境】

linux版本: 22.10

gcc版本: 10.2.0

  • T-HEAD C920 的矢量扩展支持以下特性:

1.C920 兼容 RISC-V Vector Spec 0.7.1。支持所有标准矢量指令,支持 Zvamo 指令和 Zvlsseg 指令,不支持 Zvediv 扩展。

2.32 个独立的矢量寄存器 v0-v31。矢量寄存器的位宽为 128 (VLEN=128)

3.对于矢量浮点指令,支持的元素类型为 FP16FP32FP64(SEW=16/32/64)

4.对于矢量整型指令,支持的元素类型为 INT8INT16INT32 INT64(SEW=8/16/32/64)

5.支持矢量寄存器的分组,以提高矢量运算的效率。支持 4 种分组方式:每组包含 1/2/4/8 个矢量寄存器,分成32/16/8/4个组。

 

使用Vector加速memcpy

简介

内存拷贝操作是一个非常常见且基本的任务。本实验将使用vectormemcpy进行加速和评估性能提升。

函数原型

void *memcpy(void *destin, void *source, unsigned n);
参数
destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。source-- 指向要复制的数据源,类型强制转换为 void* 指针。n-- 要被复制的字节数。

实验过程

1.为了便于比较,我用C语言编写了memcpy的函数,考虑到64位处理器,每次拷贝了一个8bytes

C代码:

void *memcpy_8byte(void *destin, void *source, size_t n){    long *dst = destin;    const long *src = source;    for (; n > 7; n -= 8)    {        *dst++ = *src++;    }    if (n > 0)    {        char *char_dst = (char *)dst;        const char *char_src = (const char *)src;        for (size_t i = 0; i < n; i++)        {            char_dst[i] = char_src[i];        }    }    return destin;}
编译命令
gcc -S memcpy_8byte.c -O3 -march=rv64gcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c920
编译成汇编如下:
memcpy_8byte:
li a5,7
bleu a2,a5,.L5
addi a7,a2,-8
andi a7,a7,-8
addi a7,a7,8
add a6,a0,a7
mv a4,a1
mv a5,a0
.L3:
ld a3,0(a4)
addi a5,a5,8
addi a4,a4,8
sd a3,-8(a5)
bne a5,a6,.L3
andi a2,a2,7
add a1,a1,a7
.L2:
beq a2,zero,.L4
lbu a4,0(a1)
li a5,1
sb a4,0(a6)
beq a2,a5,.L4
lbu a4,1(a1)
li a5,2
sb a4,1(a6)
beq a2,a5,.L4
lbu a4,2(a1)
li a5,3
sb a4,2(a6)
beq a2,a5,.L4
lbu a4,3(a1)
li a5,4
sb a4,3(a6)
beq a2,a5,.L4
lbu a4,4(a1)
li a5,5
sb a4,4(a6)
beq a2,a5,.L4
lbu a4,5(a1)
li a5,7
sb a4,5(a6)
bne a2,a5,.L4
lbu a5,6(a1)
sb a5,6(a6)
.L4:
ret
.L5:
mv a6,a0
j .L2
.size memcpy_8byte, .-memcpy_8byte
.ident "GCC: (GNU) 10.2.0"
.section .note.GNU-stack,"",@progbits

写了一个简单的测试代码如下:

int main(){    char src[50]={"Hello,World"};    char dst[50];    memcpy_8byte(dst, src, strlen(src)+1);    printf("dest=%s\n", dst);    return 0;}

测试结果如下:

 

2.使用intrinsic实现memcpy函数的加速,注意该CPUVector位宽位128bits

C代码:

void *memcpy_rvv(void  *destin, void *source, unsigned n){    unsigned char *dst = destin;    const unsigned char *src = source;    for (size_t vl; n > 0; n -= vl, src += vl, dst += vl)    {        vl = vsetvl_e8m4(n);        vuint8m4_t vec_src = vle8_v_u8m4(src, vl);        vse8_v_u8m4(dst, vec_src, vl);    }    return destin;}
编译命令:
gcc -S rvv_memcpy.c -O3 -march=rv64gcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c920
编译成汇编如下:
memcpy_rvv:
beq a2,zero,.L2
mv a4,a0
.align 3
.L3:
extu a5,a2,31,0
vsetvli a5,a5,e8,m4
vle.v v4,0(a1)
subw a2,a2,a5
add a1,a1,a5
vse.v v4,0(a4)
add a4,a4,a5
bne a2,zero,.L3
.L2:
ret
.size memcpy_rvv, .-memcpy_rvv
.ident "GCC: (GNU) 10.2.0"
.section .note.GNU-stack,"",@progbits

写了一个简单的测试代码如下:

int main(){    char src[50]={"Hello,World"};    char dst[50];    memcpy_rvv(dst, src, strlen(src)+1);    printf("dest=%s\n", dst);    return 0;}

测试结果如下:

 

性能测试

测试代码实现如下,测试数据大小164K Bytes,循环十次,取最大值。

void benchmark_memcpy_task(void *(*memcpy_function)(void *, void *, size_t), size_t buf_size, size_t loop_times){    unsigned char *source_buffer = malloc(buf_size);    unsigned char *destination_buffer = malloc(buf_size);    initialize_buffer(source_buffer, buf_size);    double max_speed = 0.0;    for (int i = 0; i < loop_times; ++i)    {        struct timespec start_clockend_clock;        clock_gettime(CLOCK_MONOTONIC, &start_clock);        memcpy_function(destination_buffer, source_buffer, buf_size);        clock_gettime(CLOCK_MONOTONIC, &end_clock);        long long elapsed_time = (end_clock.tv_sec - start_clock.tv_sec) * 1000000000 + (end_clock.tv_nsec - start_clock.tv_nsec);        double speed = (double)buf_size / (1024 * 1024) / (elapsed_time / 1000000000.0);        if (speed > max_speed)        {            max_speed = speed;        }    }    double buf_size_kb = (double)buf_size / 1024;    printf("%8.0f   %8.0f \n", buf_size_kb, max_speed);    // 使用memcmp比较两个内存块是否相等    int result = memcmp(source_buffer, destination_buffer, buf_size);    if (result != 0)    {        printf("Memory comparison result: Not equal.\n");    }    free(source_buffer);    free(destination_buffer);}

性能对比曲线如下:

 

参考文档:

https://github.com/riscv/riscv-v-spec/tree/master/example

https://github.com/riscv-non-isa/rvv-intrinsic-doc/tree/main/examples

--正文结束--


  • 关于RISC-V公共测试平台

    RISC-V高性能处理器公共测试平台。

  • 快速使用指南

    下载链接:   https://www.kdocs.cn/l/cmnYcyFIlVRx

  • 加入我们的RISC-V社区

    欢迎关注我们,参与进来共建RISC-V软件生态。加入我们的讨论群后,可以向管理员申请免费的64核RISC-V服务器SUDO权限试用账号

  1. 发邮件到riscvinfo@perfxlab.com

  2. 加入微信讨论群:加iYuta-R2为好友后可拉入群。

  3. 加入QQ讨论群:906962594(RVBoards·Only RISC-V)

扫描二维码加群👇

  • RISC-V公共测试平台系列文章

  1. RISC-V公测平台发布 ·Stream带宽完整测试

  2. RISC-V公测平台发布 · 我的世界MohistMC

  3. RISC-V公测平台发布 · 第一个WEB Server“Hello RISC-V world!”
  4.  RISC-V公测平台发布 ·如何在SG2042上玩转k3s
  5.  “RISC-V成长日记” blog发布,第一个运行在RISC-V服务器上的blog?
  6. RISC-V公测平台发布:如何在SG2042上玩转OpenMPI
  7. RISC-V公测平台发布:Compiling The Fedora Linux Kernel Natively on RISC-V
  8. RISC-V公测平台发布 · Unix Bench完整测试
  9. RISC-V公测平台发布 · 使用YCSB测试SG2042上的MySQL性能
  10. RISC-V公测平台发布 · 7-zip 测试
  11. RISC-V公测平台发布 · CoreMark测试报告
  12. RISC-V公测平台发布 · 数据库在RISC-V服务器上的适配评估
  13. RISC-V公测平台发布 ·  FFTW的移植和性能对比
  14. RISC-V公测平台发布 · 在SG2042上配置Jupiter+Octave科学计算环境
  15. RISC-V公测平台发布:在SG2042上玩转Caddy
  16. RISC-V公测平台发布:在SG2042上玩转docker
  17. RISC-V Vector加速实验-memcpy (本篇)



【声明】内容源于网络
0
0
RVBoards
内容 0
粉丝 0
RVBoards
总阅读0
粉丝0
内容0