C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串size_t find(string_view sv, size_t pos) const noexcept; • 为什么我看官方文档上没写?标准库头文件里也没看到? • 其实是有的,只不过官方为了让头文件不依赖于 头 文件,把他们写成了模板,并利用类似 SFINAE 的机制给模板参数类型的设 了一些限制(相当于把 string_view 定义为一个 concept )。 小彭老师学到了黑科技 • 这一黑科技在 zeno 中也有运用。例如 zeno/utils/Translator.h 中,为了让 Translator 类不依赖于 头文件(这是 Qt 的),但又能接受 QString 作为参数。具体来说是使用 SFINAE ,检测了 S 类型是否具有 fromStdString 和 toStdString 这两个函数。 string_view 码表,建立了英文字母和标点 符号到 0x00~0x7F 的一一映射。 • 后来计算机普及到世界各地,问题来了:并不是所有 国家都说英语!例如拉丁语也是由字母构成,好在当 年 ASCII 只占用了 0x00~0x7F 的部分,而一个字 节( char 类型)可以表示的范围是 0x00~0xFF , 因此只需把这 0x80~0xFF 的部分映射为拉丁字母和 其他标点符号等等,这就是后来的“扩展 ASCII 0 码力 | 162 页 | 40.20 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅趋向于无穷时的时间复杂度来衡量,比如 O(n/c) 应该变成 O(1) 。 映射( map ) 1 个线程,独自处理 8 个元素的映射,花了 8 秒 用电量: 1*8=8 度电 结论:串行映射的时间复杂度为 O(n) ,工作复杂度为 O(n) ,其中 n 是元素个数 并行映射 4 个线程,每人处理 2 个元素的映射,花了 2 秒 用电量: 4*2=8 度电 结论:并行映射的时间复杂度为 O(n/c) ,工作复杂度为 O(n) bm) • 里面即可。他会自动决定要重复多少次, 保证结果是准确的,同时不浪费太多时间 。 运行结果 刚才的 BENCHMARK_MAIN 自动生成了一个 main 函数 ,从而生成一个可执行文件供你运行。运行后会得到测试 的结果打印在终端上。 命令行参数 他还接受一些命令行参数来控制测试的输出格式为 csv 等等,你可以调用 --help 查看更多用法。 CMake 中使用: find_package0 码力 | 116 页 | 15.85 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针位计算机的寄存器能处理 64 位的整数,实际上的内存地址并没有 64 位。 • 实际上地址的高 16 位始终和第 48 位一致(符号扩展),也就是虚拟地址空间只有 48 位。 • 而经过 MMU 映射后实际给内存的地址只有 39 位,因此如今的 x64 架构实际上只能访 问 512GB 内存,如果插了超过这个大小的内存条他也不会认出来。 • 此外, 16 位计算机实际上能通过额外的段寄存器访问到 int 甚至可以是 16 位的!只不过主流操作系统一致认为是 32 位的而已,并不是标准所保 证的。 • 为了解决不同操作系统上对类型定义混乱的问题, C 语言标准引入了 stdint.h 这个头文件 。 • 他里面包含一系列类型别名 (typedef) ,这些别名保证不论是什么操作系统什么架构,都是 固定的大小,例如: • typedef char int8_t; • typedef 传一个空指针,就表示“用户不想指定 这个参数”的意思。 C++ 可以用更安全的 func(std::optionalpars) 来替代。 NULL 的定义为什么是这样的? • 如果你看过标准库的头文件内容,会看到 NULL 的 本质无非是一个宏。那为什么要这样定义呢? • 可见他在 C++ 中会直接定义为常数 0 ,而 C 语言 中却定义为 ((void*)0) ,为什么会区别对待? • 0 码力 | 128 页 | 2.95 MB | 1 年前3
Borsh 安全高效的二进制序列化Object Representation Serializer for Hashing • 字节级别确定性 • 执行速度快 Borsh • 轻量级 • 每一个对象与其二进制表示之间都存在一个双射映射 • 不同的对象的二进制表示一定不同 • 便于基于二进制表示进行 Hash 字节级别确定性 • 在 Rust 中, borsh 并没有使用 serde • 全部逻辑原生实现 • 序列化、反序列化速度大幅领先其他解决方案0 码力 | 21 页 | 3.35 MB | 1 年前3
新一代分布式高性能图数据库的构建 - 沈游人设别出带有某种共同特征 的企业或个人群体 舆情传导 营销传导 风险传导 … 计算某个事件在关联的企业、个人 之间的传递过程和传递概率 图深度学习及其应用场景 图嵌入 • 将高维的图信息映射到低维向量中 • 通过图嵌入将客户关系表示为低维向量,可以结合其 他客户行为特征进行机器学习训练 图卷积神经网络 • 对图结构数据进行卷积计算 • 通过已有的企业数据,通过 GCN 进行半监督学习和分0 码力 | 38 页 | 24.68 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 13 C++ STL 容器全解之 vector值得注意的是, [] 运算符在索引超出数组大 小时并不会直接报错,这是为了性能的考虑。 • 如果你不小心用 [] 访问了越界的索引,可能 会覆盖掉别的变量导致程序行为异常,或是访 问到操作系统未映射的区域导致奔溃。 • int &operator[](size_t i) noexcept; • int const &operator[](size_t i) const noexcept;0 码力 | 90 页 | 4.93 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 16 现代 CMake 模块化项目管理指南com/263032155 找不到头文 件怎么办呀 CMake Cookbook 小彭老师建议 : ~~-·~·~-·~ -~·-·~·- 第一章:文件 / 目录组织规范 基于 CMake 的 C/C++ 项目,如何优雅地、模块化地组织大量源文件 ? 推荐的目录组织方式 • 目录组织格式: • 项目名 /include/ 项目名 / 模块名 .h • 项目名 /src/ 模块名 .cpp ries( 项目名 PUBLIC include) • 源码文件中写: • #include < 项目名 / 模块名 .h> • 项目名 :: 函数名 (); 完整案例请看源码仓库: https://github.com/parallel101/course/tree/master/16/00 推荐的目录组织方式 • 头文件(项目名 /include/ 项目名 / 模块名 .h )中写: )中写: • #pragma once • namespace 项目名 { • void 函数名 (); • } • 实现文件(项目名 /src/ 模块名 .cpp )中写: • #include < 项目名 / 模块名 .h> • namespace 项目名 { • void 函数名 () { 函数实现 } • } 完整案例请看源码仓库: https://github.com/pa0 码力 | 56 页 | 6.87 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 01 学 C++ 从 CMake 学起a.out 这个文件中,(称为可执行文件)。 • > ./a.out • 之后执行该命令,操作系统会读取刚刚生成的可执行文件,从而执行其中编译成机器码, 调用系统提供的 printf 函数,并在终端显示出 Hello, world 。 厂商 C C++ Fortran GNU gcc g++ gfortran LLVM clang clang++ flang 多文件编译与链接 • 单文件编译虽然方便,但也有如下缺点: 单文件编译虽然方便,但也有如下缺点: 1. 所有的代码都堆在一起,不利于模块化和理解。 2. 工程变大时,编译时间变得很长,改动一个地方就得全部重新编译。 • 因此,我们提出多文件编译的概念,文件之间通过符号声明相互引用。 • > 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 ) • 文件越来越多时,一个个调用 g++ 编译链接会变得很麻烦。 • 于是,发明了 make 这个程序,你只需写出不同文件之间的依赖关系,和生成各文件的规则。 • > make a.out •0 码力 | 32 页 | 11.40 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 11 现代 CMake 进阶指南项目的构建分为两步: • 第一步是 cmake -B build ,称为配置阶段( configure ),这时只检测环境并生成构建规则 • 会在 build 目录下生成本地构建系统能识别的项目文件( Makefile 或是 .sln ) • 第二步是 cmake --build build ,称为构建阶段( build ),这时才实际调用编译器来编译代码 • 在配置阶段可以通过 -D 设置缓存变量。第二次配置时,之前的 现在只需要写一次 CMakeLists.txt ,他会视不同的操作系统,生成不同构建系统的规则文件。 • 那个和操作系统绑定的构建系统( make 、 MSBuild )称为本地构建系统( native buildsystem )。 • 负责从 CMakeLists.txt 生成本地构建系统构建规则文件的,称为生成器( generator )。 -G 选项:指定要用的生成器 • Linux 启动时会把每个文件都检测一遍, 浪费很多时间。特别是有很多文件,但是实 际需要构建的只有一小部分,从而是 I/O Bound 的时候, Ninja 的速度提升就很明 显。 然而某些专利公司的 CUDA toolkit 在 Windows 上只允许用 MSBuild 构建,不能 用 Ninja (怕不是和 Bill Gates 有什么交 易) 第 1 章:添加源文件 一个 .cpp 源文件用于测试0 码力 | 166 页 | 6.54 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化写,即函数链接表。链接器会查找其他 .o 文件中是否定义了 _Z5otheri 这个符号, 如果定义了则把这个 @PLT 替换为他的地 址。 对 PLT 感兴趣?看 https://www.cnblogs.com/pannengzhi/p/2018-04-09-about-got-plt.html 编译器优化: call 变 jmp 多个函数定义在同一个文件中 如果 _Z5otheri 定义在同一个文件中,编 译器会直接调用,没有 译器会直接调用,没有 @PLT 表示未定义 对象。减轻了链接器的负担。 编译器优化:内联化 只有定义在同一个文件的函数可以被内联 !否则编译器看不见函数体里的内容怎么 内联呢? 为了效率我们可以尽量把常用函数定义在 头文件里,然后声明为 static 。这样调用 他们的时候编译器看得到他们的函数体, 从而有机会内联。 内联:当编译器看得到被调用函数( other )实现的时候 ,会直接把函数实现贴到调用他的函数( 给其 他文件,而且 func 也已经内联了 other , 所以编译器干脆不定义 other 了。 inline 关键字?不需要! 编译的结果完全一致? 结论:在现代编译器的高强度优化下,加不加 inline 无所谓 编译器不是傻子,只要他看得见 other 的函数体定义,就会自动内联 内联与否和 inline 没关系,内联与否只取决于是否在同文件,且函数体够小 要性能的,定义在头文件声明为 static0 码力 | 108 页 | 9.47 MB | 1 年前3
共 23 条
- 1
- 2
- 3













