新一代分布式高性能图数据库的构建 - 沈游人新一代分布式高性能图数据库的构建 北京海致星图科技有限公司 2023-06-18 沈游人 数据库与大数据专场 海致简介—企业级知识图谱开创者 专业顶尖技术团队支撑 超 700 人团队,其中 80% 为技术人员,创始团队在完成全球第一个中文知 识图谱网站研发后,探索知识图谱技术在企业领域的应用。 2021 年,海致院 士专家工作站成立,站内清华大学计算机博士生占比达 90% 以上。 专注于数据智能技术赋能中国数字经济发展 海致高性能图计算院士专家工作站 郑纬民 - 海致科技首席科学家 中国工程院院士、清华大学计算机科学与技术系教 授、中国计算机学会前理事长,中国计算机系统结构 的学科带头人,我国高性能计算和存储系统等方面的 泰斗和先行者。 2021 年 3 月 25 日,海致科技与清华大学计算机科学与技术系共同建设高性能图计算院士专家工作站 。 高性能图计算是高性能计算、图计算两项技术融合产生的新的技术方向,满足人们对更大规模、更复 术方向,满足人们对更大规模、更复 杂数据的实时处理和存储需求,是计算机领域竞争新战略制高点。 产学结合、协同创新,打造全球领先的国产自研图数据库 AtlasGraph ,培育世界级的图计算软硬件 生态体系,保持对全球科技竞争的战略均衡。 海致高性能图计算院士专家工作站 海致获得“ 2021 年 CCF 科学技术奖科技进步卓越奖” CCF 科学技术奖被认为是计算机科学与技术领域最具影响力的专业奖项之一,0 码力 | 38 页 | 24.68 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 o2 • Zeno 1.0 所在的分支: https://github.com/zenustech/zeno/ Zeno 中的基本类型 • IObject 一切对象的公共基类。 • INode 一切节点的公共基类。 多态的经典案例 • IObject 具有一个 eatFood 纯虚函数,而 CatObject 和 DogObject 继承自 IObject ,他 们实现了 eatFood m_catFood 。所以 这里的解构函数也是多态的,他根据类型的不同 调用不同派生类的解构函数。 多态用于设计模式之“模板模式” • 这样之后如果有一个任务是要基于 eatFood 做文章,比如要重复 eatFood 两遍。 • 就可以封装到一个函数 eatTwice 里,这个函数只需接受他们共同的基类 IObject 作为参数,然后调 用 eatFood 这个虚函数来做事(而不是直接操作具体的猫和狗本身)。 模板函数?未免有些差强人意 • 索性把 eatTwice 声明为模板函数的确能解决问题,但模板函数不是面向对象的思路,并 且如果 cat 和 dog 是在一个 IObject 的指针里就会编译出错,例如右图的 vector(这是游戏引擎中很常见的用法)。 正确解法:额外定义一个 clone 作为纯虚函数,然后让猫和狗分别实现他 clone 的调用 • 这样一来,我们通用的 0 码力 | 54 页 | 3.94 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程不过,这个功能同样需要开启 CUDA_SEPARABLE_COMPILATION 。 第 2 章:内存管理 如何从核函数里返回数据? • 我们试着把 kernel 的返回类型声明为 int ,试 图从 GPU 返回数据到 CPU 。 • 但发现这样做会在编译期出错,为什么? • 刚刚说了 kernel 的调用是异步的,返回的时候 ,并不会实际让 GPU 把核函数执行完毕,必须 cudaDeviceSynchronize() Segmentation Fault 差不多。 封装好了: helper_cuda.h • 其实 CUDA toolkit 安装时,会默认附带一系列案例代码, 这些案例中提供了一些非常有用的头文件和工具类,比如这 个文件: • /opt/cuda/samples/common/inc/helper_cuda.h • 把他和 helper_string.h 一起拷到头文件目录里,然后改一 下 CMakeLists lexible-kernels-grid-stride-loops/ 第 4 章: C++ 封装 std::vector 的秘密:第二模板参数 • 你知道吗? std::vector 作为模板类,其实有两个模板参数: std::vector• 那为什么我们平时只用了 std::vector 呢?因为第二个参数默认是 std::allocator 。 0 码力 | 142 页 | 13.52 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程std::milli> 的别名 跨平台的 sleep : std::this_thread::sleep_for • 可以用 std::this_thread::sleep_for 替代 Unix 类操作系统专有的的 usleep 。他可 以让当前线程休眠一段时间,然后继续。 • 而且单位也可以自己指定,比如这里是 milliseconds 表示毫秒,也可以换成 microseconds 下载完成前,整个界面都会处于“未响应”状 态,用户想做别的事情就做不了。 现代 C++ 中的多线程: std::thread • C++11 开始,为多线程提供了语言级别的 支持。他用 std::thread 这个类来表示线 程。 • std::thread 构造函数的参数可以是任意 lambda 表达式。 • 当那个线程启动时,就会执行这个 lambda 里的内容。 • 这样就可以一边和用户交互,一边在另一 主线程等待子线程结束: t1.join() • 因此,我们想要让主线程不要急着退出, 等子线程也结束了再退出。 • 可以用 std::thread 类的成员函数 join() 来等待该进程结束。 std::thread 的解构函数会销毁线程 • 作为一个 C++ 类, std::thread 同样遵循 RAII 思想和三五法则:因为管理着资源, 他自定义了解构函数,删除了拷贝构造 / 赋 值函数,但是提供了移动构造0 码力 | 79 页 | 14.11 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 03 现代 C++ 进阶:模板元编程2” 这个 功能,需要: 为什么面向对象在 HPC 不如函数式和元编程香了? 这个例子要是按传统的面向对象思想,可能是这样: 令 Int, Float, Double 继承 Numeric 接口类并实现 ,其中 multiply(int) 作为虚函数。然后定义: Numeric *twice(Numeric *t) { return t->multiply(2); } 且不说这样的性能问题,你忍得住寂寞去重复定义好 ,你也去 定义好几个重载吗?定义为 multiply(Numeric *) 的话 依然会违背你们的开 - 闭原则:比如 3.14f * 3 ,两 端是不同的类型,怎么处理所有可能类型的排列组合 ? 不如放弃类和方法的概念,欣然接受全局函数和重载 。 模板函数:定义 • 使用 template• 其中 T 可以变成任意类型。 • 调用时 twice 即可将 T 替换为 定义的变量,其类型会自动根据等号右边的值来确定 : 自动类型推导:一些局限性 • 不过 auto 也并非万能,他也有很多限制。 • 因为需要等号右边的类型信息,所以没有 = 单独声明一个 auto 变量是不行的: • 而且,类成员也不可以定义为 auto : 自动类型推导:函数返回值 • 除了可以用于定义变量,还可以用作函数的返回类型: • 使用 auto 以后,会自动被推导为 return 右边的类型。 • 不过也有三点注意事项: 0 码力 | 82 页 | 12.15 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 16 现代 CMake 模块化项目管理指南六、头文件和源文件的一一对应关系 • 通常每个头文件都有一个对应的源文件,两个文件名字应当相同 (方便我们理解,也方便 IDE 跳转),只有后缀名不一样。 • 如果是一个类,则文件名应和类名相同,方便查找 ( Animal.cpp )。 • 头文件中包含函数和类的声明,源文件则包含他们的实现。 七、只有头文件,没有源文件的情况 • 有时我们会直接把实现直接写在头文件里,这时可以没有与之对 应的源文件,只有一个头文件。 时,同时添加同名的源文件和头文 件。 • 头文件中的声明和源文件中的实现一一对应。 九、一个模块依赖其他模块,则应导入他的头文件 • 如果新模块( Carer )中用到了其他模块( Animal )的类或函数,则需要 在新模块( Carer )的头文件和源文件中都导入其他模块( Animal )的头 文件。 • 注意不论是项目自己的头文件还是外部的系统的头文件,请全部统一采用 < 项目名 / 这种相对路径的格式,避 免模块名和系统已有头文件名冲突。 十、依赖其他模块但不解引用,则可以只前向声明不导入头文件 • 如果模块 Carer 的头文件 Carer.h 虽然引用了其他模块中的 Animal 类,但 是他里面并没有解引用 Animal ,只有源文件 Carer.cpp 解引用了 Animal 。 • 那么这个头文件是不需要导入 Animal.h 的,只需要一个前置声明 struct Animal0 码力 | 56 页 | 6.87 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 09 CUDA C++ 流体仿真实战ace-memory CUDA 多维数组:封装 • cudaMalloc3DArray 用于分配一个三维数组。 各维度上的大小通过 cudaExtent 指定,方 便起见我们的 C++ 封装类用了 uint3 表示 大小。 • GPU 的多维数组有特殊的数据排布来保障 访存的高效,和我们 CPU 那样简单地行主 序或列主序(如 a[x + nx * y] )的多维数组 不一样。 Accessor , GPU 编程常用)。 原来的 CudaSurface 管理资源,禁止拷贝。然后单独 弄一个访问者类 CudaSurfaceAccessor ,不管理资源 ,仅仅是指向资源的一个弱引用,可以随意拷贝。并把 读写访问的方法( surf3Dread )定义在访问者类。 CUDA 表面对象:封装 • 此外,表面对象还支持自动判断 x,y,z 坐标是否越界 , surf3Dread/write 时要如何在周围 8 个值之间插值,有以下几种选择: • cudaFilterModeLinear :三线性插值更平滑(左图) • cudaFilterModePoint :最接近的那个点作为值(右 图) 烟雾仿真系统:封装 • 我们统一通过 unique_ptr 来管理对象,这样尽管 CudaSurface 对象是不可 移动的,我们仍可以通过移 动其指针的方式来实现双缓 冲( std::swap0 码力 | 58 页 | 14.90 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型加上去没有任何变化),是因为 第一个数太大了,要表示 1234000.01 需要 9 位有效位数。 • 而单精度浮点数 float 的底数有 23 位,指数有 8 位(图 1 )。 • 双精度浮点数 float 的底数有 52 位,指数有 11 位(图 2 )。 double: float: http://c.biancheng.net/view/314.html 以求最大值为案例 用定点数来表示 量,目的是为了防止用户犯错。 • 因此,想要追求稀疏的我们,最好想办法绕 开 glibc ,直接和操作系统打交道。 解决:绕开 glibc ,直接调用操作系统的 mmap 分配 • 那么就要用到 Unix 类操作系统的 mmap 函数,他位于 sys/mman.h 头文件里。 • Windows 可以用 VirtualAllocateEx 之类。 • mmap 出来的起始地址保证是对齐到 4KB 的,读写访问其0 码力 | 102 页 | 9.50 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 07 深入浅出访存优化既能高效利用内存 ,随机访问和插桩又特别高效。有兴趣可以研究一下他们的论文,也用了莫顿序增强 TLB 和缓存的局域性,非常精彩。 vector 也可以不初始化:只需使用一个帮手类 也可以使用小彭老师封装好的帮手类 重复分配效率低 • 即使第二次分配的是同一段差不多大小的内存,也是会产生缺页中断,花费分配时间的。 • glibc 的 malloc 实现,不会重复利用现有的内存。 改用 tbbmalloc 正确的遍历顺序和错误的遍历顺序,速度 相差了 20 倍。其中一部分是因为每个缓存 行只用到了 1/16 造成的,一部分是因为跳 跃的访存让 CPU 没有办法自动预取造成的 。 封装成 ndarray 类 ndarray.h ,同学们可以在作业或 是自己的项目里随意使用。 不要再用 Java 式的二层三层指针 了,用 ndarray<2, float> 声明一 个二维浮点数组, ndarray<3, ,但是 实际上还是 YX 序,和静态数组 的 a[y][x] 一样的,指标出现的顺 序并无关紧要。 …… ndarray :访问越界问题 • 在物理仿真中,常常需要访问在一个元素附近的几个元素。图 像处理中用到的模糊操作,也需要向上下左右扩散 w 个单位。 • 这样假如当前元素正好在二维网格的边界上,那再往外索引 w 个单位就会超出数组的界限,导致出错。对此有多种解决办法 : 1. 使用0 码力 | 147 页 | 18.88 MB | 1 年前3
Rust与算法 - 谢波写作动机 当情况不明时,抱着一个纯粹的目标干事就行了,其他 的留给时间检验。不懂就学,技术写作更像一种共创, 要反复总结和修改 ( 费曼学习法 ) 。 写作本书给我的启示 基础、排序、查找、树、图 代码框、颜色、图片绘制均由 Latex 完成 可参考点 为什么 为什么讲这个话题? 为什么要讲数据结构和算法两部分? 算法相关知识 算法相关知识 • 抽象数据类型 • 时空复杂度 • 字典树 • 图 Rust 实现算 法 蒂姆排序 什么是蒂姆排序? 蒂姆排序 位运算 高低位排序区别处理 https://github.com/QMHTMY/RustBook/blob/main/publication/code/chapter07/tim_sort_without_gallop.rs 字典树 怎么确定单词结束? 需要区分大小写吗? 图 如何定义点、边、图? 图 图 点和边操作注意事项 图 联想:图数据结构的的点、边、面似乎满足欧拉公式 : V – E + F = 2 、则时间复杂度为: O(V+E) = O(2E – F + 2) • V = 14; E = 18; F = 5 + 1; • V+E = 32 • 2E – F + 2 = 32 总结及学习资源 • 算法总结 • 学习资源 总结及学习资源 Rust 算法总结0 码力 | 28 页 | 3.52 MB | 1 年前3
共 25 条
- 1
- 2
- 3













