1. 程式人生 > >視頻筆記 CppCon 2016 Chandler Carruth High Performance Code 201 Hybrid Data Structures

視頻筆記 CppCon 2016 Chandler Carruth High Performance Code 201 Hybrid Data Structures

簡單 work int small 包含 接口 cat multi 類型擦除

版權聲明:轉載請說明出處 http://www.cnblogs.com/eagledai/

https://www.youtube.com/watch?v=vElZc6zSIXM&t=1157s LLVM internal data structures LLVM 內部數據結構 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 技術分享

The map uses the same traits class.

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:有人可能會忘了讓這些數字在所有的callers都同步,否則...booom。也許有辦法解決這個問題,但是很難找到簡單有效的方法 技術分享

問題2:返回這個vector對象的時候,很有可能這個vector包含memory在stack裏面。也許也是有辦法解決了,但是很challenging 技術分享

使用costomed containers,而不是allocators,所有這些問題都消失了。

13:44 Small-size optimizations效果最好,只在values小的時候 works way better when the values are really small. 這是最最critical的!這樣才有足夠高的密度。所以真正的challenges,是優化這些values,使他們足夠小。這比有上面那些containers更重要。Containers不難,但是有效的使用好它們需要很多的工作。 14:45 第一個關鍵的想法是給large objects address identity address identity: 對象有內在的ID嗎?something unique about the object。如果仔細分配,可以借用地址作為ID 技術分享

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

問題:為什麽不使用forward list?上面的用法比forward list效果好很多!因為地址是連續的,對緩存相對友好。如果遍歷forward list,必須先要讀出一個對象,才能知道下一個對象的地址在哪裏。也就是如果有一次cache miss,就會有一序列的cache misses. 但是以上的用法也有問題,這些大對象本事沒有locality。他們內存分配的時候一般都是隨意哪裏有內存就在哪裏,根本沒有locality。所以LLVM使用下面可怕的BumpPtrAllocator 20:00 class BumPtrAllocator 簡化版本below 技術分享

"World‘s worst malloc implementation". Nice thing about this:

  • local. strong locality for large objects, though wasteful: a page (4k) at least
  • really fast
21:50 Sometimes, if pointers are too large, use an index 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 提問開始

視頻筆記 CppCon 2016 Chandler Carruth High Performance Code 201 Hybrid Data Structures