C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程当前板块的编号: blockIdx • 总的板块数量: gridDim • 线程 (thread) :并行的最小单位 • 板块 (block) :包含若干个线程 • 网格 (grid) :指整个任务,包含若干个板块 • 从属关系:线程<板块<网格 • 调用语法: <<>> 区分板块和线程有点麻烦?“扁平化”他们! • 你可能觉得纳闷,既然已经有线程可以并行了 小技巧:网格跨步循环( grid-stride loop ) • 无论调用者指定了多少个线程 ( blockDim ),都能自动根据给定的 n 区间循环,不会越界,也不会漏掉几个元 素。 • 这样一个 for 循环非常符合 CPU 上常见 的 parallel for 的习惯,又能自动匹配不同 的 blockDim ,看起来非常方便。 从线程到板块 • 核函数内部,用之前说到的 核函数内部,用之前说到的 blockDim.x + blockIdx.x + threadIdx.x 来获取线程在整个 网格中编号。 • 外部调用者,则是根据不同的 n 决定板块的 数量( gridDim ),而每个板块具有的线程 数量( blockDim )则是固定的 128 。 • 因此,我们可以用 n / 128 作为 gridDim , 这样总的线程数刚好的 n ,实现了每个线程 负责处理一个元素。 0 码力 | 142 页 | 13.52 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化通常来说,并行只能加速计算的部分,不能加速内存读写的部分 。 • 因此,对 fill 这种没有任何计算量,纯粹只有访存的循环体,并 行没有加速效果。称为内存瓶颈( memory-bound )。 • 而 sine 这种内部需要泰勒展开来计算,每次迭代计算量很大的 循环体,并行才有较好的加速效果。称为计算瓶颈( cpu- bound )。 • 并行能减轻计算瓶颈,但不减轻内存瓶颈,故后者是优化的重点 。 浮点加法的计算量 可见数据量较小时,实际带宽甚至超过了 理论带宽极限 42672 MB/s ! • 而数据量足够大时, 才回落到正常的带宽 。 • 这是为什么? CPU 内部的高速缓存 • 原来 CPU 的厂商早就意识到了内存延迟高,读写效率低 下的问题。因此他们在 CPU 内部引入了一片极小的存储 器——虽然小,但是读写速度却特别快。这片小而快的 存储器称为缓存( cache )。 • 当 CPU 访问某个地址时,会先查找缓存中是否有对应的 MyClass 内部是 SOA ,而外部仍是一个 vector的 AOS—— 这种内存布局称为 AOSOA 。 • 缺点是必须保证数量是 1024 的整数倍, 而且因为要两次指标索引,随机访问比较 烦。 • 这里的 1024 并非随意选取,而是要让每 个属性 SOA 数组的大小为一个页 ( 4KB )才能最高效,原因稍后会说明。 AOSOA :注意,内部 SOA 0 码力 | 147 页 | 18.88 MB | 1 年前3
Hello 算法 1.0.0b4 C++版11111111(补码) = 10000000(补码) = −128 3. 数据结构 hello‑algo.com 43 你可能已经发现,上述的所有计算都是加法运算。这暗示着一个重要事实:计算机内部的硬件电路主要是基 于加法运算设计的。这是因为加法运算相对于其他运算(比如乘法、除法和减法)来说,硬件实现起来更简 单,更容易进行并行化处理,从而提高运算速度。 然而,这并不意味着计算机只能做 个字节;如果字符串中有超出 BMP 的字符,那么 每个字符占用 4 个字节。 ‧ Go 语言的 string 类型在内部使用 UTF‑8 编码。Go 语言还提供了 rune 类型,它用于表示单个 Unicode 码点。 ‧ Rust 语言的 str 和 String 类型在内部使用 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以 public 中,这方面有什么考量吗?为什么要将 height() 函数和 updateHeight() 函数分别放在 public 和 private 中呢? 主要看方法的使用范围,如果方法只在类内部使用,那么就设计为 private 。例如,用户单独 调用 updateHeight() 是没有意义的,它只是插入、删除操作中的一步。而 height() 是访问结 点高度,类似于 vector0 码力 | 343 页 | 27.39 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型com/video/BV1fa411r7zp 课程 PPT 和代码: https://github.com/parallel101/course 本课涵盖:稀疏矩阵、 unordered_map 、空间稀 疏网格、位运算、浮点的二进制格式、内存带宽优 化 面向人群:图形学、 CFD 仿真、深度学习编程人 员 第 0 章:稀疏矩阵 稠密数组存储矩阵 用 foreach 包装一下枚举的过程 改用 map 按行压缩( Compressed Row Storage ) http://www.netlib.org/linalg/html_templates/node91.html 第 1 章:稀疏网格 稠密网格计算粒子经过的格点数量 改用更小的 char 存储 只用一个 bit 存储,一个 char 可以存储 8 个 bit 用 map 来存储 读取:如果不存在,则读到 0 写入:如果不存在,则创建该表项 块优化。 实际上空间局域 性正是稀疏网格 能够实现的一大 前提,稍后详细 讨论。 在 16x16 分块的基础上,只用一个 bit 存储 图片解释稀疏的好处 传统稠密二维数组 无边界稀疏分块哈希表 有了无边界的稀疏网格,再也不用担心二维数组要分配多大了。 坐标可以无限延伸,甚至可以是负数!比如 (-1,2) 等…… 他会自动在写入时分配 16x16 的子网格,称之为叶节点 (leaf node)0 码力 | 102 页 | 9.50 MB | 1 年前3
Hello 算法 1.1.0 C++ 版(反码) = 1000 0001 (补码) + 1111 1111 (补码) = 1000 0000 (补码) → −128 你可能已经发现了,上述所有计算都是加法运算。这暗示着一个重要事实:计算机内部的硬件电路主要是基 于加法运算设计的。这是因为加法运算相对于其他运算(比如乘法、除法和减法)来说,硬件实现起来更简 第 3 章 数据结构 hello‑algo.com 58 单,更容易进行并行化处理,运算速度更快。 占用 2 字节;如果有超出 BMP 的字 符,则每个字符占用 4 字节。 ‧ Go 语言的 string 类型在内部使用 UTF‑8 编码。Go 语言还提供了 rune 类型,它用于表示单个 Unicode 码点。 ‧ Rust 语言的 str 和 String 类型在内部使用 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 ArrayList 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。 Q:原码转补码的方法是“先取反后加 1”,那么补码转原码应该是逆运算“先减0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.0.0 C++版(反码) = 1000 0001 (补码) + 1111 1111 (补码) = 1000 0000 (补码) → −128 你可能已经发现了,上述所有计算都是加法运算。这暗示着一个重要事实:计算机内部的硬件电路主要是基 于加法运算设计的。这是因为加法运算相对于其他运算(比如乘法、除法和减法)来说,硬件实现起来更简 第 3 章 数据结构 hello‑algo.com 58 单,更容易进行并行化处理,运算速度更快。 占用 2 字节;如果有超出 BMP 的字 符,则每个字符占用 4 字节。 ‧ Go 语言的 string 类型在内部使用 UTF‑8 编码。Go 语言还提供了 rune 类型,它用于表示单个 Unicode 码点。 ‧ Rust 语言的 str 和 String 类型在内部使用 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 ArrayList 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。 66 第 4 章 数组与链表 � 数据结构的世界如同一堵厚实的砖墙。0 码力 | 378 页 | 17.59 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 态的虚函数,这就是被小彭老师称为自动 虚克隆 (auto-vitrual-clone) 的大法。 Zeno 中对 OpenVDB 对象的封装 • 开源的体积数据处理库 OpenVDB 中有许多“网格”的类(可以理解为多维数组),例如: • openvdb::Vec3fGrid , FloatGrid , Vec3IGrid , IntGrid , PointsDataGrid • 我们并不 之类的任意表达式,只要语义上通过,就可以实例化。 • (把 sort 封装成虚函数,留作回家作业) Zeno 中对 OpenVDB 的类型擦除 • 结合类型擦除技术,自动虚克隆技术。 • VDBGrid 作为所有网格类的基类提供各个 操作做为虚函数, VDBGridWrapper 则是 那个实现了擦除的包装类。 Zeno 节点系统 • 节点在 Zeno 中所扮演的角色,实际上相当于函数式编程中的函数。 lambda 的妙用 • 小彭老师小技巧: • []{ xxx; yyy; return zzz; }() • 可以在表达式层面里插入一个语句块,本 质上是立即求值的 lambda 表达式(内部 是分号级别,外部是逗号级别)。 • 在函数体内也可以这样: • [&]{ xxx; yyy; return zzz; }() • 来在语句块内使用外部的局部变量。 带有构造函数和解构函数的类0 码力 | 54 页 | 3.94 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版(反码) = 1000 0001 (补码) + 1111 1111 (补码) = 1000 0000 (补码) → −128 你可能已经发现了,上述所有计算都是加法运算。这暗示着一个重要事实:计算机内部的硬件电路主要是基 于加法运算设计的。这是因为加法运算相对于其他运算(比如乘法、除法和减法)来说,硬件实现起来更简 第 3 章 数据结构 www.hello‑algo.com 58 单,更容易进行并行化处理,运算速度更快。 占用 2 字节;如果有超出 BMP 的字 符,则每个字符占用 4 字节。 ‧ Go 语言的 string 类型在内部使用 UTF‑8 编码。Go 语言还提供了 rune 类型,它用于表示单个 Unicode 码点。 ‧ Rust 语言的 str 和 String 类型在内部使用 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 ArrayList 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。 Q:原码转补码的方法是“先取反后加 1”,那么补码转原码应该是逆运算“先减0 码力 | 379 页 | 18.48 MB | 10 月前3
Hello 算法 1.0.0b5 C++版(反码) = 1000 0001 (补码) + 1111 1111 (补码) = 1000 0000 (补码) → −128 你可能已经发现,上述的所有计算都是加法运算。这暗示着一个重要事实:计算机内部的硬件电路主要是基 于加法运算设计的。这是因为加法运算相对于其他运算(比如乘法、除法和减法)来说,硬件实现起来更简 第 3 章 数据结构 hello‑algo.com 56 单,更容易进行并行化处理,运算速度更快。 个字节;如果字符串中有超出 BMP 的字符,那么 每个字符占用 4 个字节。 ‧ Go 语言的 string 类型在内部使用 UTF‑8 编码。Go 语言还提供了 rune 类型,它用于表示单个 Unicode 码点。 ‧ Rust 语言的 str 和 String 类型在内部使用 UTF‑8 编码。Rust 也提供了 char 类型,用于表示单个 Unicode 码点。 需要注意的是,以 public 中,这方面有什么考量吗?为什么要将 height() 函数和 updateHeight() 函数分别放在 public 和 private 中呢? 主要看方法的使用范围,如果方法只在类内部使用,那么就设计为 private 。例如,用户单独 调用 updateHeight() 是没有意义的,它只是插入、删除操作中的一步。而 height() 是访问结 点高度,类似于 vector0 码力 | 377 页 | 30.69 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 09 CUDA C++ 流体仿真实战迭代因为需要写入 pre 的同时读取 pre ,所以也要用双缓冲。 投影部分:计算未消除的散度 为了评估效果的好坏,额外加一个计算散度方差的核函数,看看是不是无散度(不可压缩流)了。 多重网格法 投影部分:多重网格实现 投影部分:红黑高斯 投影部分:计算残差 投影部分:缩小一倍 投影部分:清零数组 投影部分:扩大一倍 创建与导出 主函数:创建场景 导出 VDB :调用接口 导出 VDB 边界条件:添加判断边界的版本 边界条件:仅在第一层额外判断边界条件 进一步改进 VDB 导出:支持导出多个网格,并指定名称 进一步改进 VDB 导出: P-IMPL 模式 进一步改进 VDB 导出: F-IMPL 模式 Blender 渲染结果 改进 改进边界条件:外部边界流出而不是反弹,内部边界可以流出速度 Blender 中调整一下材质 Blender 中调整一下材质 改进对流:让烟雾随时间逐渐褪色0 码力 | 58 页 | 14.90 MB | 1 年前3
共 22 条
- 1
- 2
- 3













