Neon intrinsics

2023-11-12

1.介绍

            在上篇中,介绍了ARM的Neon,本篇主要介绍Neon intrinsics的函数用法,也就是assembly之前的用法。NEON指令是从Armv7架构开始引入的SIMD指令,其共有16个128位寄存器。发展到最新的Arm64架构,其寄存器数量增加到32个,但是其长度仍然为最大128位,因此操作上并没有发生显著的变化。对于这样的寄存器,因为可以同时存储并处理多组数据,称之为向量寄存器。Intrinsics是使用C语言的方式对NEON寄存器进行操作,因为相比于传统的使用纯汇编语言,具有可读性强,开发速度快等优势。如果需要在代码中调用NEON Intrinsics函数,需要加入头文件"arm_neon.h"。关于neon的所有函数,可以参考官网的:ARM NEON intrinsics reference 这里将网上的Neon intrinsics的函数做个总结:

1.1 指令的分类

  • 正常指令:生成大小相同且类型通常与操作数向量相同的结果向量
  • 长指令:对双字节向量操作数执行运算,生成四字向量的结果,所生成的元素一般是操作数元素宽度的两倍
  • 宽指令:一个双字向量操作数和一个四字向量操作数执行运算,生成四字向量结果,所生成的元素和第一个操作数的元素是第二个操作数元素宽度的两倍
  • 窄指令:四字向量操作数执行运算,并生成双字向量结果,所生成的元素一般是操作数元素宽度的一半
  • 饱和指令:当超过数据类型指定的范围则自动限制在该范围内

示例1:

  • int16x8_t vqaddq_s16 (int16x8_t, int16x8_t)
  • int16x4_t vqadd_s16 (int16x4_t, int16x4_t)
  1. 第一个字母'v'指明是vector向量指令,也就是NEON指令;
  2. 第二个字母'q'指明是饱和指令,即后续的加法结果会自动饱和;
  3. 第三个字段'add'指明是加法指令;
  4. 第四个字段'q'指明操作寄存器宽度,为'q'时操作QWORD, 为128位;未指明时操作寄存器为DWORD,为64位;
  5. 第五个字段's16'指明操作的基本单元为有符号16位整数,其最大表示范围为-32768 ~ 32767;
  6. 形参和返回值类型约定与C语言一致。

     其它可能用到的助记符包括:

  • l 长指令,数据扩展
  • w 宽指令,数据对齐
  • n 窄指令, 数据压缩

     关于所有函数的分类,请参考博客:https://blog.csdn.net/hemmingway/article/details/44828303

1.2 数据类型

   NEON Intrinsics内置的整数数据类型主要包括以下几种:

  • (u)int8x8_t;
  • (u)int8x16_t;
  • (u)int16x4_t;
  • (u)int16x8_t;
  • (u)int32x2_t;
  • (u)int32x4_t;
  • (u)int64x1_t;

       其中,第一个数字代表的是数据类型宽度为8/16/32/64位,第二个数字代表的是一个寄存器中该类型数据的数量。如int16x8_t代表16位有符号数,寄存器中共有8个数据。

2.Syntax

2.1 Arithmetic

  • add: vaddq_f32 or vaddq_f64 (  sum = v1 + v2 )
float32x4_t v1 = { 1.0, 2.0, 3.0, 4.0 }, v2 = { 1.0, 1.0, 1.0, 1.0 };
float32x4_t sum = vaddq_f32(v1, v2);
// => sum = { 2.0, 3.0, 4.0, 5.0 }
  • multiply: vmulq_f32 or vmulq_f64 ( sum = v1 + v2 )
float32x4_t v1 = { 1.0, 2.0, 3.0, 4.0 }, v2 = { 1.0, 1.0, 1.0, 1.0 };
float32x4_t prod = vmulq_f32(v1, v2);
// => prod = { 1.0, 2.0, 3.0, 4.0 }
  • multiply and accumulate: vmlaq_f32 (  sum = v3 + v1 * v2 )
float32x4_t v1 = { 1.0, 2.0, 3.0, 4.0 }, v2 = { 2.0, 2.0, 2.0, 2.0 }, v3 = { 3.0, 3.0, 3.0, 3.0 };
float32x4_t acc = vmlaq_f32(v3, v1, v2);  // acc = v3 + v1 * v2
// => acc = { 5.0, 7.0, 9.0, 11.0 }
  • multiply by a scalar: vmulq_n_f32 or vmulq_n_f64 ( prod = V1 * a)
float32x4_t v = { 1.0, 2.0, 3.0, 4.0 };
float32_t s = 3.0;
float32x4_t prod = vmulq_n_f32(v, s);
// => prod = { 3.0, 6.0, 9.0, 12.0 }
  • multiply by a scalar and accumulate: vmlaq_n_f32 or vmlaq_n_f64 ( acc = v1*v2 + s)
float32x4_t v1 = { 1.0, 2.0, 3.0, 4.0 }, v2 = { 1.0, 1.0, 1.0, 1.0 };
float32_t s = 3.0;
float32x4_t acc = vmlaq_n_f32(v1, v2, s);
// => acc = { 4.0, 5.0, 6.0, 7.0 }
  • invert (needed for division): vrecpeq_f32 or vrecpeq_f64 ( reciprocal =  1 / v)
float32x4_t v = { 1.0, 2.0, 3.0, 4.0 };
float32x4_t reciprocal = vrecpeq_f32(v);
// => reciprocal = { 0.998046875, 0.499023438, 0.333007813, 0.249511719 }
float32x4_t v = { 1.0, 2.0, 3.0, 4.0 };
float32x4_t reciprocal = vrecpeq_f32(v);
float32x4_t inverse = vmulq_f32(vrecpsq_f32(v, reciprocal), reciprocal);
// => inverse = { 0.999996185, 0.499998093, 0.333333015, 0.249999046 }

2.2 Load

  • load vector: vld1q_f32 or vld1q_f64
float values[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
float32x4_t v = vld1q_f32(values);
// => v = { 1.0, 2.0, 3.0, 4.0 }
  • load same value for all lanes: vld1q_dup_f32 or vld1q_dup_f64
float val = 3.0;
float32x4_t v = vld1q_dup_f32(&val);
// => v = { 3.0, 3.0, 3.0, 3.0 }
  • set all lanes to a hardcoded value: vmovq_n_f16 or vmovq_n_f32 or vmovq_n_f64
float32x4_t v = vmovq_n_f32(1.5);
// => v = { 1.5, 1.5, 1.5, 1.5 }

2.3 Store

  • store vector: vst1q_f32 or vst1q_f64
float32x4_t v = { 1.0, 2.0, 3.0, 4.0 };
float values[5] = new float[5];
vst1q_f32(values, v);
// => values = { 1.0, 2.0, 3.0, 4.0, #undef }
  • store lane of array of vectors: vst4q_lane_f16 or vst4q_lane_f32 or vst4q_lane_f64 (change to vst1... / vst2... / vst3...for other array lengths)
float32x4_t v0 = { 1.0, 2.0, 3.0, 4.0 }, v1 = { 5.0, 6.0, 7.0, 8.0 }, v2 = { 9.0, 10.0, 11.0, 12.0 }, v3 = { 13.0, 14.0, 15.0, 16.0 };
float32x4x4_t u = { v0, v1, v2, v3 };
float buff[4];
vst4q_lane_f32(buff, u, 0);
// => buff = { 1.0, 5.0, 9.0, 13.0 }

2.4 Arrays

  • access to values: val[n]
float32x4_t v0 = { 1.0, 2.0, 3.0, 4.0 }, v1 = { 5.0, 6.0, 7.0, 8.0 }, v2 = { 9.0, 10.0, 11.0, 12.0 }, v3 = { 13.0, 14.0, 15.0, 16.0 };
float32x4x4_t ary = { v0, v1, v2, v3 };
float32x4_t v = ary.val[2];
// => v = { 9.0, 10.0, 11.0, 12.0 }

2.5 Max and min

  • max of two vectors, element by element:
float32x4_t v0 = { 5.0, 2.0, 3.0, 4.0 }, v1 = { 1.0, 6.0, 7.0, 8.0 };
float32x4_t v2 = vmaxq_f32(v0, v1);
// => v1 = { 5.0, 6.0, 7.0, 8.0 }
  • max of vector elements, using folding maximum:
float32x4_t v0 = { 1.0, 2.0, 3.0, 4.0 };
float32x2_t maxOfHalfs = vpmax_f32(vget_low_f32(v0), vget_high_f32(v0));
float32x2_t maxOfMaxOfHalfs = vpmax_f32(maxOfHalfs, maxOfHalfs);
float maxValue = vget_lane_f32(maxOfMaxOfHalfs, 0);
// => maxValue = 4.0
  • min of two vectors, element by element:
float32x4_t v0 = { 5.0, 2.0, 3.0, 4.0 }, v1 = { 1.0, 6.0, 7.0, 8.0 };
float32x4_t v2 = vminq_f32(v0, v1);
// => v1 = { 1.0, 2.0, 3.0, 4.0 }
  • min of vector elements, using folding minimum:
float32x4_t v0 = { 1.0, 2.0, 3.0, 4.0 };
float32x2_t minOfHalfs = vpmin_f32(vget_low_f32(v0), vget_high_f32(v0));
float32x2_t minOfMinOfHalfs = vpmin_f32(minOfHalfs, minOfHalfs);
float minValue = vget_lane_f32(minOfMinOfHalfs, 0);
// => minValue = 1.0

2.5 conditionals

  • ternary operator: use vector comparison (for example vcltq_f32 for less than comparison)
float32x4_t v1 = { 1.0, 0.0, 1.0, 0.0 }, v2 = { 0.0, 1.0, 1.0, 0.0 };
float32x4_t mask = vcltq_f32(v1, v2);  // v1 < v2
float32x4_t ones = vmovq_n_f32(1.0), twos = vmovq_n_f32(2.0);
float32x4_t v3 = vbslq_f32(mask, ones, twos);  // will select first if mask 0, second if mask 1
// => v3 = { 2.0, 1.0, 2.0, 2.0 }

3. Sample for openCV, c pointer, Neon

       前提:图片大小 640 x 480,动作:每三行的各列相加等于当前列。例如:x(i,j) = x(i, j) +x(i - 1, j) + x(i-2, j).

  • openCV的做法:其中,cv::Mat gray, src .src是来自每一帧图片(640x480 deep = 8bits)
GETTIME(&lTimeStart);
for (int col = 0; col < gray.cols; col++)
{
		gray.at<uchar>(0, col) = src.at<uchar>(0, col);
}
for (int col = 0; col < gray.cols; col++)
{
		gray.at<uchar>(1, col) = gray.at<uchar>(0, col) + src.at<uchar>(1, col);
}
for (int col = 0; col < gray.cols; col++)
{
		gray.at<uchar>(2, col) = gray.at<uchar>(1, col) + src.at<uchar>(2, col);
}
for (int row = 3; row < gray.rows; row++)
{
		for (int col = 0; col < gray.cols; col++)
		{
		   gray.at<uchar>(row, col) = gray.at<uchar>(row - 1, col) + src.at<uchar>(row, col) - src.at<uchar>(row - 3, col);
		}
}
GETTIME(&lTimeEnd);
printf("time %ldus\n",lTimeEnd - lTimeStart);
在arm-A57平台,openCV消耗的时间均值:time = 19175us
  • c-pointer的做法:
GETTIME(&lTimeStart);
unsigned char *ptr = src.ptr(0);
unsigned char *grayPtr = gray.ptr(0);
for(int col = 0; col < gray.cols; col++)
{
      grayPtr[col] = ptr[col];
}
unsigned char *ptr1 = src.ptr(1);
unsigned char *grayPtr1 = gray.ptr(1);
for(int col =0; col < gray.cols; col++)
{
       grayPtr1[col] = ptr[col] + ptr1[col];//34us
}
unsigned char *ptr2 = NULL;
unsigned char *grayPtr2 = NULL;
for(int row = 2; row < gray.rows; row++)
{
       ptr = src.ptr(row - 2);
       ptr1 = src.ptr(row -1);
       ptr2 = src.ptr(row);
       grayPtr2 = gray.ptr(row);

       for(int col = 0; col <gray.cols; col+=16){
          grayPtr2[col] = ptr[col] + ptr1[col] + ptr2[col];//11252us
        }
}
GETTIME(&lTimeEnd);
printf("time %ldus\n",lTimeEnd - lTimeStart);
在arm-A57平台,C-pointer消耗的时间均值:time = 11252us
  • Neon 方式:
GETTIME(&lTimeStart);
unsigned char *ptr = src.ptr(0);
unsigned char *grayPtr = gray.ptr(0);
for(int col = 0; col < gray.cols; col++)
{
     grayPtr[col] = ptr[col];
}
unsigned char *ptr1 = src.ptr(1);
unsigned char *grayPtr1 = gray.ptr(1);
for(int col =0; col < gray.cols; col++)
{
     grayPtr1[col] = ptr[col] + ptr1[col];//34us
}
unsigned char *ptr2 = NULL;
unsigned char *grayPtr2 = NULL;
for(int row = 2; row < gray.rows; row++)
{
     ptr = src.ptr(row - 2);
     ptr1 = src.ptr(row -1);
     ptr2 = src.ptr(row);
     grayPtr2 = gray.ptr(row);

for(int col = 0; col <gray.cols; col+=16){
                
    uint8x16_t in1,in2,in3,out;
    in1 = vld1q_u8(ptr+col);
    in2 = vld1q_u8(ptr1+col);
    in3 = vld1q_u8(ptr2+col);
    out = vaddq_u8(in1,in2);
    out = vaddq_u8(in3,out);
    vst1q_u8(grayPtr2+col,out);

   }
}
GETTIME(&lTimeEnd);
printf("time %ldus\n",lTimeEnd - lTimeStart);
在arm-A57平台,Neon intrinscis消耗的时间均值:time = 1907us

       综上,可以看到,neon相对opencv方式的性能提升快10倍。(注意,这里的加法都有溢出的情况,由于本算法特殊,所以没有做溢出处理)

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Neon intrinsics 的相关文章

  • Android NDK添加NEON以及cpufeatures支持

    本人使用Android studio3 0进行NDK开发 由于Android develop官网文档是针对2 2版本以下 这里为2 2以上版本的cmakelist配置做以下纪录 一 添加NEON支持 在build gradle app 中添
  • neon vuzp 的 sse/avx 等效项

    Intel 的向量扩展 SSE AVX 等为每个元素大小提供两个解包操作 例如SSE 内在函数是 mm unpacklo and mm unpackhi 对于向量中的 4 个元素 它执行以下操作 inputs A0 A1 A2 A3 B0
  • numpy 是否自动针对树莓派进行优化

    Raspberry Pi armv7l 架构 具有 neon vfpv4 支持 可用于优化 标准版numpy在安装命令时是否包含这些优化pip3 install numpy or apt get python3 numpy 我不是在谈论 b
  • ARM NEON:比较 128 位值

    我感兴趣的是找到比较 Cortex A9 内核 允许使用 VFP 指令 上 NEON 寄存器 例如 Q0 和 Q3 中存储的值的最快方法 最低周期数 到目前为止我有以下内容 1 使用VFP浮点比较 vcmp f64 d0 d6 vmrs A
  • 使用 ARM NEON 汇编对 atan2 进行 SIMD 向量化

    我想使用 neon 指令 SIMD 和臂组件来计算 4 个点的大小和角度 大多数语言都有一个内置库 在我的例子中是 C 它计算角度 atan2 但仅针对一对浮点变量 x 和 y 我想利用处理 q 寄存器的 SIMD 指令来计算 4 个值向量
  • 与 NEON 内在函数的数据类型兼容性

    我正在使用来自 C 代码的 NEON 内在函数进行 ARM 优化 我理解并掌握了大部分打字问题 但我陷入了这一问题 指令vzip u8返回一个uint8x8x2 t值 实际上是两个数组uint8x8 t 我想将返回值分配给一个普通的uint
  • 有没有办法将寄存器文件视为 ARMv8 中的数组(标量或 Neon)?

    假设我有一个短数组v说 8int64 t 我有一个算法需要访问该数组的不同元素 这些元素不是编译时常量 例如就像是v i j 2 其中i and j是不受任何类型的常量传播影响的变量 通常 我会保留内存中的数组 计算数组索引 从内存中的该位
  • 调试 Arm neon 代码中的数据/neon 性能危害

    最初 当我尝试时出现了问题优化算法根据 Profiler 的数据 Neon Arm 和其中的一小部分占据了 80 我尝试测试看看可以采取哪些措施来改进它 为此我创建了指向优化函数的不同版本的函数指针数组 然后在循环中运行它们以在探查器中查看
  • NEON 简单向量赋值内在?

    Having r1 r3 and r4类型的uint32x4 t加载到 NEON 寄存器中我有以下代码 r3 veorq u32 r0 r3 r4 r1 r1 vandq u32 r1 r3 r4 veorq u32 r4 r2 r1 ve
  • 海湾合作委员会;臂64; aarch64;无法识别的命令行选项“-mfpu=neon”

    我得到编译错误 无法识别的命令行选项 mfpu neon 当尝试使用 mfpu neon 标志进行编译时 实际上 我尝试的任何 mfpu 选项都失败了 然而在文档中提到了这个标志 所以它应该是有效的 这把钥匙有什么问题吗 我如何告诉编译器使
  • Cortex A9 NEON 与 VFP 使用混淆

    我正在尝试为 Cortex A9 ARM 处理器 更具体地说是 OMAP4 构建一个库 对于在浮点运算和 SIMD 上下文中使用 NEON 与 VFP 的情况 我有点困惑 需要注意的是 我知道两个硬件协处理器单元之间的区别 也概述了这里就这
  • 如何在 ARM Cortex-a8 中使用乘法和累加内在函数?

    如何使用GCC提供的乘累加内在函数 float32x4 t vmlaq f32 float32x4 t float32x4 t float32x4 t 谁能解释一下我必须传递给这个函数的三个参数 我的意思是源寄存器和目标寄存器以及函数返回什
  • Arm Neon Intrinsics 与手动组装

    https web archive org web 20170227190422 http hilbert space de p 22 https web archive org web 20170227190422 http hilber
  • 用于通用 SIMD(SSE、AVX、NEON)测试零匹配的高效 C 向量。 (求FP最大绝对值和指数)

    我想看看是否可以编写一些可以高效编译的通用 SIMD 代码 主要用于 SSE AVX 和 NEON 该问题的简化版本是 找到浮点数数组的最大绝对值并返回该值和索引 导致问题的是最后一部分 即最大值的索引 似乎没有一种很好的方法来编写具有分支
  • NEON 向量化无符号字节的乘积之和: (a[i]-int1) * (b[i]-int2)

    我需要改进循环 因为我的应用程序调用了数千次 我想我需要用 Neon 来做这件事 但我不知道从哪里开始 假设 先决条件 w始终为 320 16 32 的倍数 pa and pb16 字节对齐 ma and mb是积极的 int whileI
  • Android 版 ffmpeg:neon 构建具有文本重定位

    您好 我成功构建了 appunite ffmpeg 库 包括 arm v7a neon 支持 但是当我尝试在 Marshmallow 设备上运行这些库时 出现此错误 01 08 23 42 02 350 E AndroidRuntime 1
  • 如何检查 vDSP 函数在 neon 上运行的是标量还是 SIMD

    我目前正在使用 vDSP 框架中的一些函数 尤其是 vDSP conv 我想知道是否有任何方法可以检查该函数是否调用标量模式或在 neon 处理器上处理 SIMD The 文档 https developer apple com libra
  • 使用 NEON 对 ARM 汇编中的四字向量中的所有元素求和

    我对组装相当陌生 尽管手臂信息中心通常很有帮助 但有时这些说明可能会让新手感到有点困惑 基本上我需要做的就是对四字寄存器中的 4 个浮点值求和 并将结果存储在单个精度寄存器中 我认为 VPADD 指令可以满足我的需要 但我不太确定 你可以尝
  • ARM NEON:如何实现 256 字节查找表

    我正在使用内联汇编将我编写的一些代码移植到 NEON 我需要的一件事是将范围 0 128 的字节值转换为表中采用完整范围 0 255 的其他字节值 该表很短 但其背后的数学并不容易 因此我认为不值得每次 即时 计算它 所以我想尝试查找表 我
  • 如何使用 Neon SIMD 将无符号字符转换为有符号整数

    如何转换变量的数据类型uint8 t to int32 t使用霓虹灯 我找不到执行此操作的任何内在因素 假设您想要将 16 x 8 位整数的向量转换为 4 个 4 x 32 位整数的向量 您可以通过首先解压缩为 16 位 然后再次解压缩为

随机推荐

  • 长大后会发现,学习其实就是因为自己想知道

    简单总结 01 习惯 看不懂的名词 第一时间google 02 注释 注释一些思路 把注释嵌入到工作和生活 像现在的记录 03 随记 关注身边的细节 及时回应别人 明白自己想说什么 选择好时机去说 04 务实方法 ETC Easier to
  • IDEA 设置为护眼的豆沙绿

    代码区域设置成护眼色 先打开 IDEA 的设置界面 然后按照下图按顺序店了设置就可以了 这个时候 可以看到 只有代码区域别成了护眼色 其他地方还是白的刺眼 我们来一个一个的解决掉 左侧的文件页修改为护眼色 还是先打开设置 然后如下图所示 先
  • 非对称加密工作原理

    非对称加密 非对称加密使用两个密钥 一个是public key 一个是private key 通过某个算法 使得数据的加密和解密使用不同的密钥 因为用的是不同的密钥 所以称为非对称加密 非对称加密最著名的是RSA算法 这是以其发明者Rive
  • java static变量_什么是静态(static)?什么是静态方法,静态变量,静态块和静态类...

    static是Java中的一个关键字 我们不能声明普通外层类或者包为静态的 static用于下面四种情况 静态变量 我们可以将类级别的变量声明为static 静态变量是属于类的 而不是属于类创建的对象或实例 因为静态变量被类的所有实例共用
  • Excel解决CSV文件中的乱码

    背景 对于CSV文件中的乱码问题 大概率是编码的问题 可以基于Excel进行编码转换 或将文本进行编码转化 解决办法 打开Excel应用 点击文件 新建文件 点击文件 选择导入 导入具体的CSV文件 选择CSV文件 点击完成即可 然后就可以
  • 麻雀算法(SSA)优化长短期记忆神经网络的数据分类预测,SSA-LSTM分类预测,多输入单输出模型

    清空环境变量 warning off 关闭报警信息 close all 关闭开启的图窗 clear 清空变量 clc 清空命令行 读取数据 res xlsread 数据集 xlsx num res size res 1 样本数 每一行 是一
  • vue + css气泡图动态气泡图

    div ul class bubbleUl li class bubbleLi div class textBubble span item value span div div class topDiv div style width 1
  • 从一个类调用另一个类的方法或属性

    package 练习 class yu String m 人工小智能 public void shout1 System out println 我是 m 今年18岁 同类中直接调用了m public void shout2 yu p ne
  • grep指令详解

    shell grep指令详解 grep 参数 e 使用PATTERN作为模式 这可以用于指定多个搜索模式 或保护以连字符 开头的图案 指定字符串做为查找文件内容的样式 f 指定规则文件 其内容含有一个或多个规则样式 让grep查找符合规则条
  • 【SQL注入】堆叠注入

    目录 一 简介 概述 原理 优势 前提 防护 二 分析堆叠注入 使用MYSQL 第一步 使用堆叠查询构造多条语句 第二步 查看语句是否成功执行 第三步 删除test 再查询 第四步 执行其它查询语句 一 简介 概述 顾名思义 就是多条语句堆
  • 【电脑使用】chm文件打开显示确保Web地址 //ieframe.dll/dnserrordiagoff.htm#正确

    问题描述 最近找到一个之前的一个chm文件 打开的时候内容是空白的 同时报错 确保Web地址 ieframe dll dnserrordiagoff htm 正确 如下图所示 参考链接 解决方案 根据文章中提示的方法 找到了原因所在 chm
  • 详解微信小程序支付流程

    小程序微信支付图 微信小程序的商户系统一般是以接口的形式开发的 小程序通过调用与后端约定好的接口进行参数的传递以及数据的接收 在小程序支付这块 还需要跟微信服务器进行交互 过程大致是这样的 一 小程序调用登录接口获取code 传递给商户服务
  • linux传输文件指令

    使用scp传输 从本地传到服务器 scp P 目的端口 本地路径 目的用户名 目的IP 目的路径 r参数可用来传文件夹 scp r P 使用sftp传输 sftp oPort 目的端口号 目的用户名 目的IP get下载 put上传
  • 这5个开源和免费静态代码分析工具,你一个都没有用过吗?不会吧

    如果您是软件开发人员或代码安全分析师 则通常需要分析源代码以检测安全漏洞并维护安全的质量代码 但是您的代码中可能存在许多难以手动发现的问题 毕竟 我们仍然是人类 因此即使是最高级的安全分析师也都会错过一些安全漏洞 我们提供了源代码分析工具功
  • MySql中4种批量更新的方法

    MySql中4种批量更新的方法 mysql 批量更新共有以下四种办法1 replace into 批量更新 replace into test tbl id dr values 1 2 2 3 x y 例子 replace into boo
  • 人生顿悟之宽以待人,严以律己

    台风已经过去了 天气也渐渐地晴朗了 但是不知道为什么自己的心情却越发觉得沉重起来 总觉得生活中少了点什么 是没有了以往的激情 还是多了几分压力 看了近1个月的房子 两个人的所有积蓄加上两家人的积蓄 勉强可以付得起首付 接下去就是了无止境的房
  • 开启MySQL主从半同步复制

    记录配置mysql主从半同步复制的过程 加载lib 所有主从节点都要配置 主库 install plugin rpl semi sync master soname semisync master so 从库 install plugin
  • Android Studio从一个activity到另一个activity

    Android Studio从一个activity跳转到另一个activity 简单的跳转 创建两个activity 创建跳转按钮 在第一个activity的onCreate中添加按钮监听事件 编写内部类 button setOnClick
  • [网盘工具/百度网盘]秒传链接的使用 -2022版油猴网页脚本

    注 此项技术仅针对百度网盘有效 软件要求 Chrome或Firefox等支持tampermonkey Violentmonkey的浏览器 1 什么是秒传链接 度盘秒传链接 标准提取码 由128位 32个16进制数 128位 32个16进制数
  • Neon intrinsics

    1 介绍 在上篇中 介绍了ARM的Neon 本篇主要介绍Neon intrinsics的函数用法 也就是assembly之前的用法 NEON指令是从Armv7架构开始引入的SIMD指令 其共有16个128位寄存器 发展到最新的Arm64架构