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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • eplan激活码分享【最新永久激活】

    (eplan激活码分享)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html70YZDJVTFP-eyJsaWNlbnNlSW…

    2022年3月26日
    3.7K
  • harris角点检测_那就更详细一点吧

    harris角点检测_那就更详细一点吧1.不同类型的角点在现实世界中,角点对应于物体的拐角,道路的十字路口、丁字路口等。从图像分析的角度来定义角点可以有以下两种定义:角点可以是两个边缘的角点; 角点是邻域内具有两个主方向的特征点;前者往往需要对图像边缘进行编码,这在很大程度上依赖于图像的分割与边缘提取,具有相当大的难度和计算量,且一旦待检测目标局部发生变化,很可能导致操作的失败。早期主要有Rosenfeld和Freema…

    2022年10月9日
    2
  • 计算机专业的男生喜欢你,【男生这十个反应说明他喜欢你】_男人的10个表现说明他喜欢上了你…

    计算机专业的男生喜欢你,【男生这十个反应说明他喜欢你】_男人的10个表现说明他喜欢上了你…[onlylady乐活健康情感]男人是一种奇怪动物.和他看不上的女人说话时,他表现得十分自然大方,仿佛兄弟.和他看上的女人说话时,则表现得有点扭捏.1、和女人说话时,不太敢正面女人,而是常常温柔地瞟女人.男人是一种奇怪动物.和他看不上的女人说话时,他表现得十分自然大方,仿佛兄弟.和他看上的女人说话时,则表现得有点扭捏.并非缺乏正面女人的勇气,而是心底不由自主的害羞在作祟.对了,还有一种伴发症…

    2022年7月25日
    5
  • Struts2用AbstractInterceptor取代了AroundInterceptor

    Struts2用AbstractInterceptor取代了AroundInterceptorStruts2中绝大多数预建interceptor都从AbstractInterceptor扩展而来,AbstractInterceptor不在支持before、after两个抽象方法,取而代之的是intercept方法被抽象出来,交由子类去实现。其实大多数interceptor只会去实现before、after中的一个,这样就必须还要在ww中为另一个提供空方法,再由于线程安全问题WW…

    2022年5月14日
    34
  • JAVA反射机制

    JAVA反射机制

    2021年12月8日
    35
  • apk签名失败问题[通俗易懂]

    apk签名失败问题[通俗易懂]在给apk签名的时候会出现如下的问题,如何解决呢?Exceptioninthread”main”java.lang.UnsatisfiedLinkError:noconscrypt_openjdk_jniinjava.library.path atjava.lang.ClassLoader.loadLibrary(ClassLoader.java:1864) atj…

    2022年5月25日
    91

发表回复

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

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