拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Vc 库指南:用 C++ 类型系统实现显式 SIMD 数据并行编程

Vc 库指南:用 C++ 类型系统实现显式 SIMD 数据并行编程 桌面应用系统监控【免费下载链接】conkyLight-weight system monitor for X, Wayland, and other things, too项目地址https://gitcode.com/gh_mirrors/co/conky点击查看免费下载导读本文以 conky 仓库中随附的 Vc 库版本 1.4.4位于 3rdparty/Vc/文档为主线系统讲解 Vc 的核心编程模型如何通过Vector、Mask、SimdArray等类型在 C 源码中显式表达数据并行从而摆脱对编译器自动向量化的依赖。读完本文你将掌握 Vc 的向量类型体系、掩码与条件赋值、内存对齐约定、simdize的使用方式并能在 conky 这样的实际项目中识别 Vc 的集成位置与调用方式最终能够独立完成 Vc 的克隆、构建与集成配置。Vc 是什么通过类型系统显式表达数据并行现代 CPU 与 GPU 要获得完整性能几乎都依赖数据并行data-parallel代码同一序列的运算被施加到不同的输入数据上。CPU 通过 SIMD 寄存器与指令实现这一点——一条 SIMD 指令可以同时执行 N 个寄存器通道上的运算GPU 则由单一指令解码/调度器驱动 N 个线程严格同步执行。Vc 正是为弥合用 C 写标量代码与目标硬件需要向量代码之间鸿沟而生的免费软件库。Vc 的核心设计理念是通过类型系统引入并行性。开发者用 Vc 的向量类型书写一次运算编译器与硬件按指令集宽度自动展开。这与另一类显式并行控制结构在循环体内引入新语义的竞争方案形成鲜明对比——Vc 无需改动控制流只需改动类型。用 Vc 写出的代码可以不加修改地编译到多种后端AVX 与 AVX2SSE2 至 SSE4.2 或 SSE4aScalar标量回退至于 AVX-512、NEON、NVIDIA GPU / CUDA 的支持在文档中被明确标注为开发中或研究状态Intel 在 ICC 18 中放弃 MIC 支持后Vc 1.4 也同步移除了对 MIC 的支持。这一类型即并行的路线可以从 Vc/vector.h 的源码中得到印证float_v、double_v、int_v等全部是VectorT的别名而VectorT的底层实现会依据编译期宏Vc_IMPL_SSE/Vc_IMPL_AVX分别拉取 sse/vector.h 或 avx/vector.h 中的实现始终保留 scalar/vector.h 作为兜底。为什么编译器自动向量化不够当前 C 编译器如 GCC、clang确实能对标量代码做自动变换auto-vectorization但这一过程存在根本性障碍当开发者以纯标量方式书写算法时算法内在的数据并行属性已经在类型层面丢失编译器必须事后重建它。因此编译器无法保证把任意代码向量化为最高效的数据并行变体尤其是跨越多个函数、甚至多个编译单元的较大数据并行循环往往不会被改写成高效的 SIMD 代码。Vc 提供的正是缺失的连接件并行性在写代码时就通过类型显式声明编译器无需猜测。Vc 1.4 的向量类型体系向量类型别名Vector在 Vc/vector.h 中Vc 为常见基础类型提供了开箱即用的向量别名别名底层类型含义float_vVectorfloat单精度浮点向量double_vVectordouble双精度浮点向量int_v/uint_vVectorint/Vectoruint有/无符号整型向量short_v/ushort_vVectorshort/Vectorushort短整型向量llong_v/ullong_vVectorllong/Vectorullong长长整型向量long_v/ulong_vVectorlong/Vectorulong长整型向量schar_v/uchar_vVectorschar/Vectoruchar字符宽整型向量此外还提供了int_leastN_v、int_fastN_v、intN_vN 取 8/16/32/64等与cstdint风格对齐的类型族方便在不同平台上写出可移植的宽度约定。向量类型的宽度Size由编译目标与 ABI 决定Vc/vector.h 中通过一组static_assert将double_v::Size等与宏Vc_DOUBLE_V_SIZE、Vc_FLOAT_V_SIZE、Vc_INT_V_SIZE、Vc_UINT_V_SIZE等逐一核对保证头文件宏定义与类型实际宽度一致——这正是可移植性来自类型系统的落地保障。掩码类型Mask与条件赋值向量运算常常需要按通道选择语义Vc 为此提供与每个向量类型一一对应的掩码类型double_m、float_m、int_m、uint_m、short_m、ushort_m等同样定义在 Vc/vector.h。在 common/mask.h 中MaskT, Abi作为模板类实现了掩码的布尔代数运算、||、、|及对应的复合赋值可以用于描述哪些通道参与运算。掩码最典型的消费方是条件赋值机制Vc::where(mask, lvalue)。从 common/where.h 的实现可以看到MaskedLValue把掩码与左值引用绑定在一起返回一个带掩码的左值对其赋值时只有掩码为真的通道会被写入。其接口刻意让赋值运算符返回void——源码注释指出当掩码退化为bool时整段代码可能被完全跳过因此无法承诺返回引用。这种设计让分支密集的标量逻辑如逐元素条件更新能够以全宽度执行 通道掩码的 SIMD 友好方式重写。配合 common/iif.h即时 if等工具开发者可以写出既保持向量宽度、又保留条件语义的代码。SimdArray固定长度 SIMD 数组除了宽度与机器相关的VectorTVc 还提供固定长度的SimdArrayT, N用于恰好装载 N 个标量值的场景。其类型选择逻辑位于 common/simdarray.hselect_best_vector_type会按AVX2::Vector→AVX::Vector→SSE::Vector→Scalar::Vector的优先级选出第一个宽度不小于 N 的向量类型若 N 小于某个候选宽度则继续向下递归。这保证了 N 个值总是被打包进恰好够用且最优的 SIMD 寄存器。数学函数与命名空间Vc 对常用数学函数提供了向量重载sin、cos、sqrt、exp、log、log2、floor、ceil、trunc、round、fma、isfinite、isnan等并且在未定义Vc_NO_STD_FUNCTIONS时将这些重载注入std命名空间见 Vc/vector.h使得std::min(v1, v2)、std::floor(v)这样的写法对向量类型同样成立标量代码向向量代码迁移的改造成本被降到最低。内存对齐约定向量类型要求特定的内存对齐。在 Vc/vector.h 中定义了两个关键常量Vc::VectorAlignmentVectorT对象本身所需的最保守对齐Vc::MemoryAlignment对齐 load/store 所需的最保守对齐。二者可用于alignas表达式或配合Vc::malloc做动态对齐分配。加载与存储接口以Vc::Aligned/Vc::Unaligned标签区分对齐与未对齐访存conky 源码见下文正是以Vc::Unaligned标签完成常规内存的装载。入门示例3D 标量积的向量化原版 README 给出了一个教科书级别的对比完整展示同样的算法三种写法1. 内建 float 的标量写法using Vec3D std::arrayfloat, 3; float scalar_product(Vec3D a, Vec3D b) { return a[0] * b[0] a[1] * b[1] a[2] * b[2]; }2. 使用 Vc 的float_v向量化写法using Vc::float_v using Vec3D std::arrayfloat_v, 3; float_v scalar_product(Vec3D a, Vec3D b) { return a[0] * b[0] a[1] * b[1] a[2] * b[2]; }仅仅把元素类型从float换成float_v*与运算符便从标量运算自动变为逐通道的 SIMD 运算。这段代码会依据目标硬件能力在 1、4、8、16……个标量积并行计算之间自动伸缩——这正是宽度由硬件决定、代码不随宽度改变的零开销可移植性。3. 使用 Intel SSE intrinsics 的对比写法using Vec3D std::array__m128, 3; __m128 scalar_product(Vec3D a, Vec3D b) { return _mm_add_ps(_mm_add_ps(_mm_mul_ps(a[0], b[0]), _mm_mul_ps(a[1], b[1])), _mm_mul_ps(a[2], b[2])); }这条 SSE 版本既不会自动扩展到 AVX、AVX-512也无法移植到其他 SIMD 指令集如 NEON。前缀式的函数调用_mm_add_ps(...)让运算顺序被函数嵌套掩盖可读性也明显逊色。三者对比正是 Vc 设计目标的最佳注脚类型驱动、宽度无关、跨指令集可移植。原 README 还提供了若干可直接在 Compiler Explorer 上编译观察的进阶示例包括simdize示例演示如何把既有标量类型变换为向量类型总动量与时间步进示例对std::vectorParticle的整体向量化矩阵示例演示垂直向量化vertical vectorization手法文档特别注明它不能随向量宽度伸缩但适合与其他语言的同类方案对比学习N 涡求解器示例展示对多个std::vectorfloat的simdize迭代并特别强调与-mavx2 -mfma相比-march标志的正确设置对最终代码质量至关重要。simdize让既有标量类型自动获得向量宽度simdize是 Vc 1.4 的一项高阶特性它通过模板机制把标量类型构成的复合类型递归变换为对应向量类型构成的复合类型从而让既有算法无需重写即可获得数据并行能力。其实现入口位于 Vc/simdize该头文件依次引入vector.h、Allocator与核心实现 common/simdize.h。N 涡求解器、std::vectorParticle时间步进等 Compiler Explorer 示例正是围绕这一特性展开的。simdize的典型用途包括对标量结构体数组SoA直接获得向量版本让模板化算法同时服务于标量与向量两种实例化将算法与目标指令集解耦保留-march优化空间。结合Vc::Allocator等配套设施见 Vc/Allocator可以确保容器内存满足向量访存的对齐要求。构建与安装构建要求CMake 3.0C11 编译器仓库内构建脚本实际将CMAKE_CXX_STANDARD设为 14见 3rdparty/Vc/CMakeLists.txtGCC 4.8.1clang 3.4ICC 18.0.5Visual Studio 201964 位目标构建步骤原版文档全流程1. 克隆仓库并初始化 git 子模块git clone https://github.com/VcDevel/Vc.git cd Vc git submodule update --init2. 创建独立构建目录Vc 明确禁止在源码目录内直接配置见 3rdparty/Vc/CMakeLists.txt$ mkdir build $ cd build3. 用 CMake 配置并按需追加选项$ cmake ..指定安装目录$ cmake -DCMAKE_INSTALL_PREFIX/opt/Vc ..附带构建单元测试$ cmake -DBUILD_TESTINGON ..Windows 下若安装有多个 Visual Studio 版本可显式指定生成器$ cmake -G Visual Studio 16 2019 ..其余可用生成器见cmake --help。4. 构建并安装$ cmake --build . -j 16 $ cmake --install . # may require permissionsWindows 下也可以直接在 Visual Studio 中打开Vc.sln从 IDE 完成构建与安装。CMake 层面的实现选择机制Vc 的构建系统会依据目标平台自动确定指令集后端。从 3rdparty/Vc/CMakeLists.txt 可以看到构建脚本通过CMAKE_SYSTEM_PROCESSOR区分 x86Vc_X86与 ARM 平台Vc_ARMARM 平台会给出没有可用的优化实现警告并回退到支持性源码。后端选择还受用户级选项控制。在 cmake/VcMacros.cmake 中定义了Vc_IMPL缓存变量默认值为auto自动选用最佳可用指令集也可以显式指定Scalar、SSE、AVX等实现指定后脚本会附加-DVc_IMPL...编译定义并校验所选指令集是否已被编译器标志启用例如SSE会映射到USE_SSE2。当 x86 平台有效时静态库Vc会编译 src/ 下的const.cpp、cpuid.cpp、support_x86.cpp并按指令集分别编译trigonometric.cpp、sse_sorthelper.cpp、avx_sorthelper.cpp后者只对 AVX/AVX2 可用非 x86 平台则仅编译support_dummy.cpp。此外构建脚本还会针对已知有问题的编译器组合做防御性处理例如在 ARM 上禁用 XOP、处理过旧的 binutils 无法支持 XOP/AVX2 指令等见 cmake/VcMacros.cmake。conky 仓库中的 Vc从 vendored 依赖到实际调用本仓库将 Vc 作为第三方依赖随源码一并托管vendor。在 3rdparty/CMakeLists.txt 中可以看到明确的集成声明Vc version 1.4.4并add_subdirectory(Vc)与toluapp、spdlog并列。Vc 自身版本由 Vc/version.h 中的Vc_VERSION_STRING 1.4.4与Vc_VERSION_NUMBER 0x010408定义构建脚本据此生成项目版本号。值得关注的实现事实是Vc 不只是被打包进仓库conky 的核心代码确实在使用它。conky 的几何模块 src/geometry.h 以#include Vc/Vc引入 Vc 头文件L19并用 Vc 类型作为二维/三维向量的内部存储vecT, Length的内部数据成员类型为Vc::arrayT, LengthL102在支持的平台上自动获得 SIMD 友好的布局浮点向量的floor/ceil运算并不走std::floor/std::ceil而是先把数据装载进Vc::SimdArrayT, Length使用Vc::Unaligned未对齐标签调用 Vc 的 SIMD 版本Vc::floor/Vc::ceil后再存回L372-L397——这是对Vc 向量数学优于标量逐元素处理的直接工程应用基于vec/rect提供的vec2f、vec2d、vec2i、vec3f、vec4f等别名L406-L420构成了 conky 坐标与矩形运算的通用几何层。由此可见conky 选择 Vc 并非为了追逐热门而是看中其在允许 SIMD 的平台获得向量运算、在其他平台平滑回退的可移植性——这与 Vc 官方文档宣称的 Scalar 回退能力完全吻合。当你在 README.md 的构建配置中开启相应架构优化时这份依赖会自动参与编译。项目现状与路线维护模式与 std-simd原版 README 开篇即给出重要声明需要使用者知悉Vc 现已进入维护模式不再积极开发但社区提交的 bugfix 类 pull request 仍会被持续审阅。你可能希望迁移到 std-simd。背景是GCC 11 已在 libstdc 中内置了实验性的std::simd且可配合 clang 使用Vc 1.4 中已存在而std-simd尚未提供的特性未来将演化为依赖std-simd的 Vc 2.0。换言之Vc 的长期路线是功能并入 C 标准库体系官方也有把 Vc 的向量类整合进 C 标准库的工作记录。对正在评估是否采用 Vc 的开发者这一现状意味着Vc 1.4 是稳定、文档齐全、可放心用于存量代码的版本新项目可以评估 std-simd但需要接受其实验性状态与不同编译器上的可用性差异Vc 的标量回退与多指令集后端设计使其在一次性构建、多平台发布场景下仍有实用价值。文档与学术出版物Vc 的文档由 Doxygen 生成可在仓库doc子目录运行doxygen自行构建。原 README 同时列出了官方持续构建的各版本文档覆盖 1.4 分支、1.4.4/1.4.3/1.4.2/1.4.1/1.4.0 各 release、1.3 分支、1.3.0/1.2.0/1.1.0 release 以及 0.7 分支。该项目拥有一系列公开发表的学术文献可作为深入理解其设计动机与性能方法论的第一手资料M. Kretz《Extending C for Explicit Data-Parallel Programming via SIMD Vector Types》Goethe University Frankfurt 博士论文2015M. Kretz 与 V. Lindenstruth《Vc: A C library for explicit vectorization》Software: Practice and Experience2011M. Kretz《Efficient Use of Multi- and Many-Core Systems with Vectorization and Multithreading》University of Heidelberg 学位论文2009。此外还有把 Vc 向量类功能整合进 C 标准库的专项工作其讨论与进展可沿仓库 wiki 中的 ISO 标准化主题查阅。许可证Vc 以 3-clause BSD license 发布允许自由使用、修改与再分发附带保留版权声明、条件列表与免责声明的义务。本仓库对 Vc 的 vendored 集成即是在该许可证条款下进行的。赞分享桌面应用系统监控【免费下载链接】conkyLight-weight system monitor for X, Wayland, and other things, too项目地址https://gitcode.com/gh_mirrors/co/conky点击查看免费下载相关推荐FP8量化深度解析LongCat-Flash-Chat如何实现高效推理的完整指南FP8量化深度解析LongCat Flash Chat如何实现高效推理的完整指南 FP8量化技术 正在彻底改变大语言模型的推理效率 美团LongCat深入解析PP-OCRv5移动端识别模型架构掌握OCR核心技术要点深入解析PP OCRv5移动端识别模型架构掌握OCR核心技术要点 想要快速部署高效的OCR文字识别系统吗eslav_PP OCRv5_mobile_rec_Taskflow现代C通用任务并行编程系统Taskflow现代C通用任务并行编程系统 1. 项目介绍 Taskflow 是一个使用现代 C 编写的通用任务并行编程框架。它旨在帮助开发者快速实现高性能计算并发编程上一篇Resemble.jsJavaScript图像分析与对比的终极指南下一篇DearPyGui突破Python GUI开发瓶颈的高性能图形界面框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表