Archive

Posts Tagged ‘hipe’

基于LLVM的高性能Erlang(Hipe)尝鲜

March 25th, 2014 11 comments

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

本文链接地址: 基于LLVM的高性能Erlang(Hipe)尝鲜

即将发布的R17A版本引入很重要的一个针对性能提升的特性:”Support the LLVM backend in HiPE”,具体改变参见这里. 我们知道Erlang是一门领域语言,第一天就是为电信工业高可用,集群和热更新环境而设计的,语言的性能一开始不是重点。直到R12版本才加入SMP多处理器,充分适应多核化的硬件发展趋势,从此向着高性能大步迈进。

Erlang的虚拟机是register based的,性能上和python类似,和c语言大概有7倍的差距。虽然大部分的集群和网络服务器,性能瓶颈在IO上面,而且这块erts(erlang运行期系统)做的非常的强大,但是一旦涉及到大量的计算,就有点麻烦了,因为它缺乏类似java jit那样强大的支持,让语言足够的快。解决方案是自己写nif、driver或者bif,但是会破坏稳定性。

它很早有自己的hipe, 主要是Uppsala University大学的Kostis Sagonas带领学生做的, 97年开始做的,性能的提升虽然不少,但是在架构上有些缺点,而且和otp团队是二个不同的团队,在稳定性上无法达到产品质量。为了进一步解决这个问题,他带着Christos Stavrakakis和Yiannis Tsiouris,重新实现了基于LLVM后端的Hipe,也就是erllvm,官方网站在这里.

官方描述如下:

ErLLVM is a project aiming at providing multiple back ends for the High Performance Erlang (HiPE) with the use of the LLVM infastructure.

这次R17发布就是把ErLLVM融入到erlang主干版本去。那么ErLLVM的技术改进点在哪里?看下面的图就明白了。

722x227-hipe_llvm_arch

最关键的一点就是之前的hipe自己从RTL生成硬件代码,而ErlLvm把这个事情交给了llvm专业去生成,它只做RTL->llvm层的薄薄的翻译,这样稳定性的问题就offload交给了llvm,而llvm的稳定性是经过社区规模考验的。

llvm_pipeline

这样就很好的解决了稳定性和性能的问题。 Read more…

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

最快的Erlang http hello world 服务器调优指南 (20Khttp短链接请求/S每桌面CPU)

November 4th, 2009 11 comments

erl的虚拟机有2种方式 plain版本的和smp版本的。 smp版本由于锁的开销相比要比plain版本的慢很多。而32位机器由于内存访问比64位的少,也会快出很多。所有我选择在32位的linux系统下调优这个httpd服务器。这个服务器就是实现个简单的功能,在browser下返回hello world。以下我们会先编译我们的优化版本的虚拟机,然后再分别测试R13B02的标准版本的和我们优化版的性能:

root@nd-desktop:/build_opt_plain# uname -a
Linux nd-desktop 2.6.31-14-generic #3 SMP Sun Nov 1 23:03:10 CST 2009 i686 GNU/Linux

#准备开发环境
root@nd-desktop:/# apt-get build-dep erlang

#下载otp R13B02-1源码包
root@nd-desktop:/# wget http://www.erlang.org/download/otp_src_R13B02-1.tar.gz

#解开patch包
root@nd-desktop:/# tar xzvf build_opt_plain.tar.gz

#解开源码包
root@nd-desktop:/# tar xzf otp_src_R13B02-1.tar.gz

#打补丁
root@nd-desktop:/# cd otp_src_R13B02-1
root@nd-desktop:/otp_src_R13B02-1# patch -p1 <../build_opt_plain/otp_src_R13B02-1_patch_by_yufeng
patching file erts/emulator/beam/erl_binary.h
patching file erts/emulator/beam/erl_process.c
patching file erts/emulator/beam/sys.h
patching file erts/emulator/drivers/common/inet_drv.c
patching file erts/preloaded/src/Makefile
patching file erts/preloaded/src/prim_inet.erl
patching file lib/asn1/src/Makefile
patching file lib/hipe/Makefile
patching file lib/parsetools/src/Makefile
root@nd-desktop:/otp_src_R13B02-1# ../build_opt_plain/build.plain
。。。

如果编译都没有任何错误的话, 就大功告成了。

好 现在我们开始性能比较:

#先加大文件句柄数

root@nd-desktop:/otp_src_R13B02-1# cd ../build_opt_plain
root@nd-desktop:/build_opt_plain# ulimit -n 99999

#标准发布版本
root@nd-desktop:/build_opt_plain# erlc ehttpd.erl
root@nd-desktop:/build_opt_plain# taskset -c 1 erl +K true +h 99999  +P 99999 -smp enable +S 2:1 -s ehttpd
Erlang R13B03 (erts-5.7.4)  [smp:2:1] [rq:2] [async-threads:0] [hipe] [kernel-poll:true]

ehttpd ready with 2 schedulers on port 8888
Eshell V5.7.4  (abort with ^G)
1>

#在另外的一台机器上发动ab测试

[root@localhost src]# ab -c 60 -n 100000 http://192.168.235.147:8888/
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.235.147 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Finished 100000 requests


Server Software:       
Server Hostname:        192.168.235.147
Server Port:            8888

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      60
Time taken for tests:   8.925945 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Total transferred:      5100051 bytes
HTML transferred:       1200012 bytes
Requests per second:    11203.29 [#/sec] (mean)
Time per request:       5.356 [ms] (mean)
Time per request:       0.089 [ms] (mean, across all concurrent requests)
Transfer rate:          557.92 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1  65.7      0    3001
Processing:     0    3   1.5      4       7
Waiting:        0    2   1.8      4       6
Total:          0    4  65.8      4    3007
WARNING: The median and mean for the waiting time are not within a normal deviation
        These results are probably not that reliable.

Percentage of the requests served within a certain time (ms)
  50%      4
  66%      4
  75%      4
  80%      4
  90%      5
  95%      5
  98%      5
  99%      5
100%   3007 (longest request)

标准smp版本1个CPU的结果是: 11203.29 [#/sec] (mean)

#启用hipe的标准版本

root@nd-desktop:/build_opt_plain# erlc +native +"{hipe, [o3]}" ehttpd.erl
root@nd-desktop:/build_opt_plain# taskset -c 1 erl +K true +h 99999  +P 99999 -smp enable +S 2:1 -s ehttpd
Erlang R13B03 (erts-5.7.4)  [smp:2:1] [rq:2] [async-threads:0] [hipe] [kernel-poll:true]

ehttpd ready with 2 schedulers on port 8888
Eshell V5.7.4  (abort with ^G)
1>

标准smp hipe版本1个CPU结果是: 12390.32 [#/sec] (mean)

#我们的优化版本

root@nd-desktop:/build_opt_plain#  ../otp_src_R13B02-1/bin/erlc  ehttpd.erl
root@nd-desktop:/build_opt_plain# taskset -c 1   ../otp_src_R13B02-1/bin/erl +K true +h 99999  +P 99999   -s ehttpd
Erlang R13B02 (erts-5.7.3)  [rq:1] [hipe] [kernel-poll:true]

ehttpd ready with 1 schedulers on port 8888
Eshell V5.7.3  (abort with ^G)
1>

优化版本单个cpu: 19662.37 [#/sec] (mean)

#启用hipe的优化版本

root@nd-desktop:/build_opt_plain#  ../otp_src_R13B02-1/bin/erlc +native +"{hipe, [o3]}"  ehttpd.erl
root@nd-desktop:/build_opt_plain# taskset -c 1   ../otp_src_R13B02-1/bin/erl +K true +h 99999  +P 99999   -s ehttpd
Erlang R13B02 (erts-5.7.3)  [rq:1] [hipe] [kernel-poll:true]

ehttpd ready with 1 schedulers on port 8888
Eshell V5.7.3  (abort with ^G)
1>

优化版本启用hipe单个cpu:20090.83 [#/sec] (mean)

附上我们的最小的高性能的http echo 服务器:

root@nd-desktop:/build_opt_plain# cat ehttpd.erl
-module(ehttpd).
-compile(export_all).


start() ->
    start(8888).
start(Port) ->
    N = erlang:system_info(schedulers),
    listen(Port, N),
    io:format("ehttpd ready with ~b schedulers on port ~b~n", [N, Port]),

    register(?MODULE, self()),
    receive Any -> io:format("~p~n", [Any]) end.  %% to stop: ehttpd!stop.

listen(Port, N) ->
    Opts = [{active, false},
            binary,
            {backlog, 256},
            {packet, http_bin},
            {raw,6,9,<<1:32/native>>}, %defer accept
            %%{delay_send,true},
            %%{nodelay,true},
            {reuseaddr, true}],

    {ok, S} = gen_tcp:listen(Port, Opts),
    Spawn = fun(I) ->    
                    register(list_to_atom("acceptor_" ++ integer_to_list(I)),
                             spawn_opt(?MODULE, accept, [S, I], [link, {scheduler, I}]))
            end,
    lists:foreach(Spawn, lists:seq(1, N)).

accept(S, I) ->
    case gen_tcp:accept(S) of
        {ok, Socket} -> spawn_opt(?MODULE, loop, [Socket], [{scheduler, I}]);
        Error    -> erlang:error(Error)
    end,
    accept(S, I).

loop(S) ->
    case gen_tcp:recv(S, 0) of
        {ok, http_eoh} ->
            Response = <<"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nhello world!">>,
            gen_tcp:send(S, Response),
            gen_tcp:close(S),
            ok;

        {ok, _Data} ->
            loop(S);

        Error ->
            Error
    end.

这个服务器是最小的,单是在多处理器和单cpu上都有非常好的性能。

root@nd-desktop:/build_opt_plain# cat /proc/cpuinfo
model name      : Pentium(R) Dual-Core  CPU      E5200  @ 2.50GHz

注:这个http服务器基本上是在c的程序跑,erlang的代码执行的很少, 所以hipe的提升效果不是很明显。对于复杂的业务,应该是有很大的帮助的。

附件里是用到的脚本和补丁。

我们可以得出结论:
hipe启用要比不启用快。
优化版本的和标准版本的 20090:11203, 性能提高了将近80% 还是非常可观的。

点击下载附件

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

Categories: Erlang探索 Tags: , , , ,

系统标准库的hipe支持(高级)

August 23rd, 2009 2 comments

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

本文链接地址: 系统标准库的hipe支持(高级)

前篇文章http://mryufeng.javaeye.com/blog/428845 讲述了如何启用erlang hipe支持,但是用户程序大量依赖的标准库如stdlib, kernel等默认都不是native模式的, 所以我们的程序虽然启用了hipe,但是只是部分启用了。用oprofile等工具可以看到我们的程序还是在process_main(虚拟机的代码解释 在这里)里面打转。 我们来个极致的,通通hipe化。

有2个方案可以解决:
1. 在编译otp_src的时候 export ERL_COMPILE_FLAGS=’+native +”{hipe, [o3]}”‘ 但是这个方案有个问题就是
native方式是和beam的模式有关的 如beam和beam.smp它的代码是不同的,但是所有的beam又公用一套库,这样只能舍弃一个了。所以这个方案就比较麻烦。

# erl
Erlang R13B01 (erts-5.7.2)  [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.2  (abort with ^G)
1>  %%没问题

#erl -smp disable
<HiPE (v 3.7.2)> Warning: not loading native code for module fib: it was compiled for an incompatible runtime system; please regenerate native code for this runtime system
....
Erlang R13B01 (erts-5.7.2)  [64-bit] [rq:1] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1&gt;

这个也可以通过修改 alias erl=erl -smp disable 以便欺骗编译器生成单cpu模式的beam
去绕过去

2. 动态编译, 等系统运行起来以后,动态把相关的模块编译一遍,这个思路看起来最简单。

我做了个原型 证明这样是可行的。。。

# cat hi.erl
-module(hi).
-export([do/0]).

do()-&gt;
[ turn(M, P)|| {M, P} &lt;-code:all_loaded(), P=/=preloaded].

turn(M, P) -&gt;
P1 = binary_to_list(iolist_to_binary(re:replace(filename:join(filename:dirname(P), filename:basename(P, ".beam")), "ebin", "src"))),
L = M:module_info(),
COpts = get_compile_options(L),

COpts1 = lists:foldr(fun({K, V}, Acc) when is_list(V) and is_integer(hd(V)) -&gt;[{K, tr(V)}] ++ Acc ; (Skip, Acc) -&gt; Acc ++ [Skip] end, [], COpts),
c:c(P1, COpts1 ++ [native, "{hipe, [o3]}"]).

tr(P)-&gt;
binary_to_list(iolist_to_binary(re:replace(P, "/net/isildur/ldisk/daily_build/otp_prebuild_r13b01.2009-06-07_20/", "/home/yufeng/"))).  %%%这个地方要根据实际情况调整 具体的参看 m(lists).

get_compile_options(L) -&gt;
case get_compile_info(L, options) of
{ok,Val} -&gt; Val;
error -&gt; []
end.

get_compile_info(L, Tag) -&gt;
case lists:keysearch(compile, 1, L) of
{value, {compile, I}} -&gt;
case lists:keysearch(Tag, 1, I) of
{value, {Tag, Val}} -&gt; {ok,Val};
false -&gt; error
end;
false -&gt; error
end.
#erl -nostick
Erlang R13B01 (erts-5.7.2) [/source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1&gt; mnesia:start().  %启动我们的应用程序
ok
2&gt; hi:do().
[{ok,io},
{ok,erl_distribution},
{ok,edlin},
{ok,error_handler},
{ok,io_lib},
{ok,hi},
{ok,filename},
{ok,orddict},
{ok,gb_sets},
{ok,inet_db},
{ok,inet},
{ok,ordsets},
{ok,group},
{ok,gen},
{ok,erl_scan},
{ok,kernel},
{ok,erl_eval},
{ok,ets},
{ok,lists},
{ok,sets},
{ok,inet_udp},
{ok,code},
{ok,ram_file},
{ok,dict},
{ok,packages},
{ok,gen_event},
{ok,heart},
{ok,...},
{...}|...]

3&gt; m(dict).
Module dict compiled: Date: August 23 2009, Time: 17.20
Compiler options:  [{cwd,"/home/yufeng/otp_src_R13B01/lib/stdlib/src"},
{outdir,"/home/yufeng/otp_src_R13B01/lib/stdlib/src/../ebin"},
{i,"/home/yufeng/otp_src_R13B01/lib/stdlib/src/../include"},
{i,"/home/yufeng/otp_src_R13B01/lib/stdlib/src/../../kernel/include"},
debug_info,<span style="color: red;">native,"{hipe, [o3]}"</span>]
Object file: /home/yufeng/otp_src_R13B01/lib/stdlib/src/../ebin/dict.beam

。。。

看到了是用native模式编译的哦。。。

不过编译过程中有几个模块是有点问题, 得改进下。

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