# mimalloc 共筆
contributed by ` Julian Fang ` ` afcidk `
[avoid divisions](https://hackmd.io/@hPMCWajOS-ORQdEEAQ04-w/BkssztrgH)
[Brief History of free list sharding](https://hackmd.io/@hPMCWajOS-ORQdEEAQ04-w/HJbeisVNB)
based on ` microsoft ` [mimalloc](https://github.com/microsoft/mimalloc)
## 檢查事項
1. 理解 `madvise` 用法,和 `mimalloc` 如何使用
2. 如何儘量避免 atomics 卻能正確地實作 malloc/free
3. 理解 per-thread block pools, free lists 等意義
4. 量化分析數據: 重現實驗 (`mimalloc-bench` 程式碼似乎有欠缺,要再等等)
5. Watch `mimalloc` 的 GitHub 頁面,從開發者的討論中學習
6. `mimalloc` 的 Worst-Case Allocation Time (wcat) 如何確保?又如何透過 `z3` 定理證明器證明呢?
## ` mimalloc ` 論文回顧(1)
[paper itself](https://www.microsoft.com/en-us/research/uploads/prod/2019/06/mimalloc-tr-v1.pdf)
### The Allocation Free List
#### spatial locality issue
> To improve the spatial locality of allocation, mimalloc use free list sharding where the heap is divided into pages with a free list per page.
* 筆者提到一般的 function style programming 多使用 ` single free list ` 會導致很糟糕的 spatial locality 。
* 因此在這邊使用 ` free list sharding ` 這個方法來實做。將整個 heap 分成一個一個 page ,每個 page 中都有一個小的 free list 。
* 這個問題之所以在 allocator 探討是因為 static allocation 分配到的位置是在 stack 上,而且是連續的。他想要改善 dynamic allocation 的 spatial locality,減少讀取 structure 的資料時的 cache miss。
### No Bump Pointer
#### what is Bump-pointer allocation
[refernece](https://the.gregor.institute/t/5n/842/slides/3.pdf)
To wit, ` sequential allocation `!
按照順序一個一個堆到最後面。
advantages:
* easy and fast
* No wasted space during ` allocation `
* only requires 2 pointers per pool, ` unallocated ` and ` end `
disadvantages:
* only makes sense for big free regions
#### No Bump poiter allocation
這邊使用的方法,為在每個分割好的 page 中找尋下一個可以使用的 block。
如果沒有下一個可用的 block 則重新分配一個 page。
### The Local Free List
purpose:
* To bound the ` worst-case allocation ` and ` free time `
> When free a lagre data structures, the number of recursive free calls need to limited.
How to do?
* use a simple limit counter
* push the remaining pointers on a ` deferred decrement list `
So ... when to free again from the ` deferred decrement list `?
* cooperate with allocator!
* Since the best time to do this is when the allocator is finding more space.
* Calls a user defined ` deferred_free `
* In the implementation, ` deferred_free ` is called when ` free_list ` is empty.
purpose 2:
* To guarentee that the generic routine is called regularly.
> Why do we need to generic routine to be called regularly? To establish temporal cadence (like heartbeat)
How to do?
* Shard the free list (free -> free | local_free )
* We allocate from free list, and free to local_free list, so it is guaranteed that free list will become empty after a fixed number of operations.
### The Thread Free List
purpose:
* Avoid lock for thread-local free
How to do?
* Atomic push freed object to thread free list
* Wait for generic routine to collect thread free list (and local free list as well) to free list
## Madvise
` madvise ` 讓我們給 kernel 一段記憶體空間分配上的建議。
Function prototype
`int madvise(void *addr, size_t length, int advice);`
addr 和 length 可以指定一個記憶體區段。advice 有提供[很多選項](http://man7.org/linux/man-pages/man2/madvise.2.html)來使用,這邊解釋一下 mimalloc 使用到的 advice 就好 (`MADV_FREE`)。
### MADV_FREE
`MADV_FREE` 在 Linux 4.5 之後被提出,意思是告訴 kernel 這段區間已經不需要被使用到了,可以釋放,但是 free 的動作會延遲到等到出現 memory pressure(空間不夠用)時再釋放就好。
設定 `MAD_FREE` 後,kernel 在遇到 memory pressure 時隨時可以釋放空間,但是一旦在釋放前又對記憶體區段寫入資料,釋放的動作就會被取消掉。
`MAD_FREE` 只能作用在 private anonymous page。
*在 Linux v4.12 以前,在 swapless system 中使用 `MADV_FREE` 釋放 page 會被直接釋放掉而不會延遲到 memory pressure 再釋放*
### MADV_DONTNEED
告訴 kernel 這段記憶體區間未來不會使用到。在使用 `MADV_DONTNEED` 之後,我們還是可以存取到該區間的 page,但是拿到的內容可能是
* mmap 的檔案內容 (對於 shared file mappings, shared anonymous mappings, shmem-based memory segments)
* zero-fill-on-demand pages (對於 private anonymous page)
*`MADV_DONTNEED` 可能不會馬上釋放空間,kernel 會決定一個**合適的**時間來釋放*
`madvise` 實際上被用到的地方是當 `mi_options_cache_reset` 或是 `mi_options_page_reset` 時,需要告訴 kernel 這段記憶體區間應該被釋放掉,但是之後可能還會用到,所以不需要立刻釋放,在 `_mi_os_reset` 被使用到,和 `_mi_os_free` 直接釋放略為不同。
## z3 Prover
[z3-guide](https://rise4fun.com/z3/tutorial)
[z3-github](https://github.com/Z3Prover/z3)
input format:
```
(declare-const a Int)
(declare-fun f (Int Bool) Int)
(assert (> a 10))
(assert (< (f a true) 100))
(check-sat)
```
* An extension of [SMT-LIB2.0](http://smtlib.cs.uiowa.edu/)
* 令用 assert 添加一些 ` 明確肯定 ` 的限制,到 ` stack ` 中。
* script 在 ` check-sat ` 後,回傳 ` sat ` 則表示滿足。
在 ` mimalloc-bench ` 中:
```
(declare-fun x () (_ BitVec 16))
(declare-fun y () (_ BitVec 16))
(declare-fun z () (_ BitVec 16))
(declare-fun GCD () (_ BitVec 16))
(assert (= (bvmul ((_ zero_extend 16) x) ((_ zero_extend 16) GCD)) (_ bv300 32)))
(assert (= (bvmul ((_ zero_extend 16) y) ((_ zero_extend 16) GCD)) (_ bv900 32)))
(assert (= (bvmul ((_ zero_extend 16) z) ((_ zero_extend 16) GCD)) (_ bv333 32)))
(maximize GCD)
(check-sat)
(get-model)
```
###### tags: `Cprogramming`