Home > Erlang探索 > 高強度的port(Pipe)的性能測試

高強度的port(Pipe)的性能測試

September 13th, 2009 Leave a comment Go to comments

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: 高強度的port(Pipe)的性能測試

在我的項目里面, 很多運算logic是由外部的程序來計算的 那么消息先透過pipe發到外部程序,外部程序讀到消息, 處理消息, 寫消息, erlang程序讀到消息, 這條鏈路很長,而且涉及到pipe讀寫,上下文切換,這個開銷是很大的.但是具體是多少呢?

我設計了個這樣的ring. 每個ring有N個環組成, 每個環開個port. 當ring收到個數字的時候 如果數字不為0, 那么把這個數字發到外部成程序,這個外部程序echo回來數字,收到echo回來的消息后,把數字減1,繼續傳遞.當數字減少到0的時候 銷毀整個ring.
/* 注意這個數字非常重要 它影響了Erlang程序3個地方 1. epoll的句柄集大小 2. MAX_PORT 以及port的表格大小 3. open_port的時候 子進程關閉的文件句柄大小*/

root@nd-desktop:~/test#ulimit -n 1024 
root@nd-desktop:~/test# cat pipe_ring.erl 
-module(pipe_ring). 

-export([start/1]). 
-export([make_relay/1, run/3]). 

make_relay(Next)-> 
    Port = open_port({spawn, "/bin/cat"}, [in, out, {line, 128}]), 
    relay_loop(Next, Port). 

relay_loop(Next, Port) -> 
    receive 
        {Port, {data, {eol, Line}}} -> 
            Next ! (list_to_integer(Line) - 1), 
            relay_loop(Next, Port); 
        K when is_integer(K) andalso K > 0 -> 
            port_command(Port, integer_to_list(K) ++ "\n"), 
            relay_loop(Next, Port); 
        K when is_integer(K) andalso K =:=0 -> 
            port_close(Port), 
            Next ! K 
end. 

build_ring(K, Current, N, F) when N > 1 -> 
    build_ring(K, spawn(?MODULE, make_relay, [Current]), N - 1, F); 

build_ring(_, Current, _, F) -> 
    F(), 
    make_relay(Current). 

run(N, K, Par) -> 
    Parent = self(), 
    Cs = [spawn(fun ()-> Parent!run1(N, K, P) end) || P<-lists:seq(1, Par)], 
    [receive _-> ok end || _<-Cs]. 
    
run1(N, K, P)-> 
    T1 = now(), 
    build_ring(K, self(), N, fun ()-> io:format("(ring~w setup time: ~ws)~n", [P, timer:now_diff(now(), T1) /1000]), self() ! K end). 

start(Args) -> 
    Args1 = [N, K, Par] = [list_to_integer(atom_to_list(X)) || X<-Args], 
    {Time, _} = timer:tc(?MODULE, run, Args1), 
    io:format("(total run (N:~w K:~w Par:~w) ~wms ~w/s)~n", [N, K, Par, round(Time/1000), round(K*Par*1000000/Time)]), 
    halt(0). 
root@nd-desktop:~/test# erl +Bd -noshell +K true -smp disable -s pipe_ring start 10 100000 8 
(ring1 setup time: 0.021s) 
(ring2 setup time: 0.02s) 
(ring3 setup time: 0.019s) 
(ring4 setup time: 0.03s) 
(ring5 setup time: 0.018s) 
(ring6 setup time: 0.031s) 
(ring7 setup time: 0.027s) 
(ring8 setup time: 0.039s) 
(total run (N:10 K:100000 Par:8) 23158ms 34546/s) 

參數的意義:
N K Par
N:ring有幾個環 每個環開一個port
K:每個環傳遞多少消息
Par: 多少ring一起跑

總的消息數是 K * Par.

我們可以看到 每秒可以處理大概 3.4W個消息 我有2個核心. 也就是說每個消息的開銷大概是 30us. 每個port的創建時間不算多, 1ms一個.

root@nd-desktop:~/test# dstat 
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system-- 
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw 
33  18  50   0   0   1|   0     0 | 438B 2172B|   0     0 |5329    33k 
42  11  48   0   0   0|   0     0 | 212B  404B|   0     0 |5729    58k 
41  11  49   0   0   0|   0     0 | 244B 1822B|   0     0 |5540    59k 
40  11  49   0   0   0|   0     0 | 304B  404B|   0     0 |4970    60k 

注意上面的csw 達到6W每秒.

root@nd-desktop:~/test# pstree 
├─sshd─┬─sshd─┬─bash───pstree 
     │      │      └─bash───man───pager 
     │      ├─sshd───bash─┬─beam─┬─80*[cat] 
     │      │             │      └─{beam} 
     │      │             └─emacs 
     │      ├─sshd───bash───emacs 
     │      └─sshd───bash───nmon 

我們運行了80個echo程序(/bin/cat)

讀者有興趣的話可以用systemtap 詳細了解 pipe的讀寫花費,以及context_switch情況, 具體腳本可以向我索要.

root@nd-desktop:~# cat /proc/cpuinfo 
processor       : 1 
vendor_id       : GenuineIntel 
cpu family      : 6 
model           : 23 
model name      : Pentium(R) Dual-Core  CPU      E5200  @ 2.50GHz 
stepping        : 6 
cpu MHz         : 1200.000 
cache size      : 2048 KB 
physical id     : 0 
siblings        : 2 
core id         : 1 
cpu cores       : 2 
apicid          : 1 
initial apicid  : 1 
fdiv_bug        : no 
hlt_bug         : no 
f00f_bug        : no 
coma_bug        : no 
fpu             : yes 
fpu_exception   : yes 
cpuid level     : 10 
wp              : yes 
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts pni dtes64 monitor ds_cpl em 
bogomips        : 4987.44 
clflush size    : 64 
power management: 

結論是: 用port的這種架構的開銷是可以接受的.

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

Categories: Erlang探索 Tags: , , ,
  1. July 31st, 2010 at 09:33 | #1

    学习了~感谢

    [Reply]

  2. Ice
    December 31st, 2013 at 12:01 | #2

    当每次发送的每个消息的数据很大时,性能如何?

    [Reply]

    Yu Feng Reply:

    port基本上是以操作次数为代价的,数据量大就是增加内存拷贝的代价。

    [Reply]

  1. No trackbacks yet.