C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming性能优化 之 无分支编程 Branchless Programming by 彭于斌( @archibate ) 两种代码写法:分支 vs 三目运算符 两种使用方式:排序 vs 不排序 测试结果(均为 gcc -O3 ) 测试结果可视化 图表比较:分支 vs 无分支 分支 无分支 0 0.01 0.02 0.03 耗时(越低越好) 乱序 有序 • 传统的分支方法实现的 uppercase uppercase ,对于 排序过的数据明显比乱序时高效。 • 无分支的方法对于乱序和有序的数据一样 高效,性能吊打了传统的分支方法。 • 对于传统分支的做法,为什么排序了的更 高效?既然无分支更高效,我要怎样优化 才能让我的程序变成无分支的呢?那就来 看本期性能优化专题课吧! 分支预测成败对性能的影响 排序为什么对有分支的版本影响那么大 为什么需要流水线 • 为了高效, CPU 的内部其实是一个流水 让不占用相同资源的任务同时进行,这也是 CPU 流水线的初衷。但理想是美好的,现实 是骨感的,对于程序来说,指令不只是一个 个简单的任务,有时候我们需要做判断,来 决定要执行的具体任务,这就是分支,在汇 编语言中体现为条件跳转指令。 • 例如我们这里给任务清单加一个,如果烧开 水时被烫伤,则直接去医院的特殊任务。 • 特点:一旦触发去医院这个支线,则后面的 任务都不用做了,直接跳过。0 码力 | 47 页 | 8.45 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 03 现代 C++ 进阶:模板元编程com/parallel101/course 高性能并行编程与优化 - 课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 英伟达家显卡( GPU 专题) 软件要求: Visual Studio 2019 ( Windows 用户) GCC 9 及以上( Linux 用户) CMake 3.12 及以上(跨平台作业) Git 2.x (作业上传到 GitHub ) CUDA Toolkit 10.0 以上( GPU 专题) 为什么需要模板函数( template ) • 避免重复写代码。 • 比如,利用重载实现“将一个数乘以 这样显然是会被他自动优化掉的。 模板的应用:编译期分支 • 更进一步,可以用 C++17 的 if constexpr 语法,保证是编译期确定的分支: • (下一讲会深入分析编译器的工作原理) 模板的难题:编译期常量的限制 • 编译期常量的限制就在于他不能通过运行时变量组成的表达式来指定。比如: • 这里在 if constexpr 的表达式里用到了运行时变量,从而无法作为编译期分支的条件。 模板的难题:编译期常量的限制(续)0 码力 | 82 页 | 12.15 MB | 1 年前3
Zadig 面向开发者的云原生 DevOps 平台优化加速产研流程,工程师团队级规模化协 作,消除工具孤岛,系统性的提升人效 典型客户:字节飞书、云器、驭势、小鹏、 易快报、 MioTech 、星云有客、药师帮 大规模微服务环境治理 支持多分支、多业务间协作,消除环境不稳 定和不够用的阻力,高效率自动化验证质量 典型客户: TT 语音、飞书、钛动、闪电出 行 传统行业研发数字化转型 同步实现研发的数字化转型和 DevOps 不透明的测试环境导致大量问题 4. 为每一次部署维护一个 Chart 版本 现状 效能提升场景: 2K+ 微服务、多语言、 Helm 、 K8s 多集群 1. 开发流程 提交代码到 Feature 分支 -> GitLab-CI 自动构建打包 Chart (写一堆复杂 的脚本 ) -> -> Rancher 上手动替换 Helm Chart 版本 -> 调试 (使用 Chart -> Rancher 上手动替换 Helm Chart 版本 工具链: • GitLab (源码 + 服务 Chart 配 置) • Rancher 部署 分支策略: • feature -> develop/release -> master 环境策略: • 三套环境( dev 、 qa 、 prod ) 现状:基于 GitLab + Helm0 码力 | 59 页 | 81.43 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化com/parallel101/course 高性能并行编程与优化 - 课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 英伟达家显卡( GPU 专题) 软件要求: Visual Studio 2019 ( Windows 用户) GCC 9 及以上( Linux 用户) CMake 3.12 及以上(跨平台作业) Git 2.x (作业上传到 GitHub ) CUDA Toolkit 10.0 以上( GPU 专题) 第 0 章:汇编语言 x64 架构下的寄存器模型 通用寄存器: 32 位时代 • 32 位 判。如果你是自己手写 SIMD 指令 的话就要考虑一下这个。 n 总是 4 的倍数?避免边界特判 如果你能保证 n 总是 4 的倍数,也可以这样写: 编译器会发现 n % 4 = 0 ,从而不会生成边界特判的分支 。 假定指针是 16 字节对齐的: assume_aligned 如果能保证指针 a 总是对齐到 16 字节,在 GCC 编译器中这样 写: 但这样不通用,因此 C++20 引入了标准化的0 码力 | 108 页 | 9.47 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程辑核陷入内存等待时切换到另一个逻辑核上执行,避免空 转。 GPU 的解决方法就是单个 SM 执行很多个线程,然后在遇 到内存等待时,就自动切换到另一个线程) 板块内线程的同步 • 因此,我们可以给每个 if 分支后面加上 __syncthreads() 指令。 • 他的功能是,强制同步当前板块内的所有线程。也就是让所有线程 都运行到 __syncthreads() 所在位置以后,才能继续执行下去。 • 绑在一起执行的,就像 CPU 的 SIMD 那样。 因此如果出现分支( if )语句时,如果 32 个 cond 中有的为真有的为假,则会导致两个分 支都被执行!不过在 cond 为假的那几个线程 在真分支会避免修改寄存器和访存,产生副作 用。而为了避免会产生额外的开销。因此建议 GPU 上的 if 尽可能 32 个线程都处于同一个 分支,要么全部真要么全部假,否则实际消耗 了两倍时间! 避免修改寄存器和访存相当于 避免修改寄存器和访存相当于 CPU 的 SIMD 指令 _mm_blendv_ps 和 _mm_store_mask_ps ,不过 GPU 这种 SIMT 的设计能够自动处理分支和循环的分歧,这是 他门槛比 CPU 低的一点。0 码力 | 142 页 | 13.52 MB | 1 年前3
Zadig 产品使用手册本地自测—— IDE 热部署 1. 查看服务和环境 2. 本地代码热部署到远端 测试验证 变更发布 需求开发 提交代码及 CI 过程 1. 本地编写代码推送到远端分支 1. 本地基于 develop 分支新建分支,在新建的分支上,编写代码 2. 推送代码到自己账号下的代码库 3. GitLab 上创建 MR 2. 自动触发 CI 过程,包括单元 测试,代码风格 检查、代码扫描0 码力 | 52 页 | 22.95 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南也可以通过环境变量 CXX 指定 CMAKE_GENERATOR 也可以了解一下 顺便一提,小彭老师使用的 vimrc 分享 github.com/archibate/vimrc 第 9 章:分支与判断 BOOL 类型的值 • 通常来说 BOOL 类型的变量只有 ON/OFF 两种取值。 • 但是由于历史原因, TRUE/FALSE 和 YES/NO 也可以表示 BOOL 类型。 • (Hello MATCHES “Hello”) 但是因为找不到名为 Hello 的变量,所以会被直接当成普通的字符串来处理。 也就是 if (“Hello” MATCHES “Hello”) 从而会执行真分支,结果正常。 万一好巧不巧,正好定义了 Hello 这个变量呢? 然而假如存在 Hello 这个变量,其值为 “ world” 。 那么 if (${MYVAR} MATCHES “Hello”) (Hello MATCHES “Hello”) 而因为 Hello 这个变量名存在,所以会被(出于历史原因的) if 进一步求值: if (“world” MATCHES “Hello”) 从而会执行假分支,结果不正常了。 解决:用引号包裹起来,防止被当做变量名 初学者如果搞不明白,可以把所有不确定的地方都套上一层引号, 例如” ${MYVAR}” ,这样就可以避免被 if 当做变量名来求值了。0 码力 | 166 页 | 6.54 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 https://github.com/archibate ) Zeno 节点系统 1.0 Zeno 节点系统 2.0 • Zeno 2.0 所在的分支: https://github.com/zenustech/zeno/tree/zeno2 • Zeno 1.0 所在的分支: https://github.com/zenustech/zeno/ Zeno 中的基本类型 • IObject 一切对象的公共基类。0 码力 | 54 页 | 3.94 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化字节)所花费的时间。 • 根据计算: 125/64*4≈8 • 即从主内存读取一次 float 花费 8 个 cycle , 符合小彭老师的经验公式。 • “right” 和“ wrong” 指的是分支预测是否成功。 多少计算量才算多? • 看右边的 func ,够复杂了吧?也只是勉勉强强超过一 点内存的延迟了,但在 6 个物理核心上并行加速后, 还是变成 mem-bound 了。 • 加速比: float = 64 字节(缓存行大小),一个缓存行预取一遍就够了。 • 如何每隔 16 次 x++ 才执行 _mm_prefetch 一次呢?暴力通过 if (x % 16) 判断吗?不行,涉及到分支也太低效了! • 这时可以先将外层循环改为针对另一个变量, xBase 的跨步为 16 的循环,即 xBase += 16 。然后内部先执行一次 _mm_prefetch ,再弄一个小循环遍历0 码力 | 147 页 | 18.88 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理com/parallel101/course 高性能并行编程与优化 - 课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 英伟达家显卡( GPU 专题) 软件要求: Visual Studio 2019 ( Windows 用户) GCC 9 及以上( Linux 用户) CMake 3.12 及以上(跨平台作业) Git 2.x (作业上传到 GitHub ) CUDA Toolkit 10.0 以上( GPU 专题) 从一个案例看 C++ 的历史 • 求一个列表中所有数的和: # 参考资料 - [ 热心观众整理的学习资料 cn/read/CMake-Cookbook/README.md) - [CMake 官方文档 ](https://cmake.org/cmake/help/latest/) - [Git 官方文档 ](https://git-scm.com/doc) - [GitHub 官方文档 ](https://docs.github.com/en) 古代: C 语言 近代: C++98 引入 STL 容器库0 码力 | 96 页 | 16.28 MB | 1 年前3
共 20 条
- 1
- 2













