最近給 LuaJIT 實現一個新功能,在性能優化過程當中,經過一點小改動,讓 JIT 編譯器少生成一行機器指令,性能提高了兩個數量級 ...性能優化
具體是這樣子的,JIT 編譯器生成出來的機器碼,其中主要的部分是這樣子的:併發
mov rbp, [rcx] // 優化後,少了這一行了 cmp rbp, +0x05 jb 0x16ae0018 ->2 add rbp, -0x05 mov [rcx], rbp
是的,只是少了一行內存讀取指令,性能卻能夠提高兩個數量級。性能
接下來咱們分析一下其中的原因:優化
首先對於 CPU 而言,確定是多了一個內存讀取的操做。可是多了這麼一個操做,應該不至於產生數量級的性能差別的。
LuaJIT 是單線程的,讀寫內存應該是在操做 「獨享」 的 CPU cache,這個仍是很快的。
並且原來也是有一個寫內存操做的,若是是提高了一倍,仍是能夠理解的,有這麼大的差距應該仍是另有緣由。線程
咱們仔細分析下 mov rbp, [rcx]
後面的幾條指令,所有都依賴 rbp
這個寄存器的值。
這是一個典型的 「先讀後寫」 的依賴,若是內存沒有讀取到寄存器 rbp
中,後續幾條指令所有都會由於缺少操做數,致使 CPU 流水線阻塞等待。code
對於現代 CPU 十幾級的流水線而言,流水線阻塞的影響可就大多了。內存
這種指令級的優化,須要對 CPU 內部的執行細節有清楚的瞭解,而 CPU 實際執行的具體過程又沒有直觀的過程信息,只能多作實驗,經過執行時間的差別來對比分析了。編譯器
對於現代 CPU,其實硬件部分就已經很 「智能」 了,CPU 內部也會 「併發」 執行沒有依賴的機器指令,也就是常言的亂序執行。因此,有些時候指令數量增長了,可是執行時間不必定會成比例增長。編譯
可是,若是指令之間有依賴關係,那就會致使流水線的阻塞等待。這裏的例子,其實並非內存讀取很慢,而是由於內存的讀寫操做,致使了指令之間的依賴。硬件