tesseract引擎RVV代码学习笔记
Tesseract 是一个开源的 OCR(Optical Character Recognition,光学字符识别)引擎,可将图像中的文本转换为机器可读的文本格式。由于组内曾经有同事为这个项目贡献了RVV(RISC-V Vector)的代码,我打算单独拎出来学习一下。
PR链接在此:Add RISC-V V support by hleft · Pull Request #4346 · tesseract-ocr/tesseract。由于有一定的篇幅,我只挑了汇编部分来进行阅读。
static int DotProduct(const int8_t *u, const int8_t *v, int num) {
int total = 0;
asm __volatile__ (
" .option arch, +v \n\t"
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
" vmv.v.i v0,0 \n\t"
"1: \n\t"
" vsetvli t0,%[num],e8,m2,ta,ma \n\t"
" vle8.v v16,0(%[u]) \n\t"
" vle8.v v24,0(%[v]) \n\t"
" sub %[num],%[num],t0 \n\t"
" vwmul.vv v8,v24,v16 \n\t"
" add %[u],%[u],t0 \n\t"
" add %[v],%[v],t0 \n\t"
" vsetvli zero,zero,e16,m4,tu,ma \n\t"
" vwadd.wv v0,v0,v8 \n\t"
" bnez %[num],1b \n\t"
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
" vmv.s.x v8,zero \n\t"
" vredsum.vs v0,v0,v8 \n\t"
" vmv.x.s %[total],v0 \n\t"
: [u] "+r" (u),
[v] "+r" (v),
[num] "+r" (num),
[total] "+r" (total)
:
: "cc", "memory"
);
return total;
}
这个函数主要用来实现一维向量乘积,采用了内嵌汇编的方式进行优化,除了用RVV汇编,还可以用封装好的riscv_vector.h接口,不过这里使用了最原始的汇编,我们分段阅读。
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
" vmv.v.i v0,0 \n\t"
vsetvli是跟向量寄存器组有关的指令,这里设置向量长度为最大(zero表示根据配置自动计算),然后再对向量寄存器初始化为0。
"1: \n\t"
" vsetvli t0,%[num],e8,m2,ta,ma \n\t"
" vle8.v v16,0(%[u]) \n\t"
" vle8.v v24,0(%[v]) \n\t"
" sub %[num],%[num],t0 \n\t"
1这里表示进入了循环,用RVV的好处就是循环过程中步长会自动调整,比如说长度为18,如果每次步长为8,传统的SIMD需要8+8+3,8是可以用向量指令集去实现,但是3这里就需要采用普通for循环手写,但是RVV会自动忽略掉这个过程,不用担心越界,只需关注循环内部本身即可,因为硬件会根据情况自动调整为向量步长为3。另外,这里vsetvli加载了num操作数到t0寄存器,寄存器存的是向量步长,e8代表元素大小,相当于int8类型,因为函数参数传入的也是int8 *的指针。
" vwmul.vv v8,v24,v16 \n\t"
" add %[u],%[u],t0 \n\t"
" add %[v],%[v],t0 \n\t"
vwmul.vv指令首先对v24和v16这两个向量寄存器组里面的元素求和,然后扩展位宽到16位,存到v8向量寄存器里面。之所以要扩展位宽,是因为8位的数乘8位的数可能会变成16位的数。add这里就是分别对传入的两个函数参数进行指针的移动。
" vsetvli zero,zero,e16,m4,tu,ma \n\t"
" vwadd.wv v0,v0,v8 \n\t"
" bnez %[num],1b \n\t"
到了这一步,vsetvli重新将操作数类型变为16位的,因为刚刚上面乘法的时候已经扩展为16位了。接着vwadd.wv将v8的结果累加到v0向量寄存器组,由于最后返回值是32位的,这里同样用了扩展位宽的加法。
" vsetvli t0,zero,e32,m8,ta,ma \n\t"
" vmv.s.x v8,zero \n\t"
" vredsum.vs v0,v0,v8 \n\t"
" vmv.x.s %[total],v0 \n\t"
最后是这里,vsetvli重新调整向量寄存器中的元素为32位,接下来对v8清零,将v0寄存器组的所有元素归约求和到v0寄存器中,最后再将结果移到变量total当中,这个函数到此就实现完成了。
这么看来,RVV在自动调整步长方面还是很有优势的(比起SIMD),不过由于汇编比较晦涩难懂,所以下次打算寻找RVV C-Intrinsics的代码进行解剖。
tesseract引擎RVV代码学习笔记的更多相关文章
- Learning Memory-guided Normality代码学习笔记
Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...
- DeepLearnToolbox-master代码学习笔记
卷积神经网络(CNN)博大精深,网上资料浩如烟海,让初学者无从下手.笔者以为,学习编程还是从代码实例入们最好.目前,学习CNN最好的代码实例就是,DeepLearnToolbox-master,不用装 ...
- html5游戏引擎-Pharse.js学习笔记(一)
1.前言 前几天随着flappy bird这样的小游戏的火爆,使我这种也曾了解过html5技术的js业余爱好者也开始关注游戏开发.研究过两个个比较成熟的html5游戏引擎,感觉用引擎还是要方便一些.所 ...
- 动力学仿真引擎ODE的学习笔记,C#演示(一)
®版权声明:本文为博主原创文章,未经博主允许不得转载. 一.ODE介绍与平台搭建. 接触到动力学仿真引擎, 是因为笔者的一款PLC仿真软件需要3D仿真.我需要达到的效果是,以3D方式构建出工控行业中常 ...
- C# 好代码学习笔记(1):文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS
目录 1,文件操作 2,读取文件 3,Debug .Trace类 4,条件编译 5,MethodImpl 特性 5,CLSCompliantAttribute 6,必要时自定义类型别名 目录: 1,文 ...
- 1.JAVA中使用JNI调用C++代码学习笔记
Java 之JNI编程1.什么是JNI? JNI:(Java Natibe Inetrface)缩写. 2.为什么要学习JNI? Java 是跨平台的语言,但是在有些时候仍然是有需要调用本地代码 ( ...
- APM代码学习笔记1
libraries目录 传感器 AP_InertialSensor 惯性导航传感器 就是陀螺仪加速计 AP_Baro 气压计 居然支持BMP085 在我印象中APM一直用高端的MS5611 AP_Co ...
- boost timer代码学习笔记
socket连接中需要判断超时 所以这几天看了看boost中计时器的文档和示例 一共有五个例子 从简单的同步等待到异步调用超时处理 先看第一个例子 // timer1.cpp: 定义控制台应用程序的入 ...
- Java模板引擎之Freemarker 学习笔记 一
什么是Freemarker Freemarker是模板引擎,不是Web框架,只是视图层的组件,官网是 https://freemarker.apache.org/ Freemarker原理 数据模型+ ...
- cc代码学习笔记1
#define #define INT32 int #define INT8 char #define CHAR char #define SSHORT signed short #define IN ...
随机推荐
- WPF 背景阴影窗体
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/200 ...
- Java技术栈总结-基础
- - -计算机技术演化- - -1 编程语言演化1.1 写在最前 此文用于个人总结,串接知识点 1.2 汇编 举例:mov .add 特点:程序量很大,几百行.几千行乃至几万行 1.3 VB- ...
- runoob-Lua 教程
https://www.runoob.com/lua/lua-tutorial.html Lua 特性 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里. ...
- 【Docker】---Docker入门篇(1)
Docker入门篇 简单一句话: Docker 是一个便携的应用容器. 一.Docker的作用 网上铺天盖地的是这么说的: (1) Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得 ...
- 深⼊mysqlONDUPLICATEKEYUPDATE语法的分析
深⼊mysqlONDUPLICATEKEYUPDATE语法的分析mysql "ON DUPLICATE KEY UPDATE" 语法如果在INSERT语句末尾指定了ON DUPLI ...
- C#中DevExpress的GridControl相关表格的属性总结
这里用到了Dev中的GridControl表格做数据查询展示,要求字号大一些,单行选中深色显示 // grid1 this.grid1.Dock = System.Windows.Forms.Dock ...
- CF935D Fafa and Ancient Alphabet 题解
讲一个很暴力的方法(为描述方便,下文 \(a\) 数组代表 \(s1\),\(b\) 数组代表 \(s2\)). 发现假如当前 \(a_i\ne b_i\),就不需要再向下枚举了,于是拥有了分类讨论的 ...
- Ansible - [07] 定义变量的几种方式
题记部分 Ansible 支持十几种定义变量的方式 Inventory 变量 Host Facts 变量 Register 变量 Playbook 变量 Playbook 提示变量 变量文件 命令行变 ...
- swoole(7)php进程间通信-消息队列
php实现消息队列操作 ftok:可以将一个路径转换成消息队列可用的key值 msg_get_queue:第一个参数是消息队列的key 第二个参数是消息队列的读写权限 server代码: <?p ...
- 解决 Ubuntu 22.04 下 flameshot 截图工具无法使用的问题
问题描述 flameshot 是 Linux 端广受好评的一款截图工具,但在 Ubuntu 22.04 中,安装完成后却不能使用,表现为截图命令无响应,或截图过程报错. 通过查阅 flameshot ...