Skynet服務熱點火焰圖分析


最近花了一周時間對場景服務進行熱點分析,利用以前的火焰圖工具做了一點微小的貢獻,分享下心得(倉庫地址在https://github.com/spin6lock/skynet_systemtap_set)。

 

Skynet是一個輕量級的多線程在線游戲框架。線程作為worker,從服務的隊列中抽出有消息的,然后處理上面的消息。服務間通過發消息來相互通信。目前服務主要是用Lua進行編寫。

 

以前做的火焰圖工具,沒法單獨看一個skynet服務的堆棧,只能看到整個進程的。要想針對單個服務做優化分析,需要抓出skynet_context的地址,才能取到服務的id。一個服務對應的是一個Lua VM,在這個VM里,snlua.so會悄悄的將skynet_context地址塞進去REGISTRY。那么,我們只要將skynet_context取出來,然后判斷skynet_context->handle即可。這看似簡單的東西,在C里就一句話:

struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));

但是,翻譯成stap腳本后,就變成了:

        if (((((p->func))->tt_) == ((6 | (1 << 4))))) {
            next
        }
        else {
            gc = p->func->value_->gc
            closure = &@cast(gc, "GCUnion", @1)->cl
            func = &@cast(closure, "Closure", @1)->c //CClosure
            if (idx <= func->nupvalues) {
                upvalue_type = func->upvalue[idx - 1]->tt_
                if (upvalue_type != 2) {
                    next
                } /* only this one can enter counter */
                skynet_context = &@cast(func->upvalue[idx - 1]->value_->p, "skynet_context", @1)
                /* service id in decimal*/
                if (skynet_context->handle != strtol(@2, 10)) {
                    next
                }
            } else {
                next
            }
        }

感謝gcc -E,幫我展開了一重重的宏……

 

這個過程無比蛋疼,要將C翻譯成stp腳本。stp可以保護新手,避免搞掛內核,但是隨之而來的就是晦澀的指針運算魔法了。接下來打算試試用bcc寫了

 

Anyway,折騰出來一個火焰圖:

 

火焰圖取材於在內核取樣的數據點,縱向切一刀,表示當前時刻的lua棧。橫向表示統計時間內,各個棧幀的占比。橫向越長,時間越長。縱向越深,調用越深。顏色沒有關系,可以忽略

 

可以看到里面有個堆棧很高,說明調用深度很深,另外寬度也很大,說明調用頻次占比高。后來定位了一下這個函數,發現是多調了一次aoi同步……

優化后棧的深度變淺了,剩下的基本是壓測腳本跑的內容了。棧深度還能優化一下,到C函數的調用層次不宜過多。

 

好了,睡覺了……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM