C++高性能并行编程与优化 - 课件 - 04 从汇编角度看编译器优化
这种单个指令处理多个数据的技术称为 SIMD ( single-instruction multiple-data )。 • 他可以大大增加计算密集型程序的吞吐量。 • 因为 SIMD 把 4 个 float 打包到一个 xmm 寄存器里同时运算,很像数学中矢量的逐元 素加法。因此 SIMD 又被称为矢量,而原始的一次只能处理 1 个 float 的方式,则称为 标量。 • 在一定条件下,编译器能够把一个处理标量 :分离存储多个属性 SIMD 矢量化成功! 不符合面向对象编程 (OOP) 的习惯,但常常有利于性能。 又称之为面向数据编程 (DOP) 。 AOSOA :中间方案 SIMD 矢量化成功! 4 个对象一组打包成 SOA ,再用一 个 n / 4 大小的数组存储为 AOS 。 优点: SOA 便于 SIMD 优化; AOS 便于存储在传统容器; AOSOA 两者得兼!是王鑫磊的最 爱。 缺点:需要两层0 码力 | 108 页 | 9.47 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 03 现代 C++ 进阶:模板元编程
• 其实 lambda 还有更多语法,比如 mutable , [p = std::move(p)] 等…… 常用容器: tuple • std::tuple<...> 可以将多个不同类型的 值打包成一个。尖括号里填各个元素 的类型。 • 之后可以用 std::get<0> 获取第 0 个 元素, std::get<1> 获取第 1 个元素, 以此类推(从 0 开始数数)。 tuple tup; // 错误! • 对的,是两个与号 && 。 结构化绑定:还可以是任意自定义类! • 其实,结构化绑定不仅可以解包 std::tuple , 还可以解包任意用户自定义类: • 配合打包的 {} 初始化表达式,真是太便利了! • 惊不惊喜?意不意外? • 可惜 std::get 并不支持自定义类。 tuple :用于函数多个返回值 • std::tuple 可以用于有多个返回值的函数。0 码力 | 82 页 | 12.15 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming
内核中也用到多态,就是用函数指针实现的。 例如左图中的虚函数,和右边的函数指针版本等价。因此性能分析时,把虚函数视为函数 指针。 • 注:实际中虚函数往往有很多个,为了存储空间的高效利用,会把多个虚函数打包成一个数组,称之 为“虚函数表( vtable )”。这样一来,类成员里只需要存一个指向虚函数表首地址的指针,之后通过 查找该表即可找到连续的 n 个函数指针。此处为了方便理解,右侧案例代码没有用虚函数表。0 码力 | 47 页 | 8.45 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型
read/write/create 三种访问模式 foreach 直接给出当前坐标指向的值 改用 unordered_map 来存储 unordered_map 手动 read(i, j) 也一样速度 索性把坐标和值打包成 tuple ,存储在 vector 按行压缩( Compressed Row Storage ) http://www.netlib.org/linalg/html_templates/node910 码力 | 102 页 | 9.50 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理
作为扩展阅读。 C++ 有哪些面向对象思想? C++ 思想:封装 比如要表达一个数组,需要:起始地址指针 v ,数组大小 nv 将多个逻辑上相关的变量包装成一个类 因此 C++ 的 vector 将他俩打包起来,避免程序员犯错 封装:不变性 比如当我要设置数组大小为 4 时,不能只 nv = 4 还要重新分配数组内存,从而修改数组起始地址 v 常遇到:当需要修改一个成员时,其他也成员需要被修改,否则出错0 码力 | 96 页 | 16.28 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针
众所周知,计算机是二进制的,存储的实际上是一个个 0 和 1 。 • 每个存储 0 或 1 的空间称为一个位( bit ),一位可以存储 0 或 1 两个可能的值。 • 现在的计算机都会把 8 个位打包成一个字节( byte ),也就是说: 1 字节 = 8 位。 • 一字节可以表示 0 到 255 区间中所有的值,表示方式如下: • 00000000 表示 0 00000001 表示 1 000000100 码力 | 128 页 | 2.95 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化
(morton code) ?有什么用? • 如 x=x1x2x3, y=y1y2y3 • 则他们的莫顿码: m(x,y)=y1x1y2x2y3x3 • 二维莫顿编码可以把两个长度为 n 的二进制数,交错打包成一个长度 2*n 的二进制数。而莫顿编码的逆运算,就是莫顿解码: • mdec(m1m2m3m4)=(m2m4, m1m3) • 莫顿码的几何意义在于,以 (x,y)=mdec(t) 为参数方程,可以生成一0 码力 | 147 页 | 18.88 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程
kernel 好像没有执行过一样,只有 CPU 上的代码被执行了。 指定多个版本号 • 可以指定多个版本号,之间用分号分割。 • 运行时可以自动选择最适合当前显卡的版 本号,通常用于打包发布的时候。 • 不过这样会导致 GPU 编译器重复编译很 多遍,每次针对不同的架构,所以编译会 变得非常慢,生成的可执行文件也会变大 。 • 通常在自己的电脑上用时,同学们只要根 据自己显卡的指定一个版本号即可。0 码力 | 142 页 | 13.52 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串
刚刚说了,要描述一个动态长度的数组(此处为字符串),需要首地址指针和 数组长度两个参数。 • void cihou_array(char *ptr, size_t len); • 可以把这描述同一个东西的两个参数,打包进一个结构体( struct )里,这样 就可以作为一个参数了!虽然本质上是一样的,但是代码变得更易读了。 • struct FatPtr { • char *ptr; • size_t0 码力 | 162 页 | 40.20 MB | 1 年前3Hello 算法 1.1.0 C++ 版
级别 非常小,MB 级别 速度 较慢,几百到几千 MB/s 较快,几十 GB/s 非常快,几十到几百 GB/s 价格 较便宜,几毛到几元 / GB 较贵,几十到几百元 / GB 非常贵,随 CPU 打包计价 我们可以将计算机存储系统想象为图 4‑9 所示的金字塔结构。越靠近金字塔顶端的存储设备的速度越快、容 量越小、成本越高。这种多层级的设计并非偶然,而是计算机科学家和工程师们经过深思熟虑的结果。0 码力 | 379 页 | 18.47 MB | 1 年前3
共 13 条
- 1
- 2