Erlang进程创建时间统计及SMP现象.

来源:互联网 发布:网贷推广代理平台源码 编辑:程序博客网 时间:2024/05/16 08:41

看到Erlang编程指南里面的一个"进程创建"的性能基准测试,想放到我的环境里面用来对比一下打开SMP和关闭SMP的情况下的性能差异,结果和我未测试前想象的有点不一样.


#用例 1, 创建的进程之间有单向的消息发送.     SMP  4:4

7> timer:tc(create_process, start, [100000]).                              
{234828,ok}                                                                                       %%创建10w个进程, 花费了0.23秒
8> timer:tc(create_process, start, [1000000]).
{2283906,ok}                                                                                     %%创建100w个进程, 花费了2.28秒
9> timer:tc(create_process, start, [10000000]).
{23277706,ok}                                                                                   %%创建1000w个进程, 花费了23.2秒

#用例 2, 创建的进程之间有单向的消息发送.     SMP 关闭 

5> timer:tc(create_process, start, [100000]).  
{120949,ok}                                                                                       %%创建10w个进程, 花费了0.12秒
6> timer:tc(create_process, start, [10000000]).
{12299684,ok}                                                                                   %%创建100w个进程, 花费了1.23秒
7> timer:tc(create_process, start, [100000000]).
{122477601,ok}                                                                                 %%创建1000w个进程, 花费了12.2秒


从以上可以观察到两个现象:

1) Erlang创建进程的效率非常高, 100w个进程仅仅需要1,2秒的时间

2) 在打开了SMP的情况下比关闭SMP的情况下多花了近一倍的时间. 这个如何理解呢, 我开始猜测是因为在SMP打开的情形下, 不同的进程运行在不同的core上,然后跨core的进程之间的消息发送比关闭SMP的情况下同一个core上消息发送 花费的时间多,所以我猜测如果没有消息发送的话情况可能会不一样,于是我又跑了一个没有消息发送的测试.

#用例 3, 创建的进程之间无消息发送.     SMP  4:4

2> timer:tc(create_process, start_wo_msg, [100000]).
{251638,ok}                                                                                       %%创建10w个进程, 花费了0.25秒                                    
3> timer:tc(create_process, start_wo_msg, [1000000]).
{2211583,ok}                                                                                     %%创建100w个进程, 花费了2.21秒
4> timer:tc(create_process, start_wo_msg, [10000000]).
{21794646,ok}                                                                                   %%创建1000w个进程, 花费了21.7秒



#用例 4, 创建的进程之间无消息发送.     SMP  关闭

2>  timer:tc(create_process, start_wo_msg, [100000]).
{116281,ok}                                                                                       %%创建10w个进程, 花费了0.12秒             
3> timer:tc(create_process, start_wo_msg, [1000000]).
{1132018,ok}                                                                                     %%创建100w个进程, 花费了1.13秒             
4> timer:tc(create_process, start_wo_msg, [10000000]).
{10354658,ok}                                                                                   %%创建1000w个进程, 花费了10.4秒             


情况貌似没有什么变化, 那说明SMP多出来的时间并不是跨core的消息发送导致的, 那估计就是不同调度器的通信之间的额外花销了, 于是我们再做一个测试来验证一下是不是调度器之间的通信导致了多出来的时间花销


#用例 5, 创建的进程之间无消息发送.     SMP  4:1 ,只开启一个online scheduler, 没有scheduler之间的通信

2> timer:tc(create_process, start_wo_msg, [100000]).
{196128,ok}                                                                                       %%创建10w个进程, 花费了0.196秒 
3> timer:tc(create_process, start_wo_msg, [1000000]).
{1818807,ok}                                                                                    %%创建100w个进程, 花费了1.81秒 
4> timer:tc(create_process, start_wo_msg, [10000000]).
{18484187,ok}                                                                                  %%创建1000w个进程, 花费了18.4秒 


情况确实有所改善, 说明不同的调度器之间的通信确实有一些额外的时间消耗,但是这个也只是原因之一, 还有很多时间空缺没有发现是什么消耗的, 再推测推测, 估计是调度器计算分配进程到不同的core上这个过程占用了大部分的额外时间, 再来一个测试.


#用例 6 创建的进程之间无消息发送.     SMP  1:1 ,只配置一个逻辑内核. 这个用例

2> timer:tc(create_process, start_wo_msg, [100000]).
{182929,ok}                                                                                         %%创建10w个进程, 花费了0.182秒 
3> timer:tc(create_process, start_wo_msg, [1000000]).
{1708805,ok}                                                                                       %%创建100w个进程, 花费了1.71秒 
4> timer:tc(create_process, start_wo_msg, [10000000]).
{16924503,ok}                                                                                     %%创建1000w个进程, 花费了16.9秒 


我理解这个配置SMP  N:1,应该是没有什么区分的,只是说你在Erlang虚拟机启动之后有机会改变online scheduler的值(小于等于N) . 只要是只有一个online scheduler那其实就只有一个逻辑处理器被占用了,也就是说multi core的利用是由online scheduler来决定的. 假设系统有八个core,如果配置为8:4, 那CPU的利率率可以到400%, 如果是8:6, CPU的利用率可以到600%, 如果是N:1,那CPU的利用率可以到100%, 和N无关.


#用例 7 创建的进程之间无消息发送,  SMP  1:1  尝试用+sbt选项绑定scheduler.

实验了各种组合, ns, ts, ps, sct,情况, 测试结果基本和未绑定一致,  那只能猜测是, 在指定SMP 的情况下, Erlang虚拟机或者系统本身还有会有不少额外的消耗的.

从下面可见, 即使是SMP 1:1, Erlang虚拟机也额外为每个core启动了一个系统进程.

# SMP 1:1 

kilxxen2768: ~  > pstree -p 26457
beam.smp(26457)-+-erl_child_setup(26477)
                |-{beam.smp}(26472)
                |-{beam.smp}(26476)
                |-{beam.smp}(26478)
                `-{beam.smp}(26479)


#关闭SMP的情况

kilxxen2768: ~  > pstree -p 421
beam(421)---erl_child_setup(439)

#用例 8 创建的进程之间无消息发送,  SMP  1:1 , 用taskset绑定Erlang进程到指定的CPU Core 3上面

用linux命令手动绑定Erlang进程到指定的core上, 执行时间没有变化. 


beam.smp(26457)-+-erl_child_setup(26477)
                |-{beam.smp}(26472)
                |-{beam.smp}(26476)
                |-{beam.smp}(26478)
                `-{beam.smp}(26479)
kilxxen2768: ~  > taskset -cp 3 26457
kilxxen2768: ~  > taskset -cp 3 26477
kilxxen2768: ~  > taskset -cp 3 26472
kilxxen2768: ~  > taskset -cp 3 26476
kilxxen2768: ~  > taskset -cp 3 26478
kilxxen2768: ~  > taskset -cp 3 26479


测试代码文件 create_process.erl 

-module(create_process).
-compile(export_all).

%% 启动Num个进程,且进程之间有消息发送
start(Num)->
    start_proc(Num, self()).
start_proc(0, Pid)->
    Pid ! ok;
start_proc(Num, Pid)->
    NPid = spawn(?MODULE, start_proc,[Num-1, Pid]),
NPid!ok,
receive ok-> ok end.


%%启动Num个进程,进程之间无消息发送
start_wo_msg(0)->
    ok;
start_wo_msg(Num)->
    spawn(?MODULE, run, []),
    start_wo_msg(Num-1).

run() ->
    ok.


测试环境

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             4
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 45
Stepping:              7
CPU MHz:               2400.038
BogoMIPS:              4807.41
Hypervisor vendor:     Xen
Virtualization type:   para
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              20480K


##博客仅作个人记录##

0 0