SIMD 编程的优势与SIMD指令:SSE/AVX 与编程demo

2023-10-14 06:58

本文主要是介绍SIMD 编程的优势与SIMD指令:SSE/AVX 与编程demo,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

资源:https://download.csdn.net/download/Rong_Toa/18745608

《Benefits of SIMD Programming | SIMD的优势》

目录

SIMD指令编程demo

正常代码

一次循环计算4次

使用SSE指令

使用AVX指令

性能对比

更多参考


SIMD指令编程demo


本文更新于 2018.10.24

本demo主要使用矩阵相乘, 演示了Intel SSE和AVX内部指令(intrinsics)的显式使用, 并对比了使用gcc和icc(Intel C/C++编译器)使用不同编译选项编译后的代码性能.

完整源码见: https://raw.githubusercontent.com/zzqcn/storage/master/code/c/simd_multiply.c

参考: https://software.intel.com/zh-cn/articles/ticker-tape-part-2

本文的软硬件环境如下:

  • CPU: Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz
  • 操作系统: CentOS Linux release 7.0.1406
  • 内核: 3.10.0-123.el7.x86_64
  • gcc: 4.8.5 20150623
  • icc: 19.0.0.120 20180804

正常代码


正常代码如下, 直接使用基本算法计算2个矩阵a和b, 结果放在c中:

void multiply(void) {unsigned i;for(i=0; i<N; i++) {c[i] = a[i] * b[i];}
}

一次循环计算4次


可以将正常代码改为一次循环内计算4次乘法, 某种情况下可以提升性能:

void multiply(void) {unsigned i;for(i=0; i<(N & ((~(unsigned)0x3))); i+=4) {c[i]   = a[i]   * b[i];c[i+1] = a[i+1] * b[i+1];c[i+2] = a[i+2] * b[i+2];c[i+3] = a[i+3] * b[i+3];}for(; i<N; i++) {c[i] = a[i] * b[i];}
}

使用SSE指令


Intel SSE指令通过128bit位宽的专用寄存器, 支持一次操作128bit数据. float是单精度浮点数, 占32bit, 那么可以使用一条SSE指令一次计算4个float数:

void multiply(void) {unsigned i;__m128 A, B, C;for(i=0; i<(N & ((~(unsigned)0x3))); i+=4) {A = _mm_load_ps(&a[i]);B = _mm_load_ps(&b[i]);C = _mm_mul_ps(A, B);_mm_store_ps(&c[i], C);}for(; i<N; i++) {c[i] = a[i] * b[i];}
}

注意这些SSE指令要求参数中的内存地址必须对齐于16字节边界, 所以可以用以下函数分配内存:

a = (float*) _mm_malloc(N*sizeof(float), 16);
b = (float*) _mm_malloc(N*sizeof(float), 16);
c = (float*) _mm_malloc(N*sizeof(float), 16);

要使用这些intrinsics, 需要包含x86intrin.h头文件.

 

使用AVX指令


较新的Intel CPU都支持AVX指令集, 它可以一次操作256bit数据, 是SSE的2倍. 使用AVX的代码如下:

void multiply(void) {unsigned i;__m256 A, B, C;for(i=0; i<(N & ((~(unsigned)0x7))); i+=8) {A = _mm256_load_ps(&a[i]);B = _mm256_load_ps(&b[i]);C = _mm256_mul_ps(A, B);_mm256_store_ps(&c[i], C);}for(; i<N; i++) {c[i] = a[i] * b[i];}
}

AVX指令要求内存地址对齐于32字节边界, 所以内存分配代码改为:

a = (float*) _mm_malloc(N*sizeof(float), 32);
b = (float*) _mm_malloc(N*sizeof(float), 32);
c = (float*) _mm_malloc(N*sizeof(float), 32);

 

性能对比


我分别使用gcc和icc以默认选项和-O3选项编译了以上3种版本的代码, 其中用gcc编译AVX版代码时需要加-mavx选项.

代码执行时间如下(单位毫秒):

代码版本gccgcc -O3iccicc -O3
原始946438405404
每次计算4项780438439442
SSE680439405406
AVX545447407406

代码执行时间是连续运行10次取的平均值. 某些时候执行时间起伏时间较大. 下图是根据上表生成的对比图:

由上图可知:

  • 现代编译器在-O3编译时会对代码进行充分优化, 使得本文中的代码无论使不使用SIMD指令性能差距不大
  • gcc编译器默认编译时未对代码进行充分优化, 使得不同算法的代码性能差距较大
  • intel编译器对-O3编译选项不敏感, 总是会自动优化代码

更多参考

  • Intel 64 and IA-32 Architectures Software Developer’s Manual
  • Intel Intrinsics Guide

 

这篇关于SIMD 编程的优势与SIMD指令:SSE/AVX 与编程demo的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/208875

相关文章

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

Java实现远程执行Shell指令

《Java实现远程执行Shell指令》文章介绍使用JSch在SpringBoot项目中实现远程Shell操作,涵盖环境配置、依赖引入及工具类编写,详解分号和双与号执行多指令的区别... 目录软硬件环境说明编写执行Shell指令的工具类总结jsch(Java Secure Channel)是SSH2的一个纯J

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

AOP编程的基本概念与idea编辑器的配合体验过程

《AOP编程的基本概念与idea编辑器的配合体验过程》文章简要介绍了AOP基础概念,包括Before/Around通知、PointCut切入点、Advice通知体、JoinPoint连接点等,说明它们... 目录BeforeAroundAdvise — 通知PointCut — 切入点Acpect — 切面

Spring Boot 整合 SSE(Server-Sent Events)实战案例(全网最全)

《SpringBoot整合SSE(Server-SentEvents)实战案例(全网最全)》本文通过实战案例讲解SpringBoot整合SSE技术,涵盖实现原理、代码配置、异常处理及前端交互,... 目录Spring Boot 整合 SSE(Server-Sent Events)1、简述SSE与其他技术的对

C#异步编程ConfigureAwait的使用小结

《C#异步编程ConfigureAwait的使用小结》本文介绍了异步编程在GUI和服务器端应用的优势,详细的介绍了async和await的关键作用,通过实例解析了在UI线程正确使用await.Conf... 异步编程是并发的一种形式,它有两大好处:对于面向终端用户的GUI程序,提高了响应能力对于服务器端应

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

Python包管理工具核心指令uvx举例详细解析

《Python包管理工具核心指令uvx举例详细解析》:本文主要介绍Python包管理工具核心指令uvx的相关资料,uvx是uv工具链中用于临时运行Python命令行工具的高效执行器,依托Rust实... 目录一、uvx 的定位与核心功能二、uvx 的典型应用场景三、uvx 与传统工具对比四、uvx 的技术实

C++ HTTP框架推荐(特点及优势)

《C++HTTP框架推荐(特点及优势)》:本文主要介绍C++HTTP框架推荐的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Crow2. Drogon3. Pistache4. cpp-httplib5. Beast (Boos