视频笔记 CppCon 2016 Chandler Carruth High Performance Code 201 Hybrid Data Structures

转载请说明出处 http://www.cnblogs.com/eagledai/

LLVM internal data structures
LLVM 内部数据结构
 
关于Chandler Carruth: 谷歌里面搞 LLVM 编译器优化的,也是谷歌在 C++ 委员会的代表。感觉在委员会里的地位 仅仅次于 C++ 之父 和 H Sutter。经常在各种 C++ conference 里面抛头露面,挺受欢迎。
 
2:24 SmallVector
下面是 SmallVector 的简化版本。这是 LLVM 里最基本的数据结构,到处被使用。

问题:为什么不直接使用 STL 的 vector? 因为在 STL 里,如果对 vector 进行 move 操作,按照规范,迭代器还要保持有效。这个特性虽好,但带来的问题是,不能进行 small-size 优化。

 
4:57 Wield Tricks for SmallVector (SmallVector 的怪异的小把戏)

左边:仅仅有缓存 (char Buffer[])

右边:基类看起来像个 vector,但是没有缓存。缓存是通过基类的构造函数传入的。这种模式是非常强大的,因为类型擦除了 N

类型擦除N的好处?跨越接口边界的时候,不用关心这个N

 
6.27 SmallDenseSet

It is a smalll size optimized set. Unlike std::unordered_set, instead we use open addressing here, an array of buckets, flat in memory. We use quadratic probing (二次探测). The traits class is related to hashing.

 
8:40 SmallDenseMap

这个 map 类使用了一个 traits 类。

For empty and tombstone buckets, don't put complete pair into those buckets. Acutually, just put the keys into them (special code).
 
LLVM,对于通用的数据机构,99%都是基于以上三个 small size optimized containers。
 
10:37 问题:为什么 small size optimized containers 不使用allocators?

 上图是有人一种建议的实现方式(使用 allocators 二不是 custom containers)。这个solution是能工作的,但是...

 问题1:有人可能会忘了让这些数字在所有的调用处都一致,否则... booom。也许有办法解决这个问题,但是很难找到简单有效的方法
 

 问题2:返回这个vector对象的时候,很有可能这个 vector 包含的内存在栈里面。也许也是有办法解决了,但是很challenging

使用 costomed containers,而不是 allocators,所有这些问题都消失了。

 
13:44 Small-size optimizations 效果最好,只在 values 小的时候
当对象很小的时候,效果非常好 这是最最关键的!这样才有足够高的密度。所以真正的挑战,是优化这些类或者结构,使他们足够小。这比有上面那些 containers 的实现更重要。Containers 不难,但是有效的使用好它们需要很多的工作。
 
14:45 第一个关键的想法是给大对象 address identity
address identity: 对象有内生的 ID 吗?也就是一些天然独一无二的值。如果仔细分配这个对象,可以借用地址作为ID

借用地址做 ID,可以如上使用 container。

问题:为什么不使用 forward list?上面的用法比 forward list 效果好很多!因为地址是连续的,对缓存相对友好。如果遍历 forward list, 必须先要读出一个对象,才能知道下一个对象的地址在哪里。也就是如果有一次 cache miss,就会有一序列的 cache misses.
但是以上的用法也有问题,这些大对象本身没有 locality。他们内存分配的时候一般都是随意哪里有内存就在哪里,根本没有locality。所以LLVM使用下面可怕的 BumpPtrAllocator
 
20:00 class BumPtrAllocator 简化版本如下

"World's worst malloc implementation". 也有下面的优点:

  • 对大对象本地性非常强,尽管也很浪费:一个内存页至少4k
  • 真的非常快
 
21:50 有时候,如果指针也太大,可以使用索引
 
22:08 Aggressively pack the bits
  • to make objects small
  • there are 4 zeros in low bits of the pointer, e.g., 10000000010000000010000

结合之后的提问:这里的bit operations基本上cost非常低,大多都是compile time的cost

 
28:28 use above packed pointer to build below:

TinyPtrVector can be a T or a vector of T

The most useful case of this is for multi map:
  template <typename KeyT, typename ValueT>
  using SmallMultiMap = SmallDenseMap<KeyT, TinyPtrVector<ValueT>>;
 
 
31:24 Lastly, use bitfields everywhere
 
32:00 Sometimes, you really need an ordering
  不能依赖hash or set的ordering
  When possible, sort vectors
  有时候,按照什么排序不重要,但一定需要deterministic,也就是需要一个确定的顺序
 

  类似的有 template class SmallMapVector;

  可以进一步优化,当数量小的时候,只使用vector, 线性搜索有更高的效率
 
37:00 提问开始

posted on 2017-05-20 13:05  eagle-dai  阅读(519)  评论(0)    收藏  举报

导航