作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


接上一篇:【代码分享】使用 avx512 + 查表法,优化凯撒加密

好不容易捣鼓出来了 avx512 指令集的查表法代码,可是部署的时候发现服务器不支持 avx512 指令集。

终于,avx2 版本的查表法终于写出来了。上代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <immintrin.h>
#include <avx2intrin.h>
#include <inttypes.h>
#include <assert.h> typedef uint32_t Table[26][256]; void initTable(Table *table){
for (int i=0; i<26; i++){
for (int j=0; j<256; j++){
if (j>='a' && j<='z'){
(*table)[i][j] = (uint8_t)((j-'a'+i)%26 + 'a');
} else if (j>='A' && j<='Z'){
(*table)[i][j] = (uint8_t)((j-'A'+i)%26 + 'A');
} else {
(*table)[i][j] = j;
}
}
}
} void caesarEncodeAVX2(void* out1, void* in1, uint64_t len, uint64_t rot, void* table1){
uint8_t* out = (uint8_t*)out1;
uint8_t* in = (uint8_t*)in1;
Table* table = (Table*)table1; // 这些代码为了解决 cgo 中函数调用的警告
//
rot = rot % 26;
uint32_t* line = (uint32_t*)((*table)[rot]);
#define batchSize 16
uint64_t tailLen = len & 0x0f;
uint8_t* end = in + len - tailLen;
uint8_t* start = in;
const __m256i index_mask = _mm256_set_epi32(
7, 6, 3, 2,
5,4, 1, 0
);
for (; start<end; out += batchSize, start += batchSize){
__m128i src = _mm_loadu_si128(start); // 加载 16 个字符,但只处理前面 8 个字符
__m256i srcI32 = _mm256_cvtepu8_epi32(src); // 前 8 个字节,转换为 32 字节
__m256i foundHead = _mm256_i32gather_epi32(line, srcI32, 4); // 8 字节查表
// 处理后面 8 字节
src = _mm_srli_si128(src, 8); // 移动 8 字节,也就是 64 位
srcI32 = _mm256_cvtepu8_epi32(src); // 后 8 个字节,转换为 32 字节
__m256i foundTail = _mm256_i32gather_epi32(line, srcI32, 4); // 8 字节查表
// 进行压缩
__m256i found16 = _mm256_packus_epi32(foundHead, foundTail); // 16 个 16 位的值
/*
_mm256_packus_epi32 这个指令非常的恶心:aaaa bbbb 合并成了 aa bb aa bb
于是还要用下面这个指令把顺序换过来
*/
found16 = _mm256_permutevar8x32_epi32 (found16, index_mask); // 换过来了,正常了
found16 = _mm256_packus_epi16(found16, _mm256_setzero_si256());
found16 = _mm256_permutevar8x32_epi32 (found16, index_mask); // 换过来了,正常了
//存储
__m128i result = _mm256_castsi256_si128(found16);
_mm_storeu_si128 (out, result);
}
//
end = in + len;
for (; start<end; start++, out++){
*out = (uint8_t)line[*start];
}
} // 逐字节处理的版本
void caesarEncode(uint8_t* out, uint8_t* in, int len, int rot, Table* t){
rot = rot % 26;
uint8_t* end = in + len;
uint32_t* line = (uint32_t*)((*t)[rot]);
for (;in<end; in++, out++){
*out = (uint8_t)line[*in];
}
}

编译:

gcc -o caesar caesar.c -g -w -mavx -mavx2 -O3

测试了一下各个版本的性能表现:

逐字节处理版本:total:201429 us, avg: 100.715 ns/op
AVX2 版本: total:51059 us, avg: 25.529 ns/op
AVX512 版本: total:49756 us, avg: 24.878 ns/op

avx512 版本只比 avx2 快了一点点,鸡肋!

【代码分享】使用 avx2 + 查表法,优化凯撒加密的更多相关文章

  1. 经典算法,yuv与rgb互转,查表法,让你的软件飞起来

    代码的运算速度取决于以下几个方面 1. 算法本身的复杂度,比如MPEG比JPEG复杂,JPEG比BMP图片的编码复杂. 2. CPU自身的速度和设计架构 3. CPU的总线带宽 4. 您自己代码的写法 ...

  2. YUV420查表法高效、无失真的转换为RGB32格式

    YUV格式有两大类:planar和packed.planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V,这里所讲述的就是这中存储格式的:packed的YUV ...

  3. C#,Java,C -循环冗余检验:CRC-16-CCITT查表法

    C#代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ...

  4. 查表法计算CRC16校验值

    CRC16是单片机程序中常用的一种校验算法.依据所采用多项式的不同,得到的结果也不相同.常用的多项式有CRC-16/IBM和CRC-16/CCITT等.本文代码采用的多项式为CRC-16/IBM: X ...

  5. 【C语言学习笔记】空间换时间,查表法的经典例子!知识就是这么学到的~

    我们怎么衡量一个函数/代码块/算法的优劣呢?这需要从多个角度看待.本篇笔记我们先不考虑代码可读性.规范性.可移植性那些角度. 在我们嵌入式中,我们需要根据实际资源的情况来设计我们的代码.比如当我们能用 ...

  6. C语言:十进制进制转换为其他进制(思想:查表法)

    // //  main.c //  Hex conversion // //  Created by ma c on 15/7/22. //  Copyright (c) 2015年 bjsxt. A ...

  7. 最简单的CRC32源码-查表法

    这个算法是在逐BYTE法的基础上进行修改的,在上一篇文章里我们说过,如果不查表的话,逐BYTE法和逐BIT法没什么区别,现在我们就把这个算法写出来,注意在调用CRC校验函数前需要先调用表生成函数: u ...

  8. 嵌入式C语言查表法的项目应用

    嵌入式C实战项目开发技巧:如果对一个有规律的数组表进行位移操作 就像下面的这个表 之前写过上面这个标题的一篇文章,讲的是以位移的方式去遍历表中的数据,效率非常高,但是,如果要实现一个乱序的流水灯或者跑 ...

  9. 嵌入式C语言查表法

    转自:https://blog.csdn.net/morixinguan/article/details/51799668    作者:Engineer-Bruce_Yang 就像下面的这个表 之前写 ...

  10. RGB2GRAY 各种算法速度比较,整形乘法比查表法快!

    1.  查表法,外循环用 这种格式 :  //for(int j = 0; j != h; ++j)// for(int i = 0; i!=w;++i)//. for(int j = 0; j != ...

随机推荐

  1. Linux 查找进程所在目录

    查找进程所在目录位置 # 打出进程ID [root@iZuf64tp28136djioi3ki8Z /]# ps -ef|grep redis root 3451 1 0 Jun10 ? 07:02: ...

  2. .Net Core 中 MemoryCache 使用

    1.Demo,实际项目中不这么使用 class Program { static void Main(string[] args) { //缓存的配置 MemoryCacheOptions cache ...

  3. Nacos 1.2.1 集群搭建(二)MySQL、cluster 配置

    三台虚机的IP地址被DHCP重分了一下1.MySQL 配置 先建一个 nacos_config 数据库 将SQL执行(方法很多,选自己喜欢的就行) 2.修改 application.propertie ...

  4. C#写日志工具类(新版)

    源码:https://gitee.com/s0611163/LogUtil 昨天打算把我以前写的一个C#写日志工具类放到GitHub上,却发现了一个BUG,当然,已经修复了. 然后写Demo对比了NL ...

  5. Windows10/11 wsl2 安装 ArchLinux 子系统

    这篇文章针对的是在win11系统的wsl2下安装ArchLinux系统,网上很多中文教程都是使用LxRunOffline去做的,但是实际上该方法已经过时了,目前有更加先进的ArchWSL方式. 如果用 ...

  6. #1241: Oil Deposits(八向搜索 + 并查集)

    Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...

  7. POJ:Dungeon Master(BFS模板题)

    原题链接 思路: 正常的思路,只不过是将二维BFS换成三维的,也算是个模板题吧(PS:DFS超容易超时) #include<iostream> #include<queue> ...

  8. HDU - 1560:DNA sequence ( 迭代加深搜索基础题 )

    Problem Description The twenty-first century is a biology-technology developing century. We know tha ...

  9. UVA - 1594 :Ducci Sequence (set应用)

    给定n元组(a1,a2,...,an),ai均为整数,得到下一个序列为(|a1-a2|,|a2-a3|,...,|an-a1|),如此循环下去,必定会出现全零序列或重复序列. 现要求判断给定序列是全零 ...

  10. AtCoder Beginner Contest 182 Person Editorial

    Problem A - twiblr 直接输出 \(2A + 100 - B\) Problem B - Almost GCD 这里暴力枚举即可 int main() { ios_base::sync ...