C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针
vs 无符号整数 • 有时候我们是需要表示负数的。而刚刚那种二进制的做法,只能表示正数和零。 • 怎么办?可能有的同学会想,不妨这样来设计:让二进制的最高位表示符号位。 • 比如 00000011 表示 3 , 10000011 表示 -3 ,这样不就区分开来了吗?这叫做原码表示 法。 • 的确可以,这种表示方式牺牲了一位作为符号位,剩下 7 位继续表示值。 • 这样的设计下无符号可以表示 实际上表示 -1 , 11111111 则表示 -128 ,让负数部分整体“平 移”一位,这样就不会出现 -0 这种奇怪的东西了,而且表示范围也扩大了一位,虽然是扩 大在负数部分。 有符号整数 vs 无符号整数 • 刚刚说的让 10000000 表示 -1 , 11111111 表示 -128 的方法就叫做反码表示法。 • 但是这样还有一个问题,那就是硬件电路上,需要完全重新设计,对符号位做一些特殊判 = 1 ,在计算机看来就是: • 11111111 + 00000010 = 100000001 • 正好和普通的二进制加法一样,只需要丢弃最前面的那一位进位就可以了。 • 这样就重用了现有的无符号加法器,从而节省了宝贵的电路板空间。 • 补码和反码一样,让有符号整数可以表示 -128 到 127 。 • 其中负数的范围反而比正数大是因为要回避 -0 。 字节的单位: KB , MB ,0 码力 | 128 页 | 2.95 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理
入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 mutex 到无锁并行 6.并行编程常用框架: OpenMP 与 Intel TBB 7.被忽视的访存优化:内存带宽与 cpu 缓存机制 8.GPU 专题: wrap 调度,共享内存, barrier 9.并行算法实战: 有要求就不能依靠 GC 。 比如 mutex 忘记 unlock 造成死锁等等…… RAII :离不开构造函数 • 如题,那么如何定义构造函数呢? BV1h64y197Fd 自定义构造函数:无参数 自定义构造函数:无参数(使用初始化表达式) 为什么需要初始化表达式? 1. 假如类成员为 const 和引用 2. 假如类成员没有无参构造函数 3. 避免重复初始化,更高效 自定义构造函数:多个参数 。 • 虽然作者也经常会忍不住在 zeno 中用 编译器默认生成的构造函数:无参数(小心 POD 陷阱!) • 除了我们自定义的构造函数外,编译器还会自动生成一些构造函数。 • 当一个类没有定义任何构造函数,且所有成员都有无参构造函数时,编译器会自动生成一 个无参构造函数 Pig() ,他会调用每个成员的无参构造函数。 • 但是请注意,这些类型不会被初始化为 0 : 1. int, float0 码力 | 96 页 | 16.28 MB | 1 年前3Await-Tree Async Rust 可观测性的灵丹妙药 - 赵梓淇
• 异步编程的共同优势 • async/await 关键字 • 用户态调度 • Async Rust 的独特优势 • Ownership 与 Lifetime • 无栈协程 Async Rust 回顾 Rust 的无栈协程抽象 — Future Async Rust 回顾 • 通过 poll 驱动的状态机 • 组合嵌套为调度单元: Task • async fn 语法糖 Async Backtrace 不够直观 ( 调用栈 -> 调用树 ) • Tracing 无法追踪调用关系的变化 Async Rust 观测与调试的痛点 Async Rust 回顾 • 特性:用户态调度的无栈协程 • Pending Task 不存在栈空间 • 痛点:观测与调试工具无法还原 Pending Task 的执行状态 • 难以得知 Task 阻塞的位置和原因 • 难以调试 Async Stuck 的实现 Await Tree 的设计原理与实现 • 一棵树代表一个 Task 的执行状态 • Task 单线程执行 • 在 Task-Local Storage 中无竞争维护 • 使用 Arena Tree 简化实现 • 无 Unsafe 代码 Await Tree 的实现 Await Tree 的设计原理与实现 • Future Adapter API 设计 • Adapter 内部维护状态机以操作0 码力 | 37 页 | 8.60 MB | 1 年前3Rust分布式账务系统 - 胡宇
景分别优化 ● 稳定的底层 API ● 灵活的顶层 API ● 树状结构 ● 聚合查询 ● 正确性:内存安全,线程安全 ● 可靠性: Raft 共识算法 raft-rs ● 高性能:关键路径无锁单线程 顶层架构 ● Gateway 路由层 ○ 业务 API 到底层 API 的翻 译 ○ 产生转账计划 ● Marker 事务层 ○ 使用业务 id 进行路由 ○ 执行转账计划 ● 2. 将 events 送入 Raft 共识,等待 events 被多数节点保存 ● 3. 处理被共识的 events ,更新状态机 (账户表) ○ 去重 & 更新余额 ○ 关键路径采用无锁单线程 账户层: Auticuro 分布式账务系统 1 2 3 4 ● 1. 接受转账请求,转换成 events ● 2. 将 events 送入 Raft 共识,等待 events 账户层: Auticuro 分布式账务系统 1 2 3 4 事务层: Marker 分布式账务系统 A,B,C 在不同分区执行一个事务的 TCC 转账计划 ● 转账计划 ○ 有向无环图 ○ 节点是一个任务 ○ 边是依赖关系 ● 事务层 Marker 负责执行计划 ○ ACID 保证 ○ 依赖控制 ○ 条件执行 ○ 调度账户变动请求 跨分区转账 分布式账务系统0 码力 | 27 页 | 12.60 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程
blockIdx + threadIdx 三维的板块和线程编号 • CUDA 也支持三维的板块和线程区间。 • 只要在三重尖括号内指定的参数改成 dim3 类型即可。 dim3 的构造函数就是接受三 个无符号整数( unsigned int )非常简单 。 • dim3(x, y, z) • 这样在核函数里就可以通过 threadIdx.y 获取 y 方向的线程编号,以此类推。 那二维呢? 在初始化的时候(或是之后 resize 的时候)会调用所 有元素的无参构造函数,对 int 类型来说就是零初始化。然而 这个初始化会是在 CPU 上做的,因此我们需要禁用他。 • 可以通过给 allocator 添加 construct 成员函数,来魔改 vector 对元素的构造。默认情况下他可以有任意多个参数,而 如果没有参数则说明是无参构造函数。 • 因此我们只需要判断是不是有参数,然后是不是传统的 因此我们只需要判断是不是有参数,然后是不是传统的 C 语 言类型( plain-old-data ),如果是,则跳过其无参构造,从 而避免在 CPU 上低效的零初始化。 进一步:核函数可以是一个模板函数 • 刚刚说过 CUDA 的优势在于对 C++ 的 完全支持。所以 __global__ 修饰的核函 数自然也是可以为模板函数的。 • 调用模板时一样可以用自动参数类型推导 ,如有手动指定的模板参数(单尖括号) 请放在三重尖括号的前面。0 码力 | 142 页 | 13.52 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 性能优化之无分支编程 Branchless Programming
大于等于(有符号) greater or equal l 小于(有符号) less g 大于(有符号) greater be 小于等于(无符号) below or equal ae 大于等于(无符号) above or equal b 小于(无符号) below a 大于(无符号) above e 等于 equal ne 不等于 not equal http://unixwiz.net/techtips/x86-jumps0 码力 | 47 页 | 8.45 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串
unsigned char 是无符号 8 位整数, signed char 是有 符号 8 位整数,而 char 类型只需是 8 位整数即可,可以是有符号也可以 是无符号,任凭编译器决定( C 标准委员会传统异能, khronos 直呼内行) 。 • 以 GCC 为例,他规定 char 在 x86 架构是有符号的 (char = signed char) ,而在 arm 架构上则认为是无符号的 (char (char = unsigned char) ,因为他 认为“ arm 的指令集处理无符号 8 位整数更高效”,所以擅自把 char 魔改成无 符号的…… • 顺便一提, C++ 标准保证 char , signed char , unsigned char 是三个完全 不同的类型, std::is_same_v 分别判断他们总会得到 false ,无论 x86 还是 arm 。 • 但是奇葩的 C0 码力 | 162 页 | 40.20 MB | 1 年前3新一代分布式高性能图数据库的构建 - 沈游人
Docker/K8S/VM X86/ARM - 基于 RUST 语言保证性能优势 - 分布式架构性能可线性扩展 - 针对大规模图优化的存算引擎 - 配合 Atlas 图平台,实现无代码图分析 - Query 性能分析模块,启发式提示优化 - 内置多种分析函数,面向分析师友好 -MVOCC 保证事务一致性 - 多副本管理保证数据服务高可用 - 在线备份提供容灾保障 高速 据获取 01 可静态分发的 Trait 在不带来性 能损失的同时也提高代码组织性 02 03 强大的跨平台能力,在不同架构 下可以准确的控制代码行为 编译期间对生命周期检查确保内 存安全,无 GC 和运行时损耗 01 完善的测试类型支持,包括单元 测试、集成测试、基准测试等 02 03 和文档系统以及 CI/CD 工具的良 好集成 完整的断言系统 异步协程 零成本抽象 强大的测试框架 Takeway AtlasGraph 图数据库关键特性 - 基于 RUST 语言保证性能优势 - 分布式架构性能可线性扩展 - 针对大规模图的优化的存算引擎 - 配合 Atlas 图平台,实现无代码图分析 - Query 性能分析模块,启发式提示优化 - 内置多种分析函数,面向分析师友好 -MVOCC 保证事务一致性 - 多副本管理保证数据服务高可用 - 在线备份提供容灾保障 高速0 码力 | 38 页 | 24.68 MB | 1 年前3C++高性能并行编程与优化 - 课件 - 09 CUDA C++ 流体仿真实战
clr 和 vel 使用了双缓冲,写入 clrNext 的同时读取 clr 没有冲突,写入完毕后对调 clrNext 和 clr 。 投影部分 投影部分 • 我们要模拟的流体是不可压缩的,因此有着无散度的特点: div v = 0 • 上式对时间求导,即 d(div v)/dt = div dv/dt = 0 ;带入 dv/dt = -p 得 div grad p = 0 。 • 因此为了模拟不可压缩流我们要求保证 次,看看效果。 • 当然, jacobi 迭代因为需要写入 pre 的同时读取 pre ,所以也要用双缓冲。 投影部分:计算未消除的散度 为了评估效果的好坏,额外加一个计算散度方差的核函数,看看是不是无散度(不可压缩流)了。 多重网格法 投影部分:多重网格实现 投影部分:红黑高斯 投影部分:计算残差 投影部分:缩小一倍 投影部分:清零数组 投影部分:扩大一倍 创建与导出 主函数:创建场景0 码力 | 58 页 | 14.90 MB | 1 年前3谈谈MYSQL那点事
‘abc%’ LIKE ‘abc%’ 将能够使用索引 将能够使用索引 如果在 如果在 SQL SQL 里使用了 里使用了 MySQL MySQL 部分自带函数,索引将失效,同时将无 部分自带函数,索引将失效,同时将无 法 法 使用 使用 MySQL MySQL 的 的 Query Cache Query Cache ,比如 ,比如 LEFT(), SUBSTR(),0 码力 | 38 页 | 2.04 MB | 1 年前3
共 21 条
- 1
- 2
- 3