[Erlang 0078] Erlang HiPE 二三事

  1. 云栖社区>
  2. 博客>
  3. 正文

[Erlang 0078] Erlang HiPE 二三事

唐玄奘 2017-12-04 12:56:00 浏览1659
展开阅读全文

 HiPE(High Performance Erlang) 霸爷有一个一语中的的描述"erlang的hipe相当于jit, 根据语言评测有hipe支持在纯erlang的运算上会快2-3倍,这个性能的提升对于计算密集型的应用还是比较可观的。"

维基百科上关于Jit的资料:

即时编译(Just-in-time compilation),又称为动态翻译,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态直译。静态编译的程序在执行前全部被翻译为机器码,而直译执行的则是一句一句边运行边翻译。

即时编译器则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。

即时编译器有两种类型,一是字节码翻译,二是动态编译翻译。

微软的.NET Framework[1][2],还有绝大多数的Java实现[3],都依赖即时翻译以提供高速的代码执行。

 

编译启用HIPE选项可以这样:c(Module,[native,{hipe,HipeOptions}|MoreOptions). 或者在Emakefile添加对应的配置节;

关于hipe选项的可用参数,我们可以通过hipe:help_options()查看,下面是在我机器上的执行结果:

复制代码
Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.4  (abort with ^G)
1> hipe:help_options().
HiPE Compiler Options
 Boolean-valued options generally have corresponding aliases `no_...',
 and can also be specified as `{Option, true}' or `{Option, false}.

 General boolean options:
   [debug,load,pp_asm,pp_beam,pp_icode,pp_native,pp_rtl,time,timeout,verbose].

 Non-boolean options:
   o#, where 0 =< # =< 3:
     Select optimization level (the default is 2).

 Further options can be found below; use `hipe:help_option(Name)' for details.

 Aliases:
   pp_all = [pp_beam,pp_icode,pp_rtl,pp_native],
   pp_sparc = pp_native,
   pp_x86 = pp_native,
   pp_amd64 = pp_native,
   pp_ppc = pp_native,
   o0,
   o1 = [inline_fp,pmatch,peephole],
   o2 = [icode_range,icode_ssa_const_prop,icode_ssa_copy_prop,icode_type,
         icode_inline_bifs,rtl_lcm,rtl_ssa,rtl_ssa_const_prop,spillmin_color,
         use_indexing,remove_comments,concurrent_comp,binary_opt] ++ o1,
   o3 = [{regalloc,coalescing},icode_range] ++ o2.
ok
复制代码

 Note: another option is to compile your Erlang module to native code. Native code compiling is not available for every platform and OS, but on those that support it, it can make your programs go faster (about 20% faster, based on anecdotal evidence). To compile to native code, you need to use the hipe module and call it the following way: hipe:c(Module,OptionsList). You could also use c(Module,[{hipe,o3}]).when in the shell to achieve similar results. Note that the .beam file generated will no longer be portable across platforms like regular ones.

All you wanted to know 

 

   上面这幅图来自: All you wanted to know about the HiPE compiler [PDF]

   启用了HiPE的Erlang/OTP编译流程大体如下:

  1. 宏替换 代码解析 语法糖等助记符展开(比如record)
  2. Erlang Code ==> Core Erlang Code
    在Core Erlang层面会完成各种优化比如常数合并,内联函数展开.所谓常数合并,是指在编译时,就将源程序中常数表达式之值先行算出,而不必生成用于计算该常数表达式的代码.例如,可将表达式a+2*3翻译成a+6.这种常数合并在语法制导翻译时就可以完成. [Link]  内联函数之前有一篇相关的[Erlang 0029] Erlang Inline编译
  3. Core Erlang Code ==> BEAM virtual machine code
  4. 每个方法的BEAM代码首先被翻译成为ICode,ICode是具有高级功能语义的类汇编语言.
  5. 优化之后ICode翻译成RTL("register-transfer language" 一种底层类RISC的汇编语言).
    大多数Erlang运算在本次转换过程会转换成为机器运算指令.优化完成之后RTL代码翻译成实际的机器码.许多临时变量会映射到硬件寄存器和运行时堆栈.
  6. 最后,代码加载到运行时环境.

    Erlang/OTP运行时并存两种代码BEAM-code和native-code 这两种代码的互相调用由运行时负责适配,对用户这是透明的.

 

    Core Erlang 1.0.3 language specification [Link] 之前已经多次通过查看Core Erlang代码的方式去分析问题,还是颇有用的。

 
 
   最近一直在学习新东西,笔记整理停下了很久,慢慢恢复。
 
2012-11-05 09:56 更新
复制代码
maybe_hipe_compile() ->
    {ok, Want} = application:get_env(rabbit, hipe_compile),
    Can = code:which(hipe) =/= non_existing,
    case {Want, Can} of
        {true,  true}  -> hipe_compile();
        {true,  false} -> io:format("Not HiPE compiling: HiPE not found in "
                                    "this Erlang installation.~n");
        {false, _}     -> ok
    end.

hipe_compile() ->
    Count = length(?HIPE_WORTHY),
    io:format("HiPE compiling:  |~s|~n                 |",
              [string:copies("-", Count)]),
    T1 = erlang:now(),
    PidMRefs = [spawn_monitor(fun () -> [begin
                                             {ok, M} = hipe:c(M, [o3]),
                                             io:format("#")
                                         end || M <- Ms]
                              end) ||
                   Ms <- split(?HIPE_WORTHY, ?HIPE_PROCESSES)],
    [receive
         {'DOWN', MRef, process, _, normal} -> ok;
         {'DOWN', MRef, process, _, Reason} -> exit(Reason)
     end || {_Pid, MRef} <- PidMRefs],
    T2 = erlang:now(),
    io:format("|~n~nCompiled ~B modules in ~Bs~n",
              [Count, timer:now_diff(T2, T1) div 1000000]).
复制代码

网友评论

登录后评论
0/500
评论
唐玄奘
+ 关注