当前位置: 首页 > news >正文

性能优化-HVX 指令介绍

「发表于知乎专栏《移动端算法优化》」

本文主要介绍了 HVX 指令相关的知识,包括 HVX 寄存器相关内容,指令的背景依赖,部分常用 intrinsic HVX 指令。具体指令的详细内容及使用还需阅读 HVX 的指令文档,以及细致的实践操作。

🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:高性能(HPC)开发基础教程
🎀CSDN主页 发狂的小花
🌄人生秘诀:学习的本质就是极致重复!

目录

一、概述

二、HVX硬件介绍

2.1 处理器架构

2.2 HVX向量寄存器

三、HVX指令

3.1 VLIW

3.2 HVX指令分类

3.3 汇编指令格式介绍

四、HVX intrinsics指令介绍

4.1 向量类型格式

4.2 HVX intrinsics格式

4.3 Load/Store

4.4 Arithmetic

4.5 Logical and compare

4.6 Multiply

4.7 Shift

4.8 Permute

4.9 其他

五、总结


一、概述

随着骁龙多核AI引擎的发展,异构计算算力有了巨大提升,为了发挥CDSP HVX在AI和CV的优势,开发者必须熟练掌握HVX的指令。但是HVX指令多而复杂,基础指令就有上百条及一些复杂的特殊指令,写起来更是费劲。为了发挥其性能高的优势,开发者必须使用intrinsic或汇编的方式编排代码,因此完全掌握HVX指令至关重要。

本文接下来首先详细介绍HVX硬件架构,在了解架构的基础上着重介绍HVX指令相关内容,然后针对HVX开发中必须要掌握的HVX instrinsic展开图文并茂的说明。主要内容有HVX架构、寄存器、VLIW、汇编格式及ALU的Intrinsics指令使用,最后针对几个常用的Intrinsics 指令结合实例进行说明。

二、HVX硬件介绍

2.1 处理器架构

在上一篇文章中HVX架构简介详细介绍了HVX软件和硬件架构,为了能够更加深入理解HVX指令执行过程,此处详细说明Hexagon主处理器和hexagon HVX SIMD协处理的关系和指令执行过程。

Hexagon主处理和HVX协处理架构图

2.1.1 Hexagon主处理器的架构

Hexagon主处理器架构图

  • Hexagon 主处理器架构,由四个硬件线程组成,硬件线程共享一个指令cache(I)、数据cache(D)。
  • 每个硬件线程都可以访问执行 Hexagon 标量指令,这些指令在单个或成对 32 位寄存器上执行定点和浮点运算。
  • 每个硬件线程包含通用寄存器(R0-R31)、预测判断寄存器(P0-P3)及执行单元(S0-S3)。
  • 静态分组超长指令集架构(VLIW)。

2.1.2 HVX协处理器的架构

HVX协处理架构图

  • Hexagon HVX协处理架构,有四个HVX硬件线程,硬件线程间共享L2-cache和VTCM内存。
  • 每个硬件线程都可以访问执行HVX向量指令。
  • 每个硬件线程包含向量寄存器(V0-V31)、预测判断寄存器(Q0-Q3)、执行单元(ALU)及内存读写单元。
  • HVX指令可以使用Hexagon主处理器的标量操作数。
  • 静态分组超长指令集架构(VLIW)。

2.1.3 指令执行过程

Hexagon架构图

  • 指令执行过程从L2-cache加载指令和数据到I-cache和D-chche,经过Sequencer指令打包然后在执行单元(S0-S3)上执行。

2.1.4 Hexagon主处理器和HVX协处理指令共享

Hexagon core硬件线程通过访问 HVX 寄存器文件(HVX Context)来使用 HVX 协处理器。Hexagon core和HVX之间的指令包基于vector FIFO结构进行共享。因此同一个指令包中HVX指令可以与标量指令混合,如下所示,vector FIFO和HVX的处理器结构和指令混合汇编代码。

{r8 = add(r15,#128) //标量指令r14 = add(r13,#-1)r13 = add(r3,#128)v8 = vmem(r10+#0)  // HVX指令
}

以上讲解了整体架构,接下来着重说明HVX寄存器的内容。

2.2 HVX向量寄存器

2.2.1 HVX向量长度

HVX协处理随着架构不同向量寄存器长度分为64B(512bit)和128B(1024bit)模式,V66架构既包含64B也包含128B向量长度(两个HVX核为64B、两个HVX核为128B),V68架构以后只包含128B向量长度(四个HVX核均为128B),如下图所示。

向量寄存器长度

2.2.2 HVX向量寄存器数量及类别

本文中我们以V68架构展开说明,如上图右侧框内。每个HVX协处理器包含:

  • 32个1024bit的向量寄存器,V0-V31。
  • 4个128bit的预测寄存器,Q0-Q3。

向量寄存器

存放向量数据,每个向量元素的类型必须相同。向量寄存器根据处理元素的大小可以划分为 32/64/128个通道,对应数据类型为32bit/16bit/8bit。

1024-bit SIMD register

向量寄存器数据在SIMD指令操作中需要指定元素类型,例如:

// vo向量寄存器数据指定数据类型为signed byte
v0.b = vadd(v1.b,v2.b) //汇编
HVX_Vector Q6_Vb_vadd_VbVb(HVX_Vector Vu, HVX_Vector Vv) //intrinsic

常用的元素类型如下:

汇编标识intrinsic 标识含义
.bVbsigned byte
.ubVubunsigned byte
.hVhsigned halfword
.uhVuhunsigned halfword
.wVwsigned word
.uwVuwunsigned word

预测寄存器

预测寄存器每个bit位对应每个向量寄存器中的byte,既可以用来保存字节、半字和全字的比较结果。预测寄存器用Q表示,以下示例中,Q2代表预测寄存器的结果,在向量V5和V6中选择有效值在结果寄存器中。

// vmux选择指令,如果Q2为真,输出结果为V5,反之输出结果为V6
V4 = vmux(Q2, V5, V6)

三、HVX指令

这部分主要介绍VLIW、HVX指令分类和HVX汇编代码的格式和说明。

3.1 VLIW

3.1.1 VLIW解释说明

将指令的并行化(多发射)显式的声明在指令格式中,而处理器只负责执行指令,这种方式定义为超长指令字(Very Long Instruction Word,VLIW)体系结构。指令的并行化可由编译器完成,也可由开发者手写汇编代码完成,如下图所示红色圈内所示,即指令的并行化过程。

HVX的协处理指令集架构也是基于VLIW。因此,HVX协处理器有四个执行单元,理论上每个周期处理器可以执行4条指令。这4条指令看成一个指令包,取指、译码、执行单元每次都针对一个指令包进行操作,如下图所示,这就是HVX的VLIW。

指令包

虽然说指令按照VLIW并行化打包为指令包,但是也会有一定的打包规则,并不是任意组合,所以接下来会介绍HVX指令的打包规则。

3.1.2 HVX VLIW打包规则

HVX计算资源

HVX 提供了 6 种执行资源支持向量指令执行:loadstoreshiftpermute 以及 两个 multiply 。

  • 每条 HVX 指令均由上述部分资源组合而成,在S0-S3硬件资源执行
  • 每次并行执行一个指令包,由下图中指令单元负责打包分发
  • 每个指令包最多可以包含 4 条指令及一个循环结束指令,指令包需按照规则组合

VLIW打包规制

每个指令分别使用四个执行单元(shift、permute 以及 两个 multiply),且每个slot只能有一条指令,下表为HVX指令到slot执行单元的映射关系,手册中每条指令都会写可以占用的slot。

InstructionUsed Hexagon Slots
Aligned memory load0 or 1
Aligned memory store0
Unaligned memory load/store0Slot 1 must be empty.
Maximum of 3 instructions allowed in the packet
Multiplies2 or 3
Using full 32-64 bit R2 or 3
Simple ALU, permute, shif0, 1, 2, or 3

同时需要注意每个HVX指令对于执行单元的占用情况,在每条指令介绍下都会有说明,例如vmpa指令,下图红框内会对指令的HVX资源使用情况进行说明。

  • 指令包中只能包含两条load指令,或者一条load一条store指令
{V4 = vmem(iptrUp++#1)vmem(iptrUp++#1) = v4.curnopnop
}{V4 = vmem(iptrUp++#1)V5 = vmem(iptrUp++#1)nopnop
}
  • 若指令包中为简单的ALU,则均可以使用S0-S3
{ v14 = vnot(V14)                               // v14 = left bounary maskv16 = vsplat(R8)                              // 0xFF v12 = #0                                      // reset flag-collectorv6 = vlalign(v0,v2,#3)                        //[1]pixels #12
}
  • 不要在指令包中存在多个乘法,因为乘法只有在执行单元S2和S3上执行
//存在错误 -- vmpa指令需要使用S2和S3的两个乘法资源,指令包中只能包含一个vmpa指令
{ v1= vmem(iptr3++#1)                      //[1]v2.h += vmpa(v0.ub,c1c1c1c1.b)           //[1]v3.h += vmpa(v0.ub,c1c1c1c1.b)          
}

VLIW打包规制示例

以下样例为HVX协处理的指令包,指令在HVX处理器执行。

{v15 = vmem(R0++M1)vmem(R6++M1) = v14v18.uw = vrmpy(v16.ub, v17.ub)
}

上述HVX指令包完成一个1024bit数据加载,一次1024bit数据存储及地址更新,一次向量乘法(vrmpy占用两个乘法资源,在指令包中只能存在一条)。

3.2 HVX指令分类

根据指令使用的硬件资源类型不同,HVX指令分为以下几类 :

类别描述资源占用
ALU算术和逻辑运算操作使用任意一个硬件资源
Multiply乘法操作占用两个 mpy 资源或者占用两个中的一个
Shift & Bit Count位操作占用 shift 资源
Permute数据重排操作占用 xlane 资源
Load & Store数据存取操作对齐储存(vmem)会使用任意一个硬件资源 + ld 或 st 等资源。对齐取数据带 .tmp 的操作,只使用 ld资源;非对齐操作(vmemu)使用 ld 或 st + Xlane 资源;对齐存数据操作带 .new 时,只使用 st 资源。

3.3 汇编指令格式介绍

汇编格式

v<x><.><type> = <ops>(<input>)[:carry][:sat]
  • x表示32个向量寄存器的标识数字,type 为向量寄存器中数据的类型
  • type表示既可以向量寄存器中数据的类型:b、ub、h、uh、w、uw,也可以表示Aligned memory Load和Store数据的立即更新还是作为临时数据:.tmp、.new、.cur。
  • <ops> 为指令的具体指令操作标识,如 add、valignvaslvdmp 等等。

汇编示例

以有符号 halfword 的加法汇编指令为例,指令将 V4 中各 lane 的数据与 V3 中各 lane 的数据以有符号short进行进行相加,将结果存放在 V2 寄存器中。

V2.h=vadd(V3.h,V4.h)

HVX 汇编开发难点

HVX 的开发不仅仅是 SIMD 指令集的运用,汇编期 VLIW 指令的静态多发调度也尤为重要

相对于 intrinsic 指令而言

  • HVX 汇编开发需要对 HVX 指令集及硬件架构进行详细的学习 - 增加学习成本
  • HVX 汇编开发过程中需要对 HVX 指令打包,程序流程控制指令,.new\.tmp 指令,指令延迟,寄存器复用以及软件堆栈维护等多方面进行考虑 - 增加开发及维护难度,不利于迭代及增量开发
  • HVX 汇编指令严格对应硬件平台架构 - 不利于向后兼容扩展

因此,在非绝对性能瓶颈的实现中,建议使用 intrinsic 指令进行开发。

四、HVX intrinsics指令介绍

相比于汇编指令,HVX intrinsics 是一种更简单的编写 HVX 代码的方法,HVX Intrinsics 类似于 C 函数调用,在编译时由编译器替换为相应的汇编指令,使用时需要包含头文件hvx_hexagon_protos.h

4.1 向量类型格式

// 向量对格式
HVX_VectorPair
// 向量格式
HVX_Vector
// 判断向量格式
HVX_VectorPred

HVX的向量类型包含以上三种,其中HEXAGON_ARCH架构在V65以后HVX四核的向量长度为1024bit,V62到V65架构之前分为512bit和1024bit的HVX向量长度。HVX_Vector和HVX_VectorPred共用联合体,实现多种数据类型宽度兼容。

typedef union 
{size8u_t ud[MAX_VEC_SIZE_BYTES/8];size8s_t    d[MAX_VEC_SIZE_BYTES/8];size4u_t uw[MAX_VEC_SIZE_BYTES/4];size4s_t    w[MAX_VEC_SIZE_BYTES/4];size2u_t uh[MAX_VEC_SIZE_BYTES/2];size2s_t    h[MAX_VEC_SIZE_BYTES/2];size1u_t ub[MAX_VEC_SIZE_BYTES/1];size1s_t    b[MAX_VEC_SIZE_BYTES/1];size4s_t    qf32[MAX_VEC_SIZE_BYTES/4];size2s_t    qf16[MAX_VEC_SIZE_BYTES/2];size4s_t    sf[MAX_VEC_SIZE_BYTES/4];size2s_t    hf[MAX_VEC_SIZE_BYTES/2];
} mmvector_t, mmqreg_t;#ifdef __HVXDBL__typedef mmqreg_t        HEXAGON_VecPred128;typedef mmvector_t      HEXAGON_Vect1024;typedef mmvector_pair_t HEXAGON_Vect2048;#define HVX_VectorPred  HEXAGON_VecPred128#define HVX_Vector      HEXAGON_Vect1024#define HVX_VectorPair  HEXAGON_Vect2048
#elsetypedef mmqreg_t        HEXAGON_VecPred64;typedef mmvector_t      HEXAGON_Vect512;typedef mmvector_pair_t HEXAGON_Vect1024;#define HVX_VectorPred  HEXAGON_VecPred64#define HVX_Vector      HEXAGON_Vect512#define HVX_VectorPair  HEXAGON_Vect1024
#endif /*HVXDBL*/
  • HVX_VectorPair:向量对组合,由两个HVX_Vector向量组成,常用在指令运算后结果是奇偶排列结果中,例如如下数据扩展指令,把一个HVX_Vector向量扩展为HVX_VectorPair,Vdd.v[0]和Vdd.v[1]组成一个向量对(HVX_VectorPair),占用两个向量寄存器。

4.2 HVX intrinsics格式

Q6_<output_type>_<opname>_<input_type><input_type>_<mod>

1)Q6 表示高通第六代数字信号处理器,固定前缀

2) <output_type> 表示返回值类型,此处分为W和V开头,比如Ww,Vw等

  • Vw :表示输出类型为HVX_Vector,元素类型为word类型
  • Ww:表示输出类型为HVX_VectorPair,元素类型为word类型
标识符解释标识符解释
Vbint8 vectorWbint8 vector pair
Vubuint8 vectorWubuint8 vector pair
Vhint16 vectorWhint16 vector pair
Vuhuint16 vectorWuhuint16 vector pair
Vwint32 vectorWwint32 vector pair
Vuwuint32 vectorWuwuint32 vector pair

3) <opname> 表示具体操作,比如vadd,vmpy等

4) <input_type> 表示输入值类型,此处分为W、V、R和Q开头及组合,例如

HVX_VectorPair Q6_Wh_vmpy_VubRb(HVX_Vector Vu, Word32 Rt)Q6_Wh_vmpy_VubRb
  • W:表示输入类型为HVX_VectorPair向量对
  • V:表示输入类型为HVX_Vector向量
  • Q:表示输入类型为HVX_VectorPred预测向量
  • R:表示输入类型为Word标量
标识符解释标识符解释标识符解释
Vbint8 vectorWbint8 vectorpairRbint8 word
Vubuint8 vectorWubuint8 vectorpairRubuint8 word
Vhint16 vectorWhint16 vectorpairRhint16 word
Vuhuint16 vectorWuhuint16 vectorpairRuhuint16 word
Vwint32 vectorWwint32 vectorpairRword
Vuwuint32 vectorWuwuint32 vectorpairQHVX_VectorPred

5) <mod>

  • sat:表示饱和操作,例如
// Vu加Vv的结果做饱和操作
HVX_Vector Q6_Vb_vadd_VbVb_sat(HVX_Vector Vu, HVX_Vector Vv)
  • rnd:表示四舍五入操作,例如
// Vu加Vu的结果做进位输出操作
HVX_Vector Q6_Vw_vadd_VwVwQ_carry(HVX_Vector Vu, HVX_Vector Vv, HVX_VectorPred* Qp)
  • s1:表示左移一位操作,例如
// Vu加Vb的结果取平均值的四舍五入结果
HVX_Vector Q6_Vb_vavg_VbVb_rnd(HVX_Vector Vu, HVX_Vector Vv)

下面的章节将对每种类型的HVX intrinsic指令做出详细的描述。

4.3 Load/Store

按照地址对齐或者地址非对齐的方式在向量寄存器和内存之间搬移数据

HVX LOAD指令

  • 示例:
// 对齐地址
HVX_Vector v1 = *(HVX_Vector *)src;// 非对齐地址
typedef long HEXAGON_Vect_UN __attribute__((__vector_size__(VLEN)))__attribute__((aligned(4)));
HEXAGON_Vect_UN v2 = *(HEXAGON_Vect_UN *)src; 
  • 作用:完成内存到寄存器的数据搬运
  • 伪代码:Vd=vmem(Rt+#0)
  • 结果示意图:紫色框内代表输入数据

  • 相关指令
// 地址对齐加载             // 地址非对齐加载 
Vd=vmem(Rt)                vd = vmemu(Rt) 
// 立即使用加载            
Vd.cur=vmem(Rt+#s4)    
// 临时立即使用加载
Vd.tmp=vmem(Rt+#s4) 

HVX STORE指令

  • 示例:
// 对齐地址
HVX_Vector v1;
*(HVX_Vector *)src = v1;// 非对齐地址
HEXAGON_Vect_UN v2;
typedef long HEXAGON_Vect_UN __attribute__((__vector_size__(VLEN)))__attribute__((aligned(4)));
*(HEXAGON_Vect_UN *)src = v2; 
  • 作用:完成寄存器到内存的数据搬运
  • 伪代码:vmem(Rt+#0)= Vd
  • 结果示意图

  • 相关指令
// 字节使能对齐存储
If (Qv4) vmem(Rt) = Vs
// 新存储
vmem(Rt)=Os8.new
// 对齐存储
vmem(Rt)=Vs
// 非对齐存储
vmemu(Rt)=Vs

HVX 非对齐内存操作

  • vmemu非对齐操作指令,需要进行两次内存访问,与地址对齐访问相比会增加功耗和带宽,因此开发中我们建议尽量使用对齐LOAD和STORE指令。
  • vmemu非对齐指令占用两个HVX单元,分别是slot0和slot1。

HVX 对齐内存操作

  • vmem对齐操作指令,内存地址必须保证128Byte对齐。
  • 可以使用memalign(128,xxx)申请128Byte对齐内存,也可以使用ION相关函数申请。

4.4 Arithmetic

基本加减算法指令,完成向量数据的算法操作

vector 算术指令

  • 示例:HVX_Vector Q6_Vb_vsub_VbVb_sat(HVX_Vector Vu, HVX_Vector Vv)
  • 作用:两个输入vector加减法运算
  • 伪代码
for (i = 0; i < VELEM(8); i++) 
{Vd.b[i] = sat_s8(Vu.b[i] - Vv.b[i]) ;
}
  • 示意图

  • 相关指令
// type 类型加法:Vd.type = Vu.type + Vv.type;
HVX_Vector Q6_Vtype_vadd_VtypeVtype(HVX_Vector Vu, HVX_Vector Vv);// type 类型加法,结果进行饱和操作:Vd.type = sat_type(Vu.type + Vv.type);
HVX_Vector Q6_Vtype_vadd_VtypeVtype_sat(HVX_Vector Vu, HVX_Vector Vv);// type 类型减法:Vd.b = Vu.b - Vv.b;
HVX_Vector Q6_Vtype_vsub_VtypeVtype(HVX_Vector Vu, HVX_Vector Vv);

type:b、ub、h、uh、w、uw

vector pair 算术指令

  • 示例:HVX_VectorPair Q6_Ww_vadd_VhVh(HVX_Vector Vu, HVX_Vector Vv)
  • 作用:向量寄存器 Vu 与 Vv 进行相加操作,结果输出长度是输入的两倍,存放于向量对寄存器里,按照奇偶的方式排列。
奇偶排列:输入数据下标索引02468的结果存放在单独寄存器是偶排列,反之,13579...127是奇排列。
  • 伪代码
for (i = 0; i < VELEM(32); i++) 
{Vdd.v[0].w[i] = Vu.w[i].h[0] + Vv.w[i].h[0];Vdd.v[1].w[i] = Vu.w[i].h[1] + Vv.w[i].h[1];
}
  • 指令示意图

vadd

  • 结果示意图

  • 相关指令
// type 类型加法:vdd.type = Vu.type + Vv.type;
HVX_VectorPair Q6_Wtype0_vadd_Vtype1Vtype1(HVX_Vector Vu, HVX_Vector Vv)// type 类型减法:vdd.type = Vu.type - Vv.type;
HVX_VectorPair Q6_Wtype0_vsub_Vtype1Vtype1(HVX_Vector Vu, HVX_Vector Vv)// type 类型加法累加:vdd.type += Vu.type + Vv.type;
HVX_VectorPair Q6_Wtype0_vaddacc_Wtype0Vtype1Vtype1(HVX_VectorPair Vxx, HVX_Vector Vu, HVX_Vector Vv)

type0: h、w

type1: ub、h、uh

4.5 Logical and compare

eq表示相等,gt表示大于,eqand表示等于判断及与操作,gtand表示大于判断及与操作,eqxacc表示等于判断及异或操作,gtxacc表示大于判断及异或操作,eqor表示等于判断及或操作,gtor表示大于判断及或操作。

条件比较指令

  • 示例:HVX_VectorPred Q6_Q_vcmp_eq_VbVb(HVX_Vector Vu, HVX_Vector Vv)
  • 作用:向量寄存器 Vu 与 Vv 进行比较运算,结果存储在预测寄存器中
  • 伪代码
for( i = 0; i < VWIDTH; i += 1) 
{QxV[i] =((Vu.b[i] == Vv.b[i]) ? 0x1 : 0);
}
  • 示例结果

  • 相关指令
// type 类型相等判断:Qd4 = Vu == Vv;
HVX_VectorPred Q6_Q_vcmp_eq_Vtype0Vtype0(HVX_Vector Vu, HVX_Vector Vv);// type 类型大于判断:Qd4 = Vu > Vv;
HVX_VectorPred Q6_Q_vcmp_gt_Vtype1Vtype1(HVX_Vector Vu, HVX_Vector Vv);// type 类型相等判断及与操作:Qx4 &= Vu == Vv;
HVX_VectorPred Q6_Q_vcmp_eqand_QVtype0Vtype0(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv);// type 类型大于判断及与操作:Qx4 &= Vu > Vv;
HVX_VectorPred Q6_Q_vcmp_gtand_QVtype1Vtype1(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv); // type 类型相等判断及异或操作:Qx4 ^= Vu == Vv;
HVX_VectorPred Q6_Q_vcmp_eqxacc_QVtype0Vtype0(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv);// type 类型大于判断及异或操作:Qx4 ^= Vu > Vv;
HVX_VectorPred Q6_Q_vcmp_gtxacc_QVtype1Vtype1(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv);// type 类型相等判断及或操作:Qx4 |= Vu == Vv;
HVX_VectorPred Q6_Q_vcmp_eqor_QVtype0Vtype0(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv);// type 类型大于判断及或操作:Qx4 |= Vu > Vv;
HVX_VectorPred Q6_Q_vcmp_gtor_QVtype1Vtype1(HVX_VectorPred Qx, HVX_Vector Vu, HVX_Vector Vv); 

type0:b、h、w

type1:b、ub、h、uh、w、uw

位操作指令

  • 示例:HVX_VectorPred Q6_Q_not_Q(HVX_VectorPred Qs)
  • 作用:将条件寄存器 Qs 进行取反操作,结果保存至条件寄存器中
  • 伪代码
for (i = 0; i < VELEM(8); i++) 
{QdV[i] = !QsV[i];
}
  • 示意图:蓝色框代表输入数据,红色框代表输出数据

  • 相关指令
// 条件寄存器非与操作:Qd4 = Qs & ((!Qt) 或者 (Qt))
HVX_VectorPred Q6_Q_and_QQ<n>(HVX_VectorPred Qs, HVX_VectorPred Qt);// 条件寄存器非或操作:Qd4 = Qs | ((!Qt) 或者 (Qt))
HVX_VectorPred Q6_Q_or_QQ<n>(HVX_VectorPred Qs, HVX_VectorPred Qt);// 条件寄存器非操作:Qd4 = !Qs
HVX_VectorPred Q6_Q_not_Q(HVX_VectorPred Qs);// Vu 与标量 Rt 进行 u8 类型位与操作,填充条件寄存器:
// Qd4 = Vu.ub & Rt.ub => Qd4[i] = Vu.ub[i] & Rt.ub[i % 4] ? 1 : 0;
HVX_VectorPred Q6_Q_vand_VR(HVX_Vector Vu, Word32 Rt);// Vu 与标量 Rt 进行 u8 类型位与操作,结果与 Qx 进行或操作,Qx4 |= (Vu.ub & Rt.ub);
HVX_VectorPred Q6_Q_vandor_QVR(HVX_VectorPred Qx, HVX_Vector Vu, Word32 Rt);// 根据 !Qu 使用 Rt 以 u8 类型选择性填充 Vd
HVX_Vector Q6_V_vand_QnR(HVX_VectorPred Qu, Word32 Rt);// 根据 !Qu 使用 Rt 以 u8 类型选择性填充 Vd, 然后与 Vx 进行或运算
HVX_Vector Q6_V_vandor_VQnR(HVX_Vector Vx, HVX_VectorPred Qu, Word32 Rt);// 根据 Qu 使用 Rt 以 u8 类型选择性填充 Vd
HVX_Vector Q6_V_vand_QR(HVX_VectorPred Qu, Word32 Rt);// 根据 Qu 使用 Rt 以 u8 类型选择性填充 Vd, 然后与 Vx 进行或运算
HVX_Vector Q6_V_vandor_VQR(HVX_Vector Vx, HVX_VectorPred Qu, Word32 Rt);// 根据条件寄存器 Qt,以 u8 类型从 Vu 及 Vv 中选择填充 Vd
HVX_Vector Q6_V_vmux_QVV(HVX_VectorPred Qt, HVX_Vector Vu, HVX_Vector Vv);// 根据条件寄存器 Qt,以 u8 类型对 Vu 及 Vv 进行交换操作,结果保存至 HVX_VectorPair 中
HVX_VectorPair Q6_W_vswap_QVV(HVX_VectorPred Qt, HVX_Vector Vu, HVX_Vector Vv);

逻辑操作指令

  • 示例:HVX_Vector Q6_V_vnot_V(HVX_Vector Vu)
  • 作用:对向量寄存器Vu按位逻辑取反
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vd.uh[i] = ~Vu.uh[i] ;
}
  • 示意图

  • 相关指令
// Vu和Vv向量寄存器按位逻辑与
HVX_Vector Q6_V_vand_VV(HVX_Vector Vu, HVX_Vector Vv)// 对Vu向量寄存器按位取反
HVX_Vector Q6_V_vnot_V(HVX_Vector Vu)// Vu和Vv向量寄存器按位逻辑或
HVX_Vector Q6_V_vor_VV(HVX_Vector Vu, HVX_Vector Vv)// Vu和Vv向量寄存器按位逻辑异或
HVX_Vector Q6_V_vxor_VV(HVX_Vector Vu, HVX_Vector Vv)

取极值操作

  • 示例指令:HVX_Vector Q6_Vb_vmax_VbVb(HVX_Vector Vu, HVX_Vector Vv)
  • 作用:将两个数值向量寄存器进行比较操作,输出最大值到目的寄存器
  • 伪指令
for (i = 0; i < VELEM(8); i++) 
{Vd.b[i] = (Vu.b[i] > Vv.b[i]) ? Vu.b[i] : Vv.b[i] ;
}
  • 示意图

  • 相关指令
// type 类型最小值: Vd = min(Vu, Vv);
HVX_Vector Q6_Vtype_vmin_VtypeVtype(HVX_Vector Vu, HVX_Vector Vv);// type 类型最大值: Vd = max(Vu, Vv);
HVX_Vector Q6_Vtype_vmax_VtypeVtype(HVX_Vector Vu, HVX_Vector Vv);

type:b、ub、h、uh、w、uw

饱和操作

  • 示例指令:HVX_Vector Q6_Vub_vsat_VhVh(HVX_Vector Vu, HVX_Vector Vv)
  • 作用:向量寄存器 Vu Vv 中 s16 类型数据,进行 u8 类型饱和操作,然后寄存器高低交替保存至 Vd 寄存器中
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vd.uh[i].b[0]=usat_8(Vv.h[i]);Vd.uh[i].b[1]=usat_8(Vu.h[i]);
}
  • 示意图

  • 相关指令
// s16 类型 Vu Vv 饱和至 u8 类型
HVX_Vector Q6_Vub_vsat_VhVh(HVX_Vector Vu, HVX_Vector Vv);// u32 类型 Vu Vv 饱和至 u16 类型
HVX_Vector Q6_Vuh_vsat_VuwVuw(HVX_Vector Vu, HVX_Vector Vv);// s32 类型 Vu Vv 饱和至 s16 类型
HVX_Vector Q6_Vh_vsat_VwVw(HVX_Vector Vu, HVX_Vector Vv;

绝对值操作

  • 示例指令:HVX_Vector Q6_Vb_vabs_Vb(HVX_Vector Vu)
  • 作用:向量寄存器以 s8 的数值类型进行取绝对值操作,结果依旧为 s8 类型
  • 伪代码
for (i = 0; i < VELEM(8); i++) 
{Vd.b[i] = ABS(Vu.b[i]);
}
  • 示例结果

  • 相关指令
// type 类型绝对值操作,结果进行饱和操作
HVX_Vector Q6_Vtype0_vabs_Vtype0_sat(HVX_Vector Vu);// type 类型绝对值操作
HVX_Vector Q6_Vtype0_vabs_Vtype0(HVX_Vector Vu);// type 类型绝对值差操作
HVX_Vector Q6_Vtype1_vabsdiff_Vtype2Vtype2(HVX_Vector Vu, HVX_Vector Vv);

type0:b、h、w

type1:ub、uh、uw

type2:ub、h、uh、w

数值扩展

  • 示例指令:HVX_VectorPair Q6_Wuh_vzxt_Vub(HVX_Vector Vu)
  • vzxt 为无符号扩展指令,将原数值类型进行正向调整,扩展后使用 HVX_VectorPair 进行存储,数值按照偶数位和奇数位分别存储至 Vdd.v[0] 和 Vdd.v[1] 中
  • 伪代码:注意结果寄存器存储时按照奇偶交替的顺序存储
// vzxt:u8 -> u16 类型转换
for (i = 0; i < VELEM(16); i++) 
{Vdd.v[0].uh[i] = Vu.uh[i].ub[0];Vdd.v[1].uh[i] = Vu.uh[i].ub[1];
}
  • 指令示意图

  • 相关指令
// u16 类型进行零填充扩展至 u32 类型
HVX_VectorPair Q6_Wuw_vzxt_Vuh(HVX_Vector Vu);// s16 类型进行有符号填充扩展至 s32 类型
HVX_VectorPair Q6_Ww_vsxt_Vh(HVX_Vector Vu);// s8 类型进行有符号填充扩展至 s16 类型
HVX_VectorPair Q6_Wh_vsxt_Vb(HVX_Vector Vu);

4.6 Multiply

向量乘标量运算

  • 示例:HVX_VectorPair Q6_Wh_vmpy_VubRb(HVX_Vector Vu, Word32 Rt)
  • 作用:向量寄存器 Vu 与标量 Rt 的元素进行乘法操作,数值按照偶数位和奇数位分别存储至 Vdd.v[0] 和 Vdd.v[1] 中。
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vdd.v[0].h[i] = (Vu.uh[i].ub[0] * Rt.b[(2*i+0)%4]);Vdd.v[1].h[i] = (Vu.uh[i].ub[1] * Rt.b[(2*i+1)%4]) ;
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// s16 类型向量乘 s16 标量运算,结果左移一位且四舍五入,做饱和操作
HVX_Vector Q6_Vh_vmpy_VhRh_s1_rnd_sat(HVX_Vector Vu, Word32 Rt)// s16 类型向量乘 s16 标量运算,结果左移一位且饱和操作
HVX_Vector Q6_Vh_vmpy_VhRh_s1_sat(HVX_Vector Vu, Word32 Rt)// s16 类型向量乘 s16 标量运算
HVX_VectorPair Q6_Wh_vmpy_VubRb(HVX_Vector Vu, Word32 Rt)// type 类型向量乘加 type 标量运算
HVX_VectorPair Q6_Wtype_vmpyacc_WtypeVtypeRtype(HVX_VectorPair Vxx, HVX_Vector Vu, Word32 Rt)// s16 类型向量乘加 s16 标量运算
HVX_VectorPair Q6_Ww_vmpyacc_WwVhRh_sat(HVX_VectorPair Vxx, HVX_Vector Vu, Word32 Rt)

向量乘加运算(乘标量)

  • 示例:HVX_VectorPair Q6_Wh_vmpa_WubRb(HVX_VectorPair Vuu, Word32 Rt)
  • 作用:向量对寄存器Vuu乘以Rt标量的各元素,数值按照偶数位和奇数位分别存储至 Vdd.v[0] 和 Vdd.v[1] 中。
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vdd.v[0].h[i] = (Vuu.v[0].uh[i].ub[0] * Rt.b[0]) + (Vuu.v[1].uh[i].ub[0] * Rt.b[1]);Vdd.v[1].h[i] = (Vuu.v[0].uh[i].ub[1] * Rt.b[2]) + (Vuu.v[1].uh[i].ub[1] * Rt.b[3]);
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// type 类型的 Vuu 与 type 类型的Rt进行乘加操作,结果为 type 类型
HVX_VectorPair Q6_Wtype0_vmpa_Wtype1Rtype2(HVX_VectorPair Vuu, Word32 Rt);// type 类型的 Vuu 与 type 类型的Rt进行乘加操作,结果与Vxx进行累加,结果为 type 类型
HVX_VectorPair Q6_Wtype0_vmpaacc_Wtype0Wtype1Rtype2(HVX_VectorPair Vxx, HVX_VectorPair Vuu, Word32 Rt);

type0:h、w

type1:b、ub、h、uh

type2:b、ub

乘法 vdmpy操作(乘标量)

  • 示例:HVX_Vector Q6_Vh_vdmpy_VubRb(HVX_Vector Vu, Word32 Rt)
  • 作用:向量寄存器 Vu 与标量 Rt 进行乘法操作,结果相邻对累加操作。
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vd.h[i] =  (Vu.uh[i].ub[0] * Rt.b[(2 * i    ) % 4]);Vd.h[i] += (Vu.uh[i].ub[1] * Rt.b[(2 * i + 1) % 4]) ;
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// type 类型向量与 type 类型标量乘法 2 路归约操作
HVX_Vector Q6_Vtype0_vdmpy_Vtype1Rb(HVX_Vector Vu, Word32 Rt);// type 类型向量与 type 类型标量完成 2 路归约操作
HVX_Vector Q6_Vtype0_vdmpyacc_Vtype0Vtype1Rb(HVX_Vector Vx, HVX_Vector Vu, Word32 Rt);
  1. type0:h、w
  2. type1:ub、h

乘法 vrmpy 操作(乘标量)

  • 示例:HVX_Vector Q6_Vuw_vrmpy_VubRub(HVX_Vector Vu, Word32 Rt)
  • 作用:向量寄存器 Vu 与标量 Rt u进行乘法操作,结果相邻 4 元素累加操作,输出结果为u32类型。
  • 伪代码:
for (i = 0; i < VELEM(32); i++) 
{Vd.uw[i]  = (Vu.uw[i].ub[0] * Rt.ub[0]);Vd.uw[i] += (Vu.uw[i].ub[1] * Rt.ub[1]);Vd.uw[i] += (Vu.uw[i].ub[2] * Rt.ub[2]);Vd.uw[i] += (Vu.uw[i].ub[3] * Rt.ub[3]) ;
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// u8 类型向量与 s8 类型标量完成 4 路归约操作,结果为 s32 类型
HVX_Vector Q6_Vtype0_vrmpy_VubRtype1(HVX_Vector Vu, Word32 Rt);// u8 类型向量与 u8 类型标量完成 4 路归约操作,然后进行 Vx 结果累加,结果为 u32 类型
HVX_Vector Q6_Vtype0_vrmpyacc_Vtype0VubRtype1(HVX_Vector Vx, HVX_Vector Vu, Word32 Rt);
  1. type0:w、uw
  2. type1:b、ub

4.7 Shift

立即数移位

  • 示例:HVX_Vector Q6_Vuw_vlsr_VuwR(HVX_Vector Vu, Word32 Rt)
  • 作用:向量寄存器 Vu 根据立即数 Rt 进行逻辑右移。
  • 伪代码
// vlsr
for (i = 0; i < VELEM(32); i++) 
{Vd.uw[i] = (Vu.uw[i] >> (Rt & (32 - 1)));
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// s16 类型根据 Rt 进行算数右移,结果四舍五入后饱和至 s8 类型,Vu Vv 移位结果奇偶交疊存储之 Vd 中
HVX_Vector Q6_Vb_vasr_VhVhR_rnd_sat(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);// type 类型根据 Rt 进行逻辑右移,结果为 type 类型
HVX_Vector Q6_Vtype_vlsr_VtypeR(HVX_Vector Vu, Word32 Rt);// s16 类型根据 Rt 进行算数右移
HVX_Vector Q6_Vh_vasr_VhR(HVX_Vector Vu, Word32 Rt);// s16 类型算数右移 Rt,结果饱和至 s8 类型,Vu Vv 移位结果奇偶交疊存储之 Vd 中
HVX_Vector Q6_Vb_vasr_VhVhR_sat(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);
  1. type:ub、uh、uw

Narrowing移位

  • 示例指令:

HVX_Vector Q6_Vh_vasr_VwVwR_sat(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt)

  • 作用:算术右移,结果饱和操作,输入位宽是输出的两倍。
  • 伪代码
for (i = 0; i < VELEM(32); i++) 
{shamt = Rt & 0xF; Vd.w[i].h[0]=[sat_16](Vv.w[i] >> shamt); Vd.w[i].h[1]=[sat_16](Vu.w[i] >> shamt); 
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// type类型(round)算术右移,结果饱和操作
HVX_Vector Q6_Vtype0_vasr_Vtype1Vtype1R_rnd_sat(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt)// type类型算术右移,结果饱和操作                                            
HVX_Vector Q6_Vtype0_vasr_Vtype1Vtype1R_sat(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt)
  1. type0:b、ub、h、uh
  2. type1:h、uh、w、uw

4.8 Permute

向量拼接

  • 示例:HVX_Vector Q6_V_valign_VVR(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt)
  • 作用:向量寄存器 Vu 和 Vv 根据 Rt 参数进行移位拼接,向量寄存器内数值按照 u8 类型处理。
  • 伪代码
unsigned shift = Rt & (VWIDTH-1); 
for(i = 0; i < VWIDTH; i++) 
{ Vd.ub[i] = (i + shift>=VWIDTH) ? Vu.ub[i + shift - VWIDTH] \: Vv.ub[i + shift]; 
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// 向量 Vu 与 Vv 根据 (Rt & (VWIDTH-1)) 的起始进行移位拼接操作
HVX_Vector Q6_V_valign_VVR(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);// 向量 Vu 与 Vv 根据 (VWIDTH - (Rt & (VWIDTH-1))) 的起始进行移位拼接操作
HVX_Vector Q6_V_vlalign_VVR(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);// 向量 Vu 根据 Rt 进行向右循环重排
HVX_Vector Q6_V_vror_VR(HVX_Vector Vu, Word32 Rt);

向量旋转

  • 示例:HVX_Vector Q6_V_vror_VR(HVX_Vector Vu, Word32 Rt)
  • 作用:用于1个vector内部的循环移位,Rt最大127
  • 伪代码
for (k = 0; k < VWIDTH; k++) 
{ Vd.ub[k] = Vu.ub[(k + Rt)&(VWIDTH - 1)]; 
}
  • 指令示意图

向量交织操作

  • 示例:HVX_Vector Q6_Vb_vshuffe_VbVb(HVX_Vector Vu, HVX_Vector Vv);
  • 作用:取 Vv 及 Vu 中的偶数位元素,然后进行交织存储到 Vd 寄存器
  • 伪代码
for (i = 0; i < VELEM(16); i++) 
{Vd.uh[i].b[0]=Vv.uh[i].ub[0];Vd.uh[i].b[1]=Vu.uh[i].ub[0] ;
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// 偶数位交织
HVX_Vector Q6_Vb_vshuffe_VbVb(HVX_Vector Vu, HVX_Vector Vv);// 奇数位交织
HVX_Vector Q6_Vb_vshuffo_VbVb(HVX_Vector Vu, HVX_Vector Vv);// 奇偶数位交织
HVX_VectorPair Q6_Wb_vshuffoe_VbVb(HVX_Vector Vu, HVX_Vector Vv);

向量Shuffle - Deal操作

  • 示例
// 将向量内偶数位元素存放至目标寄存器低半位,奇数位元素存放至寄存器高半位
HVX_Vector Q6_Vb_vdeal_Vb(HVX_Vector Vu);// 向量内以低半位和高半位为单位进行奇偶数位解交织操作
HVX_Vector Q6_Vb_vshuff_Vb(HVX_Vector Vu);
  • 作用: vdeal 指令实现将 Vu 向量内的偶数位元素存放到 Vd 寄存器的低半位,奇数位元素存放到 Vd 寄存器的高半位,实现向量中数据奇偶数位的重排(后续简称交织操作)。 vshuff 指令则以向量的低半位和高半位为基本单位,进行奇偶数位的交织重排,与vdeal 互为逆操作(后续简称解交织操作)。
  • 伪代码
//vdeal
for (i = 0; i < VELEM(16); i++) 
{Vd.ub[i ] = Vu.uh[i].ub[0];Vd.ub[i+VBITS/16] = Vu.uh[i].ub[1];
}//vshuff
for (i = 0; i < VELEM(16); i++) 
{Vd.uh[i].b[0]=Vu.ub[i];Vd.uh[i].b[1]=Vu.ub[i+VBITS/16];
}
  • 指令示意图

  • 结果示意图

  • 相关指令
// 两个向量的交织操作,接受一个常量 Rt 参数,Rt 参数影响交织操作的元素大小
HVX_VectorPair Q6_W_vdeal_VVR(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);// 两个向量的解交织操作,接受一个常量 Rt 参数,Rt 参数影响交织操作的元素大小
HVX_VectorPair Q6_W_vshuff_VVR(HVX_Vector Vu, HVX_Vector Vv, Word32 Rt);

4.9 其他

上述章节讲解了基本指令,并没有对复杂指令展开说明,例如查表指令、直方图统计、gather/scatter和vrdelta等复杂指令,后面我们会专门针对以上提到的复杂指令做详细的讲解说明。例如如下所示的vrdelta、vdelta指令的交织网络结构,这种复杂的指令网络设计结构,必须结合设计paper和使用规则才能完全理解。

vrdelta/vdelta指令网络

五、总结

本文主要介绍了 HVX 指令相关的知识,包括 HVX 寄存器相关内容,指令的背景依赖,部分常用 intrinsic HVX 指令。具体指令的详细内容及使用还需阅读 HVX 的指令文档,以及细致的实践操作。

🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏⭐→关注🔍,如果能评论下就太惊喜了!
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!欢迎关注、关注!

相关文章:

性能优化-HVX 指令介绍

「发表于知乎专栏《移动端算法优化》」 本文主要介绍了 HVX 指令相关的知识&#xff0c;包括 HVX 寄存器相关内容&#xff0c;指令的背景依赖&#xff0c;部分常用 intrinsic HVX 指令。具体指令的详细内容及使用还需阅读 HVX 的指令文档&#xff0c;以及细致的实践操作。 &…...

web安全思维导图(白帽子)

web安全思维导图(白帽子) 客户端脚本安全 服务端应用安全 白帽子讲web安全 安全运营体系建设...

美,英,法,德、意大利和西班牙的geojson,以及区域json

美&#xff0c;英&#xff0c;法&#xff0c;德、意大利和西班牙的geojson文件 json地址 https://pan.baidu.com/s/1nio1bV_j-jAEVqgEHXWsNw?pwdqwer#list/path/GEOJSON 感谢大佬提供的 大佬连接 大佬的知乎原地址 国内geojson获取工具地址 http://da![在这里插入图片描述](h…...

JavaEE-微服务-Vuex

Vuex 2.1 什么是Vuex Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 Vuex在组件之间共享数据。 2.2 使用 vue cli 构建项目 2.3 入门案例 2.3.1 定义数据 export default new Vuex.Store({state: { // 状态区域&#xff08;定义变量区域&#xff09;user: ,toke…...

在Windows虚拟机中挂载IP代理的流程

在虚拟机中挂载IP代理的步骤通常依赖于所使用的虚拟机软件&#xff08;如VMware、VirtualBox等&#xff09;以及代理服务器类型&#xff08;HTTP/HTTPS/SOCKS&#xff09;。以下是一个通用流程&#xff1a; 在Windows虚拟机中设置网络代理以使用代理IP&#xff1a; 1. SOCKS或H…...

软考之软件工程

一、瀑布模型 严格区分阶段&#xff0c;每个阶段因果关系紧密相连&#xff0c;只适合需求明确的项目 缺点&#xff1a;软件需求完整性、正确性难确定&#xff1b;严格串行化&#xff0c;很长时间才能看到结果&#xff1b;瀑布模型要求每个阶段一次性完全解决该阶段工作&#xf…...

微信小程序(六)tabBar的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1. 标签栏文字的内容以及默认与选中颜色 2. 标签栏图标的默认样式与选中样式 3. 标签选项路径页面 4.标签栏背景颜色 &#x1f43c;&#xff08;文末补充&#xff09;设置标签栏后为什么navigator标签无法跳转页…...

写Shell以交互方式变更Ubuntu的主机名

以下是一个简单的 Bash 脚本&#xff0c;用于以交互方式更改 Ubuntu 20 系统的主机名&#xff1a; 1#!/bin/bash 2 3# 提示用户输入新的主机名 4read -p "请输入新的系统名称&#xff08;主机名&#xff09;: " new_hostname 5 6# 检查是否输入了新的主机名 7if [ -…...

SpringBoot整合ElasticSearch实现基础的CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述spring-boot-starter-data-elasticsearch项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest&#xff0c;还有一种就是SpringData-ElasticSearch。根据…...

【PyTorch】记一次卷积神经网络优化过程

记一次卷积神经网络优化过程 前言 在深度学习的世界中&#xff0c;图像分类任务是一个经典的问题&#xff0c;它涉及到识别给定图像中的对象类别。CIFAR-10数据集是一个常用的基准数据集&#xff0c;包含了10个类别的60000张32x32彩色图像。在上一篇博客中&#xff0c;我们已…...

C++面试宝典第24题:袋鼠过河

题目 一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子。每隔一米就有一个桩子,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳得更远。每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5,就代表袋鼠下一跳最多能够跳5米;如果为0,就会陷进去无法…...

2401vim,vim标号

标号简介 提供高亮,快速告诉用户有用信息.如,调试器在左侧列中有个表示断点的图标. 另一例可能是表示(PC)程序计数器的箭头.标号功能允许在窗口左侧放置标号或图标,并定义应用行的高亮. 此外,调试器还支持8到10种不同的标号和高亮颜色,见|NetBeans|. 使用标号有两个步骤: 1…...

Web开发中HTTP请求、响应等相关知识

目录 params和data区别? post请求可以使用params吗&#xff1f; put、delete请求应该使用params还是data? get和post的区别? 常用注解使用 params和data区别? 在使用Ajax时&#xff0c;"params" 和 "data" 通常用于不同的上下文。 "params…...

[Android] Android文件系统中存储的内容有哪些?

文章目录 前言root 文件系统/system 分区稳定性:安全性: /system/bin用来提供服务的二进制可执行文件:调试工具:UNIX 命令&#xff1a;调用 Dalvik 的脚本(upall script):/system/bin中封装的app_process脚本 厂商定制的二进制可执行文件: /system/xbin/system/lib[64]/system/…...

透明拼接屏在汽车领域的应用

随着科技的进步&#xff0c;透明拼接屏作为一种新型的显示技术&#xff0c;在汽车领域的应用越来越广泛。尼伽小编将围绕透明拼接屏在汽车本身、4S店、展会、工厂等方面的应用进行深入探讨&#xff0c;并展望未来的设计方向。 一、透明拼接屏在汽车本身的应用 车窗显示&#x…...

“深入理解RabbitMQ交换机的原理与应用“

深入理解RabbitMQ交换机的原理与应用 引言1. RabbitMQ交换机简介介绍1.1 什么是RabbitMQ&#xff1f;1.1.1 消息中间件的作用1.1.2 RabbitMQ的特点和优势 1.2 RabbitMQ的基本概念1.2.1 队列1.2.2 交换机1.2.3 路由键 1.3 交换机的作用和分类1.3.1 直连交换机&#xff08;direct…...

Programming Abstractions in C阅读笔记:p248-p253

《Programming Abstractions in C》学习第69天&#xff0c;p248-p253总结&#xff0c;总计6页。 一、技术总结 “A generalized program for two-player games”如标题所示&#xff0c;该小节强调要学会从一个复杂的程序中抽象出通用的内容——这也是本书的主旨——“Program…...

面试题目,你对前端工程化的了解

前端工程化是通过工具和流程来提高软件开发效率、降低维护成本以及改善项目可维护性的方法。在前端领域&#xff0c;前端工程化通常包括以下方面内容 版本控制 使用 git 来管理代码的版本&#xff0c;追踪变更&#xff0c;协作开发等项目脚手架 使用项目的脚手架进行项目的初始…...

2023年春秋杯网络安全联赛冬季赛 Writeup

文章目录 Webezezez_phppicup Misc谁偷吃了外卖modules明文混淆 Pwnnmanagerbook Reupx2023 CryptoCF is Crypto Faker 挑战题勒索流量Ezdede 可信计算 Web ezezez_php 反序列化打redis主从复制RCE&#xff1a;https://www.cnblogs.com/xiaozi/p/13089906.html <?php c…...

docker安装Rabbitmq教程(详细图文)

目录 1.下载Rabbitmq的镜像 2.创建并运行rabbitmq容器 3.启动web客户端 4.访问rabbitmq的微博客户端 5.遇到的问题 问题描述&#xff1a;在rabbitmq的web客户端发现界面会弹出如下提示框Stats in management UI are disabled on this node 解决方法 &#xff08;1&#…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...