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,所以需要等一段时间才能出来。

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 关于XXE「建议收藏」

    关于XXE「建议收藏」NJUPTCTF2019:做题的时候,抓包看了一下,响应XML格式消息,并没有严格过滤,这道题读文件,<!DOCTYPEfoo[<!ENTITYxxeSYSTEM”php://filter/read=convert.base64-encode/resource=/flag”>]><ticket><username>&amp…

  • CentOS 安装 tomcat 环境安装及配置过程完整版「建议收藏」

    CentOS 安装 tomcat 环境安装及配置过程完整版「建议收藏」CentOS安装tomcat环境安装及配置过程查看安装包信息yuminfotomcat安装yum-yinstalltomcat查看是否安装成功rpm-qtomcat输出:tomcat-7.0.76-16.el7_9.noarch表示安装成功。配置环境变量tomcat默认安装路径/usr/share/tomcat/加入环境变量配置在/etc/profile配置文件中加入Tomcat环境变量:JAVA_HOME=/usr/lib/jvm/ja

  • 代码审计感想_代码审计是什么

    代码审计感想_代码审计是什么代码审计感想代码审计内容代码审计工具漏洞扫描漏洞扫描有以下四种检测技术:代码审计内容代码审计(Codeaudit)是一种以发现程序错误,安全漏洞和违反程序规范为目标的源代码分析。软件代码审计是对编程项目中源代码的全面分析,旨在发现错误,安全漏洞或违反编程约定。它是防御性编程范例的一个组成部分,它试图在软件发布之前减少错误。C和C++源代码是最常见的审计代码,因为许多高级语言(如Pyt…

    2022年10月28日
  • MessageDigest小结「建议收藏」

    MessageDigest小结「建议收藏」转自:http://blog.csdn.net/hudashi/article/details/8394158参考文章:http://blog.sina.com.cn/s/blog_4f36423201000c1e.html一、概述java.security.MessageDigest类用于为应用程序提供信息摘要算法的功能,如MD5或SHA算法。简单点说就是用于生成

  • LTE TDD与LTE FDD技术简介和比较

    LTE TDD与LTE FDD技术简介和比较摘要:UTRA的长期演进(LongTermEvolution,LTE)技术存在LTEFDD和LTETDD两大阵营,本文在比较分析TDD和FDD技术特点的基础上,对LTETDD(即TD-LTE)的特有技术进行了总结,并结合中国移动现有的网络部署和TDD频段资源情况,对LTETDD和LTEFDD的应用前景进行了初步分析。1、引言        随着移动通信技术的蓬勃

  • java list去重_JAVA基础-List去重的6种方式[通俗易懂]

    java list去重_JAVA基础-List去重的6种方式[通俗易懂]简述java开发中经常会遇到List去重这个工作,现在就来整理一下List去重的6种方式。方法代码以及效率测试模拟测试数据相关代码:importjava.util.LinkedList;importjava.util.List;/***@ClassName:ListCleatMain*@Description:模拟数据进行List去重测试*@author:ssqxx*@date:…

发表回复

您的电子邮箱地址不会被公开。

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