C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程
1>>>() 后,并不 会立即在 GPU 上执行完毕,再返回。实际上只是把 kernel 这个任务推送到 GPU 的执行队列上,然后立即 返回,并不会等待执行完毕。 • 因此可以调用 cudaDeviceSynchronize() ,让 CPU 陷 入等待,等 GPU 完成队列的所有任务后再返回。从而 能够在 main 退出前等到 kernel 在 GPU 上执行完。 定义在 GPU 用于定义核函数,他在 GPU 上执行,从 CPU 端通过三重尖括号语法调 用,可以有参数,不可以有返回值。 • 而 __device__ 则用于定义设备函数,他在 GPU 上执行,但是从 GPU 上调用的,而 且不需要三重尖括号,和普通函数用起来一 样,可以有参数,有返回值。 • 即: host 可以调用 global ; global 可以调 用 device ; device 可以调用 device 上的函数。 同时定义在 CPU 和 GPU 上 • 通过 __host__ __device__ 这样的双重修 饰符,可以把函数同时定义在 CPU 和 GPU 上,这样 CPU 和 GPU 都可以调 用。 让 constexpr 函数自动变成 CPU 和 GPU 都可以调用 • 这样相当于把 constexpr 函数自动变成修饰 __host__ __device__ ,从而两边都可以调用。0 码力 | 142 页 | 13.52 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化
char data[64]; • }; • CacheEntry cache[512]; • 当 CPU 读取一个地址时: • 缓存会查找和该地址匹配的条目。如果找到,则给 CPU 返 回缓存中的数据。如果找不到,则向主内存发送请求,等读 取到该地址的数据,就创建一个新条目。 • 在 x86 架构中每个条目的存储 64 字节的数据,这个条目 又称之为缓存行( cacheline )。 tmp 对象的副本, 防止多线程调用 func 出错。 • 返回时(或者进入时)调用 tmp.clear() 清除已有数据。 由于 vector 的特性,他只会把 size() 标记为 0 并调 用其成员的解构函数,而不会实际释放内存( free )。 • 因此第二次进入的时候,如果 n 不超过上一次的大小 ,就还是用的第一次分配的内存,避免了重新分配的开 销。对 func 需要被重复调用的情况很实用。 了 ,毕竟 16 次加法远远没有超过 membound 的范畴, cpubound 我们已经仁至义尽地尽量 消除了。 • 如果单单采用手动预取,或者单单采用循环分块,那反而还会变慢。这就是性能调优中的一 大难点:某个改动可能对性能没有效果,甚至反而产生负面效果。然而有经验的优化人员会 知道,这不一定意味着这项改动是错的:有可能要配合多个改动一起上,才能有正面效果。 • 性能优化我们需要0 码力 | 147 页 | 18.88 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程
每个线程共享同样的内存空间,开销比较小。 • 每个进程拥有独立的内存空间,因此开销更大。 • 对于高性能并行计算,更好的是多线程。 为什么需要多线程:无阻塞多任务 • 我们的程序常常需要同时处理多个任务。 • 例如:后台在执行一个很耗时的任务,比 如下载一个文件,同时还要和用户交互。 • 这在 GUI 应用程序中很常见,比如浏览 器在后台下载文件的同时,用户仍然可以 用鼠标操作其 UI 界面。 true 。 • 第二次上锁,由于自己已经上锁,所以失败 了,返回 false 。 只等待一段时间: try_lock_for() • try_lock() 碰到已经上锁的情况,会立即返 回 false 。 • 如果需要等待,但仅限一段时间,可以用 std::timed_mutex 的 try_lock_for() 函数, 他的参数是最长等待时间,同样是由 chrono 指定时间单位。超过这个时间还没 owns_lock() 判断是否上锁成功。 std::unique_lock :用 std::adopt_lock 做参数 • 如果当前 mutex 已经上锁了,但是之后 仍然希望用 RAII 思想在解构时候自动调 用 unlock() ,可以用 std::adopt_lock 作 为 std::unique_lock 或 std::lock_guard 的第二个参数,这时他们会默认 mtx 已经 上锁。0 码力 | 79 页 | 14.11 MB | 1 年前3Rust分布式账务系统 - 胡宇
● 3. 处理被共识的 events ,更新状态机 (账户表) ● 4. 回调完成请求 账户层: Auticuro 分布式账务系统 1 2 3 4 事务层: Marker 分布式账务系统 A,B,C 在不同分区执行一个事务的 TCC 转账计划 ● 转账计划 ○ 有向无环图 ○ 节点是一个任务 ○ 边是依赖关系 ● 事务层 Marker 负责执行计划 ○ ACID 保证0 码力 | 27 页 | 12.60 MB | 1 年前3Zadig 产品使用手册
• 单元测试、代码扫描 更新日常开发环境及 dev 业务配 置 project-dev-workflow • 构建、配置变更( Apollo/Nacos )、数 据变更、部署、冒烟测试、项目管理任务 变更 测试工程师 更新测试验证环境 project-sit-workflow • 构建、配置变更( Apollo/Nacos )、数 据变更、部署、接口测试 更新集成测试环境 project-auto-sit-workflow 据变更、部署生产环境(变量变更、模板 变更)、场景测试 管理员 ( 运维 ) 准备——工作 流 管理员 ( 运维 ) 准备——工作 流 面向角色 环境描述 环境名称样例 场景介绍 开发工程师 用于日常开发、联调 dev 如果 Java 栈实现灰度能力,可以通过新建环境随时拉 起开发自测子环境 如果采用 Istio + Skywalking 技术栈,通过 Zadig 开启自测模式随时拉起子环境 测试工程师 通知 Sprint 发布 测试验证 变更发布 产品规划 需求开发 Sprint 发布 测试验证 变更发布 产品规划 多人做集成联调——更新不同服务 启动 dev 工作流,选择多个服务和对应的 MR 执行 需求开发 多人做集成联调——更新同一个服务 启动 dev 工作流,选择多个服务以及其对应的多个 MR 执行 Sprint 发布 测试验证 变更发布 产品规划 需求开发0 码力 | 52 页 | 22.95 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅
运用多线程的方式和动机,一般分为两种。 • 并发:单核处理器,操作系统通过时间片调 度算法,轮换着执行着不同的线程,看起来 就好像是同时运行一样,其实每一时刻只有 一个线程在运行。目的:异步地处理多个不 同的任务,避免同步造成的阻塞。 • 并行:多核处理器,每个处理器执行一个线 程,真正的同时运行。目的:将一个任务分 派到多个核上,从而更快完成任务。 举个例子 • 并发:某互联网公司购置了一台单核处理 上一课的案例代码:基于标准库 基于 TBB 的版本:任务组 • 用一个任务组 tbb::task_group 启动多个 任务,一个负责下载,一个负责和用户交 互。并在主线程中等待该任务组里的任务 全部执行完毕。 • 区别在于,一个任务不一定对应一个线程 ,如果任务数量超过 CPU 最大的线程数, 会由 TBB 在用户层负责调度任务运行在 多个预先分配好的线程,而不是由操作系 统负责调度线程运行在多个物理核心。 dedicated 让人咋 用? 第 4 章:任务域与嵌套 https://link.springer.com/chapter/10.1007%2F978-1-4842-4398-5_12 任务域: tbb::task_arena 任务域:指定使用 4 个线程 嵌套 for 循环 嵌套 for 循环:死锁问题 死锁问题的原因 • 因为 TBB 用了工作窃取法来分配任务: 当一个线程 t1 做完自己队列里全部的工0 码力 | 116 页 | 15.85 MB | 1 年前3Zadig 面向开发者的云原生 DevOps 平台
面向开发者的云原生 DevOps 平台 角色: 产品 / 架构 开发 测试 运维 运维 / 开发 技术支持 事件 需求设计 架构设计 拆任务、写代码 代码集成 xN 单元测试验证 xN 代码扫描 xN 自测、联调 xN 集成验证 xN 写测试用例 系统验证 xN 自动化测试 xN 性能测试 xN 安全测试 xN 数据变更 xN 业务资源利用率提升 30% 统一治理内部规范,开发 自助上线;解放运维,工 作重心向业务稳定性保 障,建设平台工程体系 研发 研发时间被大量占用: • 本地开发环境难模拟 • 多业务联调艰难,诊断耗时多 • 出现问题诊断耗时多 • 流程割裂协作痛苦,响应慢 调试自测免打扰:本地 / 子环境免打扰,独立完成验证工作 自助验证更高效:自动化工作流 + 云上环境,高效验证调试 安全发布有信心: 客观精准的效能洞察 • 在 VScode IDE 中使用 Zadig 核心能 力 • 无需打包镜像,即可一键热部署到自测 环境 • 与 Zadig 基准环境交互,完成自测、 联调验证 云原生 IDE 插件( vscode ) 执 行 企 业 合 规 S O P 流 程 , 灰 度 蓝 绿 部 署 策 略 , 完 成 生 产 环 境 发 布 最 后 一 公 里0 码力 | 59 页 | 81.43 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming
(pipeline) 。流水线的目的是能把原本 串行的一系列指令并行化。为了理解为什 么需要流水线,我们先反过来,假设没有 流水线,会有什么坏处。 • 例如,右边你今天早上的任务清单。 • 请问你这些任务总共需要多少时间? 任务 时间 占用资源 洗脸 5 分钟 眼睛,嘴巴,手 烧开水 10 分钟 煤气灶 刷牙 5 分钟 嘴巴,手 看比站 15 分钟 眼睛 吃饭 30 分钟 嘴巴,手 拉粑粑 存器来指令解码单元才开始继续工作,很 低效。 任务 时间 占用资源 洗脸 5 分钟 眼睛,嘴巴,手 烧开水 10 分钟 煤气灶 刷牙 5 分钟 嘴巴,手 看比站 15 分钟 眼睛 吃饭 30 分钟 嘴巴,手 拉粑粑 20 分钟 屁股 洗脸 烧开水 刷牙 看比站 吃饭 拉粑粑 5 10 5 15 30 20 为什么需要流水线 • 更高效的办法是,观察每个任务都占用哪些 资源,所占用资源不冲突的可以同时进行, + 20 = 40 分钟,比你快一倍多。 任务 时间 占用资源 洗脸 5 分钟 眼睛,嘴巴,手 烧开水 10 分钟 煤气灶 刷牙 5 分钟 嘴巴,手 看比站 15 分钟 眼睛 吃饭 30 分钟 嘴巴,手 拉粑粑 20 分钟 屁股 洗脸 刷牙 烧开水 吃饭 看比站 拉粑粑 5 5 10 20 条件跳转指令 • 让不占用相同资源的任务同时进行,这也是 CPU 流水线的初衷。但理想是美好的,现实0 码力 | 47 页 | 8.45 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型
发现结果不对了……说明 int8_t 太小了(可以容纳 - 128 到 127 ),容纳不下 97*100 这么大的数,发生 了溢出导致结果错误。 试图解决:用 uint8_t 表示,定点数系数调小到 2 • 注意到我们的值始终是正数,因此可以用无符号的 uint8_t (可以容纳 0 到 255 ),然后把刚刚的系数 100 改小到 2 ,成功算对结果了,代价是精度损失了 不少。 uint8_t (范围从 0 到 255 ),着色器在读取的时候才会把他 转换成 float (范围从 0.0 到 1.0 )。这就是浮点数的 量化,存储时转换成低精度的定点数,读取时再转换 回高精度的浮点数,从而节省 4 倍内存带宽,提升 GPU 性能。 有没有更小的浮点类型? • 浮点数在接近 0 的时候精度更高,在一些图形学应用中还是很必要的(比如表示粒子的速 度),定点数就做不到。0 码力 | 102 页 | 9.50 MB | 1 年前3C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践
这里的解构函数也是多态的,他根据类型的不同 调用不同派生类的解构函数。 多态用于设计模式之“模板模式” • 这样之后如果有一个任务是要基于 eatFood 做文章,比如要重复 eatFood 两遍。 • 就可以封装到一个函数 eatTwice 里,这个函数只需接受他们共同的基类 IObject 作为参数,然后调 用 eatFood 这个虚函数来做事(而不是直接操作具体的猫和狗本身)。 • 这样只需要写一遍 eatTwice0 码力 | 54 页 | 3.94 MB | 1 年前3
共 19 条
- 1
- 2