 C++高性能并行编程与优化 -  课件 - 08 CUDA 开启的 GPU 编程(managed) ,只需把 cudaMalloc 换成 cudaMallocManaged 即可,释放时也是通过 cudaFree 。这样 分配出来的地址,不论在 CPU 还是 GPU 上都是一模一样的,都可以访问。而 且拷贝也会自动按需进行(当从 CPU 访 问时),无需手动调用 cudaMemcpy ,大 大方便了编程人员,特别是含有指针的一 些数据结构。 注意不要混淆 • 主机内存 寄存器读写的速度就和一级缓存 一样,相对而言低效了。若一级缓存还装不下,那会打翻到所有 SM 共用的二级缓存。 • 此外,如果在线程局部分配一个数组,并通过动态下标访问(例如遍历 BVH 时用到的模 拟栈),那无论如何都是会打翻到一级缓存的,因为寄存器不能动态寻址。 • 对于 Fermi 架构来说,每个线程最多可以有 63 个寄存器(每个有 4 字节)。 https://developer 结论:对于使用寄存器较少、访存为主的核函数(例如矢量加法),使用大 blockDim 为 宜。反之(例如光线追踪)使用小 blockDim ,但也不宜太小。 经典案例:矩阵转置 • 为什么需要多维?直接手动求模运算获取 x , y 坐标不行吗?看右边这个例子。 • 回顾一下:我们第七课讲过, CPU 上的 并行 for ,通常会做循环分块提升缓存局 域性。但是如果我们是传统的两层的 for 循环就低效了,对于矩阵转置这种需要0 码力 | 142 页 | 13.52 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 08 CUDA 开启的 GPU 编程(managed) ,只需把 cudaMalloc 换成 cudaMallocManaged 即可,释放时也是通过 cudaFree 。这样 分配出来的地址,不论在 CPU 还是 GPU 上都是一模一样的,都可以访问。而 且拷贝也会自动按需进行(当从 CPU 访 问时),无需手动调用 cudaMemcpy ,大 大方便了编程人员,特别是含有指针的一 些数据结构。 注意不要混淆 • 主机内存 寄存器读写的速度就和一级缓存 一样,相对而言低效了。若一级缓存还装不下,那会打翻到所有 SM 共用的二级缓存。 • 此外,如果在线程局部分配一个数组,并通过动态下标访问(例如遍历 BVH 时用到的模 拟栈),那无论如何都是会打翻到一级缓存的,因为寄存器不能动态寻址。 • 对于 Fermi 架构来说,每个线程最多可以有 63 个寄存器(每个有 4 字节)。 https://developer 结论:对于使用寄存器较少、访存为主的核函数(例如矢量加法),使用大 blockDim 为 宜。反之(例如光线追踪)使用小 blockDim ,但也不宜太小。 经典案例:矩阵转置 • 为什么需要多维?直接手动求模运算获取 x , y 坐标不行吗?看右边这个例子。 • 回顾一下:我们第七课讲过, CPU 上的 并行 for ,通常会做循环分块提升缓存局 域性。但是如果我们是传统的两层的 for 循环就低效了,对于矩阵转置这种需要0 码力 | 142 页 | 13.52 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 10 从稀疏数据结构到量化数据类型C 语言 % 的特色:负数 • 7 % 4 = 3 • -7 % 4 = -3 • 也就是说 a % b 如果 a 是负数,则得到的模也是负数。 Python 的 % 就没问题 • 7 % 4 = 3 • -7 % 4 = 1 • Python 的模运算 a % b 的值始终是 [0, b) 区间内的正数,非常方便。 对稀疏数据结构造成的问题 • 如果这里的 x 是负数,则 x % 是常数且为 2 的幂次方,编译器会检测到, 并替换为更高效的位运算,反而减少了计算量。 • 此外如果 b 一定是 2 的幂次方,那么 (unsigned)a % b 也可以(先转换成无符号的取模)。 高效的解决:位运算 & • 如果 b 是 2 的幂次方,即: 2, 4, 8, 16, 32 等 。 • 则: a % b = a & (b - 1) • 比如 a % 8 可以改成 a0 码力 | 102 页 | 9.50 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 10 从稀疏数据结构到量化数据类型C 语言 % 的特色:负数 • 7 % 4 = 3 • -7 % 4 = -3 • 也就是说 a % b 如果 a 是负数,则得到的模也是负数。 Python 的 % 就没问题 • 7 % 4 = 3 • -7 % 4 = 1 • Python 的模运算 a % b 的值始终是 [0, b) 区间内的正数,非常方便。 对稀疏数据结构造成的问题 • 如果这里的 x 是负数,则 x % 是常数且为 2 的幂次方,编译器会检测到, 并替换为更高效的位运算,反而减少了计算量。 • 此外如果 b 一定是 2 的幂次方,那么 (unsigned)a % b 也可以(先转换成无符号的取模)。 高效的解决:位运算 & • 如果 b 是 2 的幂次方,即: 2, 4, 8, 16, 32 等 。 • 则: a % b = a & (b - 1) • 比如 a % 8 可以改成 a0 码力 | 102 页 | 9.50 MB | 1 年前3
 Zadig 产品使用手册有保障、横向赋能、技能提升 随时调用工程基线提供的能力、 产品视角开发交付、团队高效协 同、稳定迭代 产研数字化过程数据透明、关键 指标易抽取、有能力合理调动资 源、随时决策响应客户需求 碎片化 研 发模 式 产研全流程拉通需求到上线所需的代码、服务、配置和数据的一致性交付 Jira 飞书 项管 其他 自测 环境 Argo K8s JFrog YAML 产品 开 发 测 试 运维 腾 讯 P C G / T E G 、 字 节 跳 动 、 小 红 书 等 。 专 注 在 云 原 生 C I / C D 、 D e v O p s 、 平 台 工 程 架 构 等 大 规 模 软 件 研 发 的 基 础 工 程 领 域 的 研 究 和 应 用 。 主 导 研 发 的 Z a d i g 开 源 D e v O p s 软 件 工 程 平 台 已 被 2 0 00 码力 | 52 页 | 22.95 MB | 1 年前3 Zadig 产品使用手册有保障、横向赋能、技能提升 随时调用工程基线提供的能力、 产品视角开发交付、团队高效协 同、稳定迭代 产研数字化过程数据透明、关键 指标易抽取、有能力合理调动资 源、随时决策响应客户需求 碎片化 研 发模 式 产研全流程拉通需求到上线所需的代码、服务、配置和数据的一致性交付 Jira 飞书 项管 其他 自测 环境 Argo K8s JFrog YAML 产品 开 发 测 试 运维 腾 讯 P C G / T E G 、 字 节 跳 动 、 小 红 书 等 。 专 注 在 云 原 生 C I / C D 、 D e v O p s 、 平 台 工 程 架 构 等 大 规 模 软 件 研 发 的 基 础 工 程 领 域 的 研 究 和 应 用 。 主 导 研 发 的 Z a d i g 开 源 D e v O p s 软 件 工 程 平 台 已 被 2 0 00 码力 | 52 页 | 22.95 MB | 1 年前3
 Zadig 面向开发者的云原生 DevOps 平台r i t + Z a d i g 方 案 二 : G i t l a b + Z a d i g 非 核 心 服 务 : 采 用 单 分 支 模 型 m a s t e r 发 版 。 核 心 服 务 : 采 用 双 分 支 模 型 : m a s t e r 发 版 测 试 环 境 和 o n l i n e 发 版 生 产 环 境 。 字节跳动 - 飞书场景一:主干开发主干发布0 码力 | 59 页 | 81.43 MB | 1 年前3 Zadig 面向开发者的云原生 DevOps 平台r i t + Z a d i g 方 案 二 : G i t l a b + Z a d i g 非 核 心 服 务 : 采 用 单 分 支 模 型 m a s t e r 发 版 。 核 心 服 务 : 采 用 双 分 支 模 型 : m a s t e r 发 版 测 试 环 境 和 o n l i n e 发 版 生 产 环 境 。 字节跳动 - 飞书场景一:主干开发主干发布0 码力 | 59 页 | 81.43 MB | 1 年前3
 C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 的指针才能调用 Derived 的拷贝 构造函数 Derived(Derived const &) 。 CRTP (Curiously Recurring Template Pattern / 奇异递归模板模 式 ) • 形如 struct Derived : Base C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 的指针才能调用 Derived 的拷贝 构造函数 Derived(Derived const &) 。 CRTP (Curiously Recurring Template Pattern / 奇异递归模板模 式 ) • 形如 struct Derived : Base- {}; • 基类模板参数包含派生类型的,这种就是传说中的 CRTP 。包含派生类型是为了能调用派 生类的某些函数(我们这个例子中是拷贝构造函数)。 0 码力 | 54 页 | 3.94 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 01 学 C++ 从 CMake 学起如果能够只写一遍,然后自动插入到需要用 hello 的那些 .cpp 里就好了…… 头文件 - 批量插入几行代码的硬核方式 • 没错, C 语言的前辈们也想到了,他们说,既然每个 .cpp 文件的这个部分是一模一样的 ,不如我把 hello() 的声明放到单独一个文件 hello.h 里,然后在需要用到 hello() 这个声 明的地方,打上一个记号, #include “hello.h” 。然后用一个小程序,自动在编译前把引号0 码力 | 32 页 | 11.40 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 01 学 C++ 从 CMake 学起如果能够只写一遍,然后自动插入到需要用 hello 的那些 .cpp 里就好了…… 头文件 - 批量插入几行代码的硬核方式 • 没错, C 语言的前辈们也想到了,他们说,既然每个 .cpp 文件的这个部分是一模一样的 ,不如我把 hello() 的声明放到单独一个文件 hello.h 里,然后在需要用到 hello() 这个声 明的地方,打上一个记号, #include “hello.h” 。然后用一个小程序,自动在编译前把引号0 码力 | 32 页 | 11.40 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 03 现代 C++ 进阶:模板元编程你知道吗?函数可以作为另一个函数的参数! 函数也是对象:函数式编程(续) • 而且,这个作为参数的函数也可以有参数! 函数式编程:函数作为模板类型 • 甚至可以直接将 func 的类型作为一个模 板参数,从而不需要写 void(int) 。 • 这样还会允许函数的参数类型为其他类型 ,比如 void(float) 。 • 这样 call_twice 会自动对每个不同的 func 类型编译一遍,从而允许编译器更好0 码力 | 82 页 | 12.15 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 03 现代 C++ 进阶:模板元编程你知道吗?函数可以作为另一个函数的参数! 函数也是对象:函数式编程(续) • 而且,这个作为参数的函数也可以有参数! 函数式编程:函数作为模板类型 • 甚至可以直接将 func 的类型作为一个模 板参数,从而不需要写 void(int) 。 • 这样还会允许函数的参数类型为其他类型 ,比如 void(float) 。 • 这样 call_twice 会自动对每个不同的 func 类型编译一遍,从而允许编译器更好0 码力 | 82 页 | 12.15 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 14 C++ 标准库系列课 - 你所不知道的 set 容器那如果我确实需要让 set 迭 代器向前移动 3 格怎么办? • 可以调用三次 ++ 运算,实 现和 + 3 同样的效果。 • vector 迭代器的 + n 复杂度 是 O(1) 。而 set 迭代器模 拟出来的 + n 复杂度为 O(n) 。虽然低效,但至少可 以用了。 std::next 等价于 + • 但是这样手写三个 ++ 太麻烦了 ,而且是就地操作,会改变迭代 器本身。 • 因此标准库提供了0 码力 | 83 页 | 10.23 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 14 C++ 标准库系列课 - 你所不知道的 set 容器那如果我确实需要让 set 迭 代器向前移动 3 格怎么办? • 可以调用三次 ++ 运算,实 现和 + 3 同样的效果。 • vector 迭代器的 + n 复杂度 是 O(1) 。而 set 迭代器模 拟出来的 + n 复杂度为 O(n) 。虽然低效,但至少可 以用了。 std::next 等价于 + • 但是这样手写三个 ++ 太麻烦了 ,而且是就地操作,会改变迭代 器本身。 • 因此标准库提供了0 码力 | 83 页 | 10.23 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 11 现代 CMake 进阶指南如果父模块里本来就定义了同名变量,则离开子模块后仍保持父模块原来设置的值。 如果子模块需要向父模块里传变量怎么办? • 可以用 set 的 PARENT_SCOPE 选项,把一个变量传递到上一层作用域(也就是父模 块)。 如果子模块需要向父模块里传变量怎么办? • 如果父模块里没有定义 MYVAR 的话,也可以用缓存变量向外部传变量(不推荐)。但是 这样就不光父模块可见了,父模块的父模块,到处都可见。0 码力 | 166 页 | 6.54 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 11 现代 CMake 进阶指南如果父模块里本来就定义了同名变量,则离开子模块后仍保持父模块原来设置的值。 如果子模块需要向父模块里传变量怎么办? • 可以用 set 的 PARENT_SCOPE 选项,把一个变量传递到上一层作用域(也就是父模 块)。 如果子模块需要向父模块里传变量怎么办? • 如果父模块里没有定义 MYVAR 的话,也可以用缓存变量向外部传变量(不推荐)。但是 这样就不光父模块可见了,父模块的父模块,到处都可见。0 码力 | 166 页 | 6.54 MB | 1 年前3
 C++高性能并行编程与优化 -  课件 - 15 C++ 系列课:字符与字符串获取字符串长度有两种写法…… • 有两种写法, s.length() 和 s.size() 等价。 • 其中 size 是和 vector 一样的名字,方便程序员理解。 • 但是为什么标准委员会还要发明一个一模一样的 length ? • 小彭老师只能说是“孔乙己直呼内行”了。 substr 切下一段子字符串 • 函数原型为: • string substr(size_t pos = 0, size_t0 码力 | 162 页 | 40.20 MB | 1 年前3 C++高性能并行编程与优化 -  课件 - 15 C++ 系列课:字符与字符串获取字符串长度有两种写法…… • 有两种写法, s.length() 和 s.size() 等价。 • 其中 size 是和 vector 一样的名字,方便程序员理解。 • 但是为什么标准委员会还要发明一个一模一样的 length ? • 小彭老师只能说是“孔乙己直呼内行”了。 substr 切下一段子字符串 • 函数原型为: • string substr(size_t pos = 0, size_t0 码力 | 162 页 | 40.20 MB | 1 年前3
共 10 条
- 1













