1. 程式人生 > >系統技術非業餘研究 » 量化Erlang程序排程的代價

系統技術非業餘研究 » 量化Erlang程序排程的代價

我們都知道erlang的基本哲學之一就是“小訊息大計算”,簡單的說就是儘可能的在訊息裡面攜帶完整的計算需要的資訊,然後計算要儘可能的多,最好遠超過訊息傳遞的代價。但是為什麼要這樣呢?erlang訊息傳送的效率是很高的, 參見這篇文章

Roughly speaking, I’m seeing 3.4 million deliveries per second one-way, and 1.4 million roundtrips per second (2.8 million deliveries per second) in a ping-pong setup in the same environment as previously – a 2.8GHz Pentium 4 with 1MB cache.

在我的機器上的演示下看看具體的數字:

$ erl 
Erlang R15B03 (erts-5.9.3.1)  [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.3.1  (abort with ^G)
1> ipctest:pingpong().
832296.5692402497
2> 

大概83萬每秒個訊息pingpong,測試程式涉及到二個Erlang程序ping和pong.
一個完整的流程涉及到 1. ping程序執行 2. ping程序等pong訊息被切出。 3. pong執行 4. pong等ping訊息被切出。這個流程涉及到二次Erlang程序的排程。
這是一個典型的erlang使用的場景,我們現在的問題是到底一個erlang程序排程的開銷是多少?
從erts的實現來看,erlang會呼叫schedule()函式來選擇下一個要排程的程序,而真正swapin和swapout的代價並不高,那我們來統計下schedule的開銷。

還是祭出我們偉大的stap,寫段調查程式碼先:

$ cat sch.stp
global total, coll_sch, sch
global exclude_sys_schedule

probe process("beam.smp").function("schedule") {
      sch[tid()] = gettimeofday_ns();
      total++;
}

probe process("beam.smp").function("schedule").return {
      tid = tid();
      e = gettimeofday_ns() - sch[tid];
      if (exclude_sys_schedule && e > 10 * 1000 * 1000 ) coll_sch <<< 0;
      else coll_sch <<< e;
}

function print_colls () {
      prt_line = 0;
      if(@count(coll_sch) >0) {
            printf("total %d, avg %d ns\n", total, @avg(coll_sch));
            printf("===========erts schedule(ns)===========\n");
            print(@hist_log(coll_sch));
            prt_line = 1;
      }

      if(prt_line) printf("--------------------------------------------------------------\n");
      delete coll_sch;
      delete sch;
      delete total;
}

probe timer.s(1) {
      print_colls();
}

probe begin {
      exclude_sys_schedule = $1
      println("x:");
}

$ PATH=/usr/local/lib/erlang/erts-5.9.3.1/bin/:$PATH sudo stap sch.stp 1
x:

如果排程器在不忙或者排程足夠多的程序後,需要收割epoll事件,也就是會呼叫sys_schedule,這個時間通常會是ms級別的,我們將之排除掉,避免對平均時間的很大幹擾。

然後我們執行上面的測試程式,我們收集到資料先下圖:
sch_time
從圖可以看出,我們的schedule每秒執行17萬次左右,每次的代價大概是3個us左右。

我們再配合執行 erlang:statistics(context_switches)以及{_, Reds} = erlang:statistics(reductions) 就可以更準確的看出來上下文切換和執行的規約數字,見下圖:
sch_ctx

考慮到stap統計的時候需要用到鎖,對目標程式的干擾還是很大的,我們來對比下有無干擾二種情況下的pingpong效能:

3> ipctest:pingpong().
100012.63959739232
4> ipctest:pingpong().
768416.6022861623

也就是說真實的類似pingpong排程開銷大概是測試到的1/7, 大概是0.5us左右。可見小訊息大計算是必要的。

小結: 量化資料是研究的基礎, 這裡拋磚引玉,希望引起大家的思考。

祝玩的開心!

Post Footer automatically generated by wp-posturl plugin for wordpress.