转载请说明出处 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 提问开始