C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南这个目标,即安 装 -D 选项:指定配置变量(又称缓存变量) • 可见 CMake 项目的构建分为两步: • 第一步是 cmake -B build ,称为配置阶段( configure ),这时只检测环境并生成构建规则 • 会在 build 目录下生成本地构建系统能识别的项目文件( Makefile 或是 .sln ) • 第二步是 cmake --build build ,称为构建阶段( build 则是专为性能优化的构建系统,他和 CMake 结合都是行业标准了。 Ninja 和 Makefile 简单的对比 性能上: Ninja > Makefile > MSBuild Makefile 启动时会把每个文件都检测一遍, 浪费很多时间。特别是有很多文件,但是实 际需要构建的只有一小部分,从而是 I/O Bound 的时候, Ninja 的速度提升就很明 显。 然而某些专利公司的 CUDA toolkit 在 CMAKE_CXX_STANDARD_REQUIRED 是 BOOL 类型,可以为 ON 或 OFF ,默认 OFF 。 • 他表示是否一定要支持你指定的 C++ 标准:如果为 OFF 则 CMake 检测到编译器不支 持 C++17 时不报错,而是默默调低到 C++14 给你用;为 ON 则发现不支持报错,更安 全。 https://crascit.com/2015/03/28/enabling-cxx11-in-cmake/0 码力 | 166 页 | 6.54 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming5 10 5 15 30 20 为什么需要流水线 • 更高效的办法是,观察每个任务都占用哪些 资源,所占用资源不冲突的可以同时进行, 节省时间。 • 例如洗脸需要眼睛嘴巴手,刷牙需要嘴巴手 ,那么洗脸和刷牙不能同时进行。但是烧开 水只需要占用煤气灶,和洗脸刷牙不冲突, 所以可以一边烧开水一边洗脸刷牙。 • 所以让小彭老师来优化的话,可以只需要 5 + 5 + 10 + 20 = set 系列指令有 setle , setge , setl 等等。 • 冷知识: 32 位时代 cmov 系列曾经是 x86 的一个拓展特性(像 sse 一样),使用前需 要先用 cpuid 指令检测是否支持,如果在不支持 cmov 的 CPU 上使用会产生 SIGILL 错误。不过现在 64 位的 x86 CPU 都保证自带了 cmov 和 sse 拓展,所以不需要手动 开启什么开关编译器就会自动生成利用 还有一种“摆烂”的做法: • (cond ? a : b) // 方法 3 • 三目运算符通常会变成和 if-else 一样的分 支,同样会生成条件跳转指令,理应一样 低效。但是有时候编译器会检测到,可以 帮你自动优化成无分支版本的。 “ 妙用加减乘”进行无分支优化的通用公式 • 我比较喜欢方法 2 ,因为他可以很直观地同样适用于多个分支的情况,例如: • if (x < 0) return0 码力 | 47 页 | 8.45 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 01 学 C++ 从 CMake 学起则不然。 • 只需要写一份 CMakeLists.txt ,他就能够在调用时生成当前系统所支持的构建系统。 • 需要准确地指明每个项目之间的依赖关系,有头文件时特别头疼。 • CMake 可以自动检测源文件和头文件之间的依赖关系,导出到 Makefile 里。 • make 的语法非常简单,不像 shell 或 python 可以做很多判断等。 • CMake 具有相对高级的语法,内置的函数能够处理 具有相对高级的语法,内置的函数能够处理 configure , install 等常见需求。 • 不同的编译器有不同的 flag 规则,为 g++ 准备的参数可能对 MSVC 不适用。 • CMake 可以自动检测当前的编译器,需要添加哪些 flag 。比如 OpenMP ,只需要在 CMakeLists.txt 中指明 target_link_libraries(a.out OpenMP::OpenMP_CXX) 即可。 fmtlib/fmt - 格式化库,提供 std::format 的替代品(需要 -DFMT_HEADER_ONLY ) 7. gabime/spdlog - 能适配控制台,安卓等多后端的日志库(和 fmt 冲突!) • 只需要把他们的 include 目录或头文件下载下来,然后 include_directories(spdlog/include) 即 可。 • 缺点:函数直接实现在头文件里,没有提前0 码力 | 32 页 | 11.40 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程多个线程同时访问同一个 vector 会出现 数据竞争( data-race )现象。 std::mutex :上锁,防止多个线程同时进入某一代码段 • 调用 std::mutex 的 lock() 时,会检测 mutex 是否已经上锁。 • 如果没有锁定,则对 mutex 进行上锁。 • 如果已经锁定,则陷入等待,直到 mutex 被 另一个线程解锁后,才再次上锁。 • 而调用 unlock() 严格在解构时 unlock() ,但是 有时候我们会希望提前 unlock() 。这时可以用 std::unique_lock ,他额外存储了一个 flag 表 示是否已经被释放。他会在解构检测这个 flag ,如果没有释放,则调用 unlock() ,否则 不调用。 • 然后可以直接调用 unique_lock 的 unlock() 函 数来提前解锁,但是即使忘记解锁也没关系, • 还用了一个 {} 包住 std::lock_guard ,限 制其变量的作用域,从而可以让他在 } 之 前解构并调用 unlock() ,也避免了和下面 一个 lock_guard 变量名冲突。 如果上锁失败,不要等待: try_lock() • 我们说过 lock() 如果发现 mutex 已经上锁 的话,会等待他直到他解锁。 • 也可以用无阻塞的 try_lock() ,他在上锁失败0 码力 | 79 页 | 14.11 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 16 现代 CMake 模块化项目管理指南myvar 不会自动更新,还是旧的那几个文件,可能出现 undefined symbol ,需要重新运行 cmake -B build 才能更新。 • 加了,则每次 cmake --build 时自动检测目录是否更新,如果目录有新文件了, CMake 会自动帮你重新运行 cmake -B build 更新 myvar 变量。 六、头文件和源文件的一一对应关系 • 通常每个头文件都有一个对应的源文件,两个文件名字应当相同 文件。 • 注意不论是项目自己的头文件还是外部的系统的头文件,请全部统一采用 < 项目名 / 模块名 .h> 的格式。不要用 “模块名 .h” 这种相对路径的格式,避 免模块名和系统已有头文件名冲突。 十、依赖其他模块但不解引用,则可以只前向声明不导入头文件 • 如果模块 Carer 的头文件 Carer.h 虽然引用了其他模块中的 Animal 类,但 是他里面并没有解引用 Animal 好处:加快编译速度,防止循环引用。 十一、以项目名为名字空间( namsepace ),避免符号冲突 • 在声明和定义外面都套一层名字空间,例如此处我的子项目名是 biology ,那 我就 biology::Animal 。避免暴露全局的 Animal 。这是因为万一有个“不拘一 格”的第三方库也暴露个全局的 Animal ,两个符号就会发生冲突,由于类符号 都具有 weak 属性,链接器会随机选择一个覆盖掉,非常危险!0 码力 | 56 页 | 6.87 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程GPU 的架构版本号 是多少。这里是 520 表示版本号是 5.2.0 ,最后一位始终是 0 不用管,我们 通常简称他的版本号为 52 就行了。 • 这个版本号是编译时指定的版本,不是运 行时检测到的版本。编译器默认就是最老 的 52 ,能兼容所有 GTX900 以上显卡。 https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index int arr[1024]; • 那么 arr[0] 是存储在 bank 0 , arr[1] 是 bank 1……arr[32] 又是 bank 0 , arr[33] 又是 bank 1 。 区块冲突( bank conflict ) • 然而这种设计有一个问题,那就是如果多个线程同时访问到 了同一个 bank 的话,就需要排队。比如右图,线程 0-3 同 时访问了 bank 0 ,但是同一个 arr[0] 和 arr[32] 就会出现 bank conflict 导致必须排队影响 性能! 没有冲突,并行访问↓ 出现冲突,串行访问↓ 回到矩阵转置的案例:如何解决区块冲突? • 而刚刚那个矩阵转置的例子,这里的 blockSize 是 32 。可以看到第一个对 tmp 的访问是没冲突的。 • 而分析一下第二个对 tmp 的访问: threadIdx=(0,0) 的线程 0 会访问 tmp[0]0 码力 | 142 页 | 13.52 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化4096 字节)随机访问 • 解决方案就是,把分块的大小调的更大一些,比 如 4KB 那么大,即 64 个缓存行,而不是一个。 • 这样一次随机访问之后会伴随着 64 次顺序访问, 能被 CPU 检测到,从而启动缓存行预取,避免了 等待数据抵达前空转浪费时间。 页对齐的重要性 • 为什么要 4KB ?原来现在操作系统管理内存是用分页 ( page ),程序的内存是一页一页贴在地址空间中的, ,这个一样沙雕,甚至更烂—— vector 本身是 24 字节。 • 但是 float [n][m] 和 array, m> 就没问题,因为他们是静态大小,编译器可 以检测到并自动扁平化,转换成乘法和加法来计算地址。 今日乳 Ja (1/1) 有一种病 ~ 叫 JavaBean~ 为什么二级指针是低效的存储和索引方式 随机访问性能测试 内存分配性能测试 二维数组:行主序与列主序 写入的地址尽可能分散开了就行了。比如这里 ,我们把每个核心访问的地方跨越了 16KB , 这样 CPU 就知道每个核心之间不会发生冲突 ,从而可以放心地放在一级缓存里,不用担心 会不会和其他核心共用了一个缓存行了。 • 不过错误共享只会发生在写入的情况,如果多 个核心同时读取两个很靠近的变量,是不会产 生冲突的,也没有性能损失。 0 码力 | 147 页 | 18.88 MB | 1 年前3
现代C++ 教程:高速上手C++11/14/17/20. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 5 目录 目录 事务内存 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 是一个独占指针,是不能够被 “=” 值捕获到,这时候我们可以将其转 移为右值,在表达式中初始化。 泛型 Lambda 上一节中我们提到了 auto 关键字不能够用在参数表里,这是因为这样的写法会与模板的功能产生 冲突。但是 Lambda 表达式并不是普通函数,所以在没有明确指明参数表类型的情况下,Lambda 表达 式并不能够模板化。幸运的是,这种麻烦只存在于 C++11 中,从 C++14 开始,Lambda 类型的对象 我们现在来看一个实际的例子。 TODO: https://godbolt.org/z/9liFPD 模块 TODO: 合约 TODO: 范围 TODO: 协程 TODO: 事务内存 TODO: 总结 总的来说,终于在 C++20 中看到 Concepts/Ranges/Modules 这些令人兴奋的特性,这对于一门已 经三十多岁『高龄』的编程语言,依然是充满魅力的。0 码力 | 83 页 | 2.42 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化inline 没关系,内联与否只取决于是否在同文件,且函数体够小 要性能的,定义在头文件声明为 static 即可,没必要加 inline 的 static 纯粹是为了避免多个 .cpp 引用同一个头文件造成冲突,并不是必须 static 才内 联 如果你不确定某修改是否能提升性能,那你最好实际测一下,不要脑内模拟 inline 在现代 C++ 中有其他含义,但和内联没有关系,他是一个迷惑性的名字 “ 大厂面试官”笑话 因为他不敢保证运行这个程序的电脑支持 AVX 指令集…… 两个 int32 可以合并为一个 int64 四个 int32 可以合并为一个 __m128 八个 int32 可以合并为一个 __m256 让编译器自动检测当前硬件支持的指令集 -march=native 让编译器自动判断当前硬件支 持的指令。老师的电脑支持 AVX 指令集,所 以他用了。不过注意这样编译出的程序,可能 放到别人不支持 AVX 的电脑上没法运行。 指向的数组是否有重合。 考虑 func(a, a + 1) 的情况,那样会产生数据依赖链,没法 SIMD 化 。 为了优化而不失正确性,他索性生成两份代码: 一份是 SIMD 的,一份是传统标量的 他在运行时检测 a, b 指针的差是否超过 1024 来判断是否有重叠现 象。 1. 如果没有重叠,则跳转到 SIMD 版本高效运行。 2. 如果重叠,则跳转到标量版本低效运行,但至少不会错。 SIMD 版 标量版0 码力 | 108 页 | 9.47 MB | 1 年前3
《深入浅出MFC》2/e却是为生活而技术,探讨深入,但 谨守主轴份际。所有我所铺陈的核心层面的知识,都是为了建立起一份扎扎实实的 programming 基础,让你彻底了解MFC 为你铺陈的骨干背后,隐藏了多少巧妙机关,做掉 了多少烦琐事务。 有了这份基础,你才有轻松驾驭MFC 的本钱。 唯有这份基础,才能使你胸中自有丘壑。 如果够用心,你还可以附带地从本书概略学习到一个application framework 的设计蓝图。虽 pSales = &aSales; pWager = &aSales; // 以「基础类别之指针」指向「衍生类别之对象」 pWager->setSales(800.0); // 错误(编译器会检测出来), // 因为CWage 并没有定义setSales 函数。 pSales->setSales(800.0); // 正确,调用CSales::setSales 函数。 虽然pSales ( 英文版) 。 第4章 Visual C++ 整合開發環境 221 图4-1b 当你安装IE 3.01 ( 英文版) 时, 可能会和你现有的IE 中文版有 些版本冲突。我的经验是依其建议, 保留现有的文件。 图4-1c Visual C++ 5.0 Setup 程序画面。请把鼠标移到右上角第五个项目 "Microsoft Visual C++ 5.0"0 码力 | 1009 页 | 11.08 MB | 1 年前3
共 26 条
- 1
- 2
- 3













