c++ SIMD AVX2比较 例子

c++ SIMD AVX2比较 例子示例代码含义:记目标字符串中有多少个目标字符。linux代码(例子)如下:#include<iostream>#include<x86intrin.h>#include<fstream>#include<chrono>usingnamespacestd;structStringView{constchar*p;constsize_tlen;};StringViewFileSize(const

大家好,又见面了,我是你们的朋友全栈君。

示例代码含义:记目标字符串中有多少个目标字符。
linux代码(例子)如下:

#include <iostream>
#include <x86intrin.h>
#include <fstream>
#include <chrono>

using namespace std;

struct StringView { 
   
    const char* p;
    const size_t len;
};

StringView FileSize(const char* fileName) { 
   
    ifstream ifstr(fileName);
    const auto b = ifstr.tellg();
    ifstr.seekg(0, ios::end);
    const auto e = ifstr.tellg();
    const size_t fileSize = e - b;
    ifstr.seekg(0, ios::beg);
    char *p = new char[fileSize];
    ifstr.read(p, fileSize);
    return { 
   p, fileSize};
}

// Normal function
size_t count_c_normal(const StringView& str, const uint8_t c) { 
   
    uint32_t num = 0;
    for (uint32_t i = 0; i < str.len; ++i) { 
   
        if (c == *(str.p + i)) { 
   
            ++num;
        }
    }
    return num;
}

// SIMD function
size_t count_c_simd(const StringView& str, const uint8_t c) { 
   
    __m128i ch = _mm_set1_epi8(c); // char ch[16] = { c, c, ..., c }
    size_t cnt = 0;
    uint32_t i = 0;
    for (; i < str.len; i+=16) { 
   
        // char t[16] = { (str+i)[0], (str+i)[1], ... }
        __m128i t = _mm_loadu_si128((__m128i *)(str.p + i));
        __m128i res = _mm_cmpeq_epi8(t, ch);

        // res[16] = { 0xFF, 0x00, 0xFF ... }
        unsigned mask = _mm_movemask_epi8(res);

        // bits[16] = 0...1101
        cnt += __builtin_popcount(mask);
    }

    // free cnt .
    for (; i < str.len; ++i) { 
   
        if (c == *(str.p + i))
        { 
   
            ++cnt;
        }
    }
    return cnt;
}

// AVX function
size_t count_c_avx256(const StringView& str, const uint8_t c) { 
   
    __m256i ch = _mm256_set1_epi8(c); // char ch[16] = { c, c, ..., c }
    size_t cnt = 0;
    uint32_t i = 0;
    for (; i < str.len; i+=32) { 
   
        // char t[16] = { (str+i)[0], (str+i)[1], ... }
        __m256i t = _mm256_loadu_si256((__m256i *)(str.p + i));
        __m256i res = _mm256_cmpeq_epi8(t, ch);

        // res[16] = { 0xFF, 0x00, 0xFF ... }
        unsigned mask = _mm256_movemask_epi8(res);

        // bits[16] = 0...1101
        cnt += __builtin_popcount(mask);
    }

    // free cnt .
    for (; i < str.len; ++i) { 
   
        if (c == *(str.p + i))
        { 
   
            ++cnt;
        }
    }
    return cnt;
}

int main() { 
   
    const auto ret = FileSize("./test_file");
    size_t cnt1 = 0, cnt2 = 0, cnt3 = 0;
    const auto t1 = std::chrono::steady_clock::now();
    cnt1 = count_c_normal(ret, uint8_t('1'));
    const auto t2 = std::chrono::steady_clock::now();
    cnt2 = count_c_simd(ret, uint8_t('1'));
    const auto t3 = std::chrono::steady_clock::now();
    cnt3 = count_c_avx256(ret, uint8_t('1'));
    const auto t4 = std::chrono::steady_clock::now();
    std::cout << "cnt1:" << cnt1 << ",cnt2:" << cnt2 << ",cnt3:" << cnt3 << std::endl;
    const auto d1 = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
    const auto d2 = std::chrono::duration_cast<std::chrono::milliseconds>(t3-t2).count();
    const auto d3 = std::chrono::duration_cast<std::chrono::milliseconds>(t4-t3).count();
    std::cout << "time1:" << d1 << ",time2:" << d2 << ",time3:" << d3 << std::endl;
    return 0;
}

生成随机文件代码详见:https://blog.csdn.net/weixin_41644391/article/details/113526563

编译命令:g++ -std=c++11 main.cc -o main -mavx -mavx2 -O2
性能:

普通O2:1890ms,simd:509ms,avx2:253ms

因为编译命令中加了avx2,怀疑simd的代码也被avx2优化了。纯simd结果可见:https://blog.csdn.net/weixin_41644391/article/details/113526563

其他:基于avx512的测试因为不支持gcc4.8.5,所以需要等一段时间才能出来。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144029.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月20日 下午12:20
下一篇 2022年5月20日 下午12:20


相关推荐

  • fd安装教程_ipfs节点搭建

    fd安装教程_ipfs节点搭建自己也是在网上学习的,然后整理了一下,凑合看吧。。。。。。自己也留个底安装好虚拟机后,在/usr/include下进行安装首先查看防火墙状态,service iptablesstatus查看剩余磁盘空间命令df-lh查看端口占用netstat-tlnsudo netstat -tlnp|grep 4200kill-9 安装gcc-c++以上fastdfs源码都是纯C语言编写的,因此需要下…

    2022年10月20日
    4
  • DuplicateHandle的应用

    DuplicateHandle的应用假设一个进程拥有对一个文件映射对象的读写权限 在程序中的某个位置 我们要调用一个函数 并希望它对文件映射对象进行只读访问 为了使应用程序变得更健壮 可以使用 DuplicateHan 为现有的对象创建一个新句柄 并确保这个新句柄有只读权限 然后 把这个只读句柄传给函数 采取这种方式 函数中的代码绝对不会对文件映射对象执行意外的写入操作 代码示例如下 intWINAPI tWinMain

    2026年3月18日
    2
  • 李开复:人工智能时代怎样才不会被取代_李开复关于人工智能的演讲

    李开复:人工智能时代怎样才不会被取代_李开复关于人工智能的演讲提起“人工智能”你会想到什么?  是欧美大片里战无不胜、技能完备的人形机器人? 还是与柯洁等围棋名将上演惊世对决的AlphaGo?事实上人工智能并没有那么遥远 “比爱人还爱你”的手机…… 你每天晨起打开的电子新闻报…… 自动驾驶汽车或翻译软件…… 人工智能早已渗透在我们生活的每一个角落——它,无处不在。

    2022年9月29日
    5
  • ultraedit激活许可证密钥 程序员必备辅助开发编辑器

    ultraedit激活许可证密钥 程序员必备辅助开发编辑器UltraEdit 是一套功能强大的文本编辑器 可以编辑文本 十六进制 ASCII 码 完全可以取代记事本 如果电脑配置足够强大 内建英文单字检查 C 及 VB 指令突显 可同时编辑多个文件 而且即使开启很大的文件速度也不会慢 UltraEdit 的界面如下图所示 UltraEdit 特征轻松打开和编辑大文件 4GB 及以上 文件和数据排序多插入符号编辑和多选集成的 FTP 客户端 支持 FTP SFTP 和 FTPS 列 块 模式编辑集成的 SSH telnet 客户端强大的搜索功能 查找和替换文

    2026年3月26日
    3
  • 易文档-快速编写专业漂亮的API文档,产品文档,使用手册

    易文档https://easydoc.top让您轻松编写和维护高质量的文档。从需求文档、API文档、部署文档到使用手册,多种定制文档编辑器,满足您整个开发周期需求;支持接口在线测试,一键生成mock配置。极致的编写体验,优雅的排版,让文档成为一种乐趣。查看示例文档查看使用技巧…

    2022年4月5日
    345
  • s一般怎么称呼自己的m_男人一般都这样称呼自己的情人?

    s一般怎么称呼自己的m_男人一般都这样称呼自己的情人?阅读本文前,请您先点击上面的“蓝色字体”,再点击“关注”,这样您就可以继续免费收到文章了。每天都会有分享,都是免费订阅,请您放心关注。注:本文转载自网络,不代表本平台立场,仅供读者参考,著作权属归原创者所有。我们分享此文出于传播更多资讯之目的。如有侵权,请在后台留言联系我们进行删除,谢谢!…

    2022年6月23日
    102

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号