C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南自动调用本地的构建系统在 build 里构建,即: make -C build -j4 // 调用本地的构建系统执行 install 这个目标,即安 装 -D 选项:指定配置变量(又称缓存变量) • 可见 CMake 项目的构建分为两步: • 第一步是 cmake -B build ,称为配置阶段( configure ),这时只检测环境并生成构建规则 • 第二次配置时没有 -D 参数,但是之前的 -D 设置的变量都会被保留 • (此时缓存里仍有你之前定义的 CMAKE_BUILD_TYPE 和 CMAKE_INSTALL_PREFIX ) -G 选项:指定要用的生成器 • 众所周知, CMake 是一个跨平台的构建系统,可以从 CMakeLists.txt 生成不同类型的构建系 统(比如 Linux 的 make , Windows 的 MSBuild MSBuild )称为本地构建系统( native buildsystem )。 • 负责从 CMakeLists.txt 生成本地构建系统构建规则文件的,称为生成器( generator )。 -G 选项:指定要用的生成器 • Linux 系统上的 CMake 默认用是 Unix Makefiles 生成器; Windows 系统默认是 Visual Studio 2019 生成器; MacOS0 码力 | 166 页 | 6.54 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 01 学 C++ 从 CMake 学起因此,我们提出多文件编译的概念,文件之间通过符号声明相互引用。 • > g++ -c hello.cpp -o hello.o • > g++ -c main.cpp -o main.o • 其中使用 -c 选项指定生成临时的对象文件 main.o ,之后再根据一系列对象文件进行链接 ,得到最终的 a.out : • > g++ hello.o main.o -o a.out 为什么需要构建系统( Makefile hellolib 的可执行文件自动添加这个路径,把 PUBLIC 改成 PRIVATE 即可。这就是他们的用途:决定一个属性要不要在被 link 的时候传播。 目标的一些其他选项 • 除了头文件搜索目录以外,还有这些选项, PUBLIC 和 PRIVATE 对他们同理: • target_include_directories(myapp PUBLIC /usr/include/eigen3) PUBLIC -fopenmp) # 添加编译器命令行选项 • target_sources(myapp PUBLIC hello.cpp other.cpp) # 添加要编译的源文件 • 以及可以通过下列指令(不推荐使用),把选项加到所有接下来的目标去: • include_directories(/opt/cuda/include)0 码力 | 32 页 | 11.40 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 16 现代 CMake 模块化项目管理指南CMakeLists.txt 。 二、根项目的 CMakeLists.txt 配置 • 在根项目的 CMakeLists.txt 中,设置了默 认的构建模式,设置了统一的 C++ 版本 等各种选项。然后通过 project 命令初始 化了根项目。 • 随后通过 add_subdirectory 把两个子项 目 pybmain 和 biology 添加进来(顺序 无关紧要),这会调用 src/main.cpp (√) src/test/main.cpp (√) • 区别在于 GLOB_RECURSE 允许 * 匹配嵌套的目录。 • 疑问 2 :加了 CONFIGURE_DEPENDS 这个选项有什么区别? • 如果不加,在你创建新文件时, myvar 不会自动更新,还是旧的那几个文件,可能出现 undefined symbol ,需要重新运行 cmake -B build 才能更新。 libQt5Core.so ) 。 • 而是去找包配置文件(例如 Qt5Config.cmake ),这个配置文件里包含了包的具体信息, 包括动态库文件的位置,头文件的目录,链接时需要开启的编译选项等等。而且某些库都 具有多个子动态库,例如 Qt 就有 libQt5Core.so 、 libQt5Widgets.so 、 libQt5Network.so 。因此 CMake 要求所有第三方 库作者统一包装成一个0 码力 | 56 页 | 6.87 MB | 1 年前3
《深入浅出MFC》2/eframework 的观念,以及MFC 骨干程序。所谓骨干程序,是指Visual C++ 的工具AppWizard 所产生出来的程序代码。当然,AppWizard 会根据你的选项做出不同 的程序代码,我所据以解说的,是大众化选项下的产品。 第四篇以微软公司附于Visual C++ 光盘片上的一个范例程序Scribble 为主轴,一步一步加 上新的功能。并在其间深入介绍Runtime Type 上顺利编译。原因出在VC++ 4.2 和VC++ 5.0 似乎未能支持"forward declaration of data structure class"(但是我怀疑VC++ 怎么会走退步?是不是有什么选项 可以设定)。无论如何,只要将CStroke 的声明搬移到SCRIBBLEDOC.H 的最前面, 然后再接续CScribbleDoc 的声明,即可顺利编译。请阅读本书第8章「CScribbleDoc 函数库,诸如COMDLG32.LIB 和TH32.LIB。 很快地,在稍后的范例程序¡ §Generic¡ ¨ 的makefile 中,你就可以清楚看到联结时期所需 的各式各样函数库(以及各种联结器选项)。 需要什么头文件(.H) 所有Windows 程序都必须包含WINDOWS.H。早期这是一个巨大的头文件,大约有5000 行左右,Visual C++ 4.0 已把它切割为各个较小的文件,但还以WINDOWS0 码力 | 1009 页 | 11.08 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程通常都是一些可以内联的函数,数学计 算表达式之类的,一个个加上太累了,所以产生了这个 需求。 • 不过必须指定 --expt-relaxed-constexpr 这个选项才能 用这个特性,我们可以用 CMake 的生成器表达式来实 现只对 .cu 文件开启此选项(不然给到 gcc 就出错 了)。 • 当然, constexpr 里没办法调用 printf ,也不能用 __syncthreads 之类的 __fdividef(x, y) 提供更快的浮点除法 ,和一般的除法有相同的精确度,但是在 2^216 < y < 2^218 时会得到错误的结果。 编译器选项: --use_fast_math • 如果开启了 --use_fast_math 选项,那么所有对 sinf 的调用都会自动被替换成 __sinf 。 • --ftz=true 会把极小数 (denormal) 退化为 0 。 • --prec-div=false0 码力 | 142 页 | 13.52 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化__restrict 让编译器放心做 SIMD 优化外,还可以用 OpenMP 的这条指令: 来迫使编译器无视指针别名的问题,并启用 SIMD 优化。不过你得给编译器打开 - fopenmp 这个选项。 循环中的矢量化:编译器提示忽略指针别名 • 除了可以用 __restrict , #pragma omp simd 外,对于 GCC 编译器还可以用: • #pragma GCC ivdep 为什么放弃优化?因为编译器害怕 b = 0 。 解决方案 1 :手动优化 乘法比除法更快!提前计算好 b 的 倒数避免重复求除法。 解决方案 2 : -ffast-math -ffast-math 选项让 GCC 更大胆地尝试浮点 运算的优化,有时能带来 2 倍左右的提升。 作为代价,他对 NaN 和无穷大的处理,可 能会和 IEEE 标准(腐朽的)规定的不一致 。 如果你能保证,程序中永远不会出现0 码力 | 108 页 | 9.47 MB | 1 年前3
现代C++ 教程:高速上手C++11/14/17/20但未来某个时间点上一定能观察到 x 为 4 的情况 内存顺序 为了追求极致的性能,实现各种强度要求的一致性,C++11 为原子操作定义了六种不同的内存顺序 std::memory_order 的选项,表达了四种多线程间的同步模型: 1. 宽松模型:在此模型下,单个线程内的原子操作都是顺序执行的,不允许指令重排,但不同线程间 原子操作的顺序是任意的。类型通过 std::memory_order_relaxed x 的 写操作,线程 B 仅依赖其中第三次 x 的写操作,与 x 的前两次写行为无关,则当 A 主动 x.release() 时候(即使用 std::memory_order_release),选项 std::memory_order_consume 能够确保 B 在 调用 x.load() 时候观察到 A 中第三次对 x 的写操作。我们来看一个例子: // 初始化为 nullptr 防止 确保了它之前的写操作不会发生在释放操作之后,是一 个向后的屏障(backward),而 std::memory_order_acquire 确保了它之前的写行为不会发生在 该获取操作之后,是一个向前的屏障(forward)。对于选项 std::memory_order_acq_rel 而言,则 结合了这两者的特点,唯一确定了一个内存屏障,使得当前线程对内存的读写不会被重排并越过此 操作的前后: 我们来看一个例子: std::vector0 码力 | 83 页 | 2.42 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串• cout 这么方便,能不能让他不要直接输出到控制台,而是把结果存到一个字 符串呢?这正是字符串流 stringstream 的作用。 • 和 cout 完全一样,同样的 << 和 hex 选项。 • 但是他的输出会保存到一个字符串里。 • 调用成员函数 .str() 就能取出这个字符串了。 • 之后这个字符串就可以用作其他用途,比如 printf 打印,或者用于查询数据库,都没问题。 cin ,用 >> 即可。 • 总结: • << 可以模仿 cout ,取代 to_string 。 • >> 可以模仿 cin ,取代 stoi/stof/stod 。 • 最重要的是他支持各种控制选项(如 hex ), 功能性比 to_string 和 stoi 更强大。 • 要导入他,只需 #include即可。 字符串常用操作 第 6 章 at 获取指定位置的字符 0 码力 | 162 页 | 40.20 MB | 1 年前3
Hello 算法 1.0.0b4 C++版元,则收银员需要给我们找 31 元。他会很自然地完成以下思考: 1. 可选项是比 31 元面值更小的货币,包括 1 , 5 , 10 , 20 元。 2. 从可选项中拿出最大的 20 元,剩余 31 − 20 = 11 元。 3. 从剩余可选项中拿出最大的 10 元,剩余 11 − 10 = 1 元。 4. 从剩余可选项中拿出最大的 1 元,剩余 1 − 1 = 0 元。 5. 完成找零,方案为 ‧ 子问题的解无需合并:二分查找旨在查找一个特定元素,因此不需要将子问题的解进行合并。当子问题 得到解决时,原问题也会同时得到解决。 分治能够提升搜索效率,本质上是因为暴力搜索每轮只能排除一个选项,而分治搜索每轮可以排除一半选 项。 12. 分治 hello‑algo.com 233 基于分治实现二分 在之前的章节中,二分查找是基于递推(迭代)实现的。现在我们基于分治(递归)来实现它。0 码力 | 343 页 | 27.39 MB | 1 年前3
Hello 算法 1.1.0 C++ 版元,则收银员需要找我们 31 元。他 会很自然地完成如图 1‑3 所示的思考。 1. 可选项是比 31 元面值更小的货币,包括 1 元、5 元、10 元、20 元。 2. 从可选项中拿出最大的 20 元,剩余 31 − 20 = 11 元。 3. 从剩余可选项中拿出最大的 10 元,剩余 11 − 10 = 1 元。 4. 从剩余可选项中拿出最大的 1 元,剩余 1 − 1 = 0 元。 5. 完成找零,方案为 ‧ 子问题的解无须合并:二分查找旨在查找一个特定元素,因此不需要将子问题的解进行合并。当子问题 得到解决时,原问题也会同时得到解决。 分治能够提升搜索效率,本质上是因为暴力搜索每轮只能排除一个选项,而分治搜索每轮可以排除一半选 项。 1. 基于分治实现二分查找 在之前的章节中,二分查找是基于递推(迭代)实现的。现在我们基于分治(递归)来实现它。 第 12 章 分治 hello‑algo0 码力 | 379 页 | 18.47 MB | 1 年前3
共 13 条
- 1
- 2













