Archive

Author Archive

erlang定时器的强度测试

September 15th, 2009 3 comments

erlang的定时器在做网络程序的时候几乎无所不在, 语法层面的receive after,IO操作超时,driver内部等都大量使用timer,特别是tcp 在发送接收都有个超时。 如果你有大量的tcp链接, 就意味着大量的定时器。 那么定时器的性能就是个很大的考验。erts的定时器是个timer_wheel实现, 和linux内核用的差不多,大概支持百万级别的规模。 测试如下:

并发开N个进程 每个进程里面0-10秒的随机定时,模拟tcp超时的情况。每个定时器事件的流程是这样的 进程检查消息队列 没消息 注册定时器事件 进程换出 定时器超时 进程换入 处理定时器事件。

root@nd-desktop:~/test# cat ttimer.erl 
-module(ttimer). 
-export([start/1]). 

upmap(F, L) -> 
    Parent = self(), 
    Ref = make_ref(), 
    [receive {Ref, Result} -> Result end 
     || _ <- [spawn(fun() -> Parent ! {Ref, F(X)} end) || X <- L]]. 

loop(0)-> 
    ok; 

loop(Cnt)-> 
        receive after random:uniform(10000) -> cont end, 
        loop(Cnt-1). 

start([A1, A2]) -> 
         Start= now(), 
         N= list_to_integer(atom_to_list(A1)), 
         Cnt = list_to_integer(atom_to_list(A2)), 
         io:format("spawn ~w process, loop ~w~n", [N, Cnt]), 
         upmap(fun loop/1, lists:duplicate(N, Cnt)), 
         io:format("run ~w ms~n", [round(timer:now_diff(now(), Start) /1000)]), 
         done. 
root@nd-desktop:~/test# erl -smp disable -noshell +P 9999999 -s ttimer start 500000 10 -s erlang halt 
spawn 500000 process, loop 10 
run 63201 ms 

单cpu保持在70-80%, 63秒处理了500W个定时器事件, 大概每秒8W.

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

结论: 定时器处理还是比较费时间的。

Categories: Erlang探索 Tags:

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

September 13th, 2009 3 comments

在我的項目里面, 很多運算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的這種架構的開銷是可以接受的.

Categories: Erlang探索 Tags: , , ,

答erlang静态数据查询方式

September 4th, 2009 Comments off

主题:erlang静态数据查询方式的一种构想 http://www.javaeye.com/topic/461367

解决这个问题有2种方式:

1.  函数匹配
2.  per module constant pool

针对这个问题我做了个试验, 构建一个atom->int的查询。

yu-fengdemacbook-2:~ yufeng$ cat t.erl
-module(t).
-export([start/1, start/2]).

start([A1, A2])-&gt;
start(list_to_integer(atom_to_list(A1)), A2).

start(N, Meth)-&gt;
Start = erlang:now(),
dotimes(N, case Meth of m-&gt;fun dict_lookup/1; f-&gt;fun fun_lookup/1 end),
Stop = erlang:now(),
erlang:display( N / time_diff(Start, Stop)).

dotimes(0, _) -&gt;
done;
dotimes(N, F) -&gt;
F(N),
dotimes(N - 1, F).

time_diff({A1,A2,A3}, {B1,B2,B3}) -&gt;
(B1 - A1) * 1000000 + (B2 - A2) + (B3 - A3) / 1000000.0 .

dict_lookup(I) -&gt;
{ok, I} = dict:find(list_to_atom("x" ++ integer_to_list(I)), h1:get_dict()) .

fun_lookup(I) -&gt;
I = h2:lookup(list_to_atom("x" ++ integer_to_list(I))).
yu-fengdemacbook-2:~ yufeng$ cat make_dict
#!/opt/local/bin/escript
main([A])-&gt;
N = list_to_integer(A),
L = [{list_to_atom("x" ++ integer_to_list(X)), X} || X&lt;-lists:seq(1, N)],
D = dict:from_list(L),
io:format("-module(h1).~n-export([get_dict/0]).~nget_dict()-&gt;~n",[]),
erlang:display(D),
io:format(".~n"),
ok.
yu-fengdemacbook-2:~ yufeng$ cat make_fun
#!/opt/local/bin/escript
main([A])-&gt;
N = list_to_integer(A),
io:format("-module(h2).~n-export([lookup/1]).~n",[]),
[io:format("lookup(~p)-&gt;~p;~n",[list_to_atom("x" ++ integer_to_list(X)), X]) || X&lt;-lists:seq(1, N)],
io:format("lookup(_)-&gt;err.~n", []),
ok.
yu-fengdemacbook-2:~ yufeng$ head h1.erl
-module(h1).
-export([get_dict/0]).
get_dict()-&gt;
{dict,100,20,32,16,100,60,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[[x10|10],[x30|30],[x50|50],[x70|70],[x90|90]],[[x11|11],[x31|31],[x51|51],[x71|71],[x91|91]],[[x12|12],[x32|32],[x52|52],[x72|72],[x92|92]],[[x13|13],[x33|33],[x53|53],[x73|73],[x93|93]],[[x4|4],[x14|14],[x24|24],[x34|34],[x44|44],[x54|54],[x64|64],[x74|74],[x84|84],[x94|94]],[[x5|5],[x15|15],[x25|25],[x35|35],[x45|45],[x55|55],[x65|65],[x75|75],[x85|85],[x95|95]],[[x6|6],[x16|16],[x26|26],[x36|36],[x46|46],[x56|56],[x66|66],[x76|76],[x86|86],[x96|96]],[[x7|7],[x17|17],[x27|27],[x37|37],[x47|47],[x57|57],[x67|67],[x77|77],[x87|87],[x97|97]],[[x8|8],[x18|18],[x28|28],[x38|38],[x48|48],[x58|58],[x68|68],[x78|78],[x88|88],[x98|98]],[[x9|9],[x19|19],[x29|29],[x39|39],[x49|49],[x59|59],[x69|69],[x79|79],[x89|89],[x99|99]],[],[],[],[],[],[]},{[[x20|20],[x40|40],[x60|60],[x80|80],[x100|100]],[[x1|1],[x21|21],[x41|41],[x61|61],[x81|81]],[[x2|2],[x22|22],[x42|42],[x62|62],[x82|82]],[[x3|3],[x23|23],[x43|43],[x63|63],[x83|83]],[],[],[],[],[],[],[],[],[],[],[],[]}}}
.
yu-fengdemacbook-2:~ yufeng$ head h2.erl
-module(h2).
-export([lookup/1]).
lookup(x1)-&gt;1;
lookup(x2)-&gt;2;
lookup(x3)-&gt;3;
lookup(x4)-&gt;4;
lookup(x5)-&gt;5;
lookup(x6)-&gt;6;
lookup(x7)-&gt;7;
lookup(x8)-&gt;8;
yu-fengdemacbook-2:~ yufeng$ cat test.sh
#!/bin/bash

#OPT=+native
OPT=

echo "build $1..."
echo "make h1..."
./make_dict $1 &gt;h1.erl
echo "make h2..."
./make_fun $1 &gt;h2.erl
echo "compile h1..."
erlc $OPT  h1.erl
echo "compile h2..."
erlc $OPT h2.erl
echo "compile t..."
erlc $OPT t.erl

echo "running..."
echo "map..."
erl -s t start $1 m -noshell -s erlang halt
echo "fun..."
erl -s t start $1 f -noshell -s erlang halt

yu-fengdemacbook-2:~ yufeng$ ./test.sh 10000
build 10000...
make h1...
make h2...
compile h1...
compile h2...
compile t...
running...
map...
2.767323e+05
fun...
2.656819e+05
done.

在10000条记录的情况下 每个查询几个us, 速度不是很快.

结果发现 函数和constant pool在处理上上差不多快的。在实践中根据需要采用把。

转:CPU密集型计算 erlang和C 大比拼

August 30th, 2009 Comments off

原文地址:http://pseudelia.wordpress.com/2009/08/23/erlang-native-code-benchmark/

Normalerweise compiliert Erlang Bytecode (heißt das so in Erlang?). Das coole daran ist, dass man die beam files leicht auf anderen Rechnern benutzen kann. Aber die Geschwindigkeit von diesem Code hat mich nicht überzeugen können. Darum habe ich ausprobiert wie gut der native Code ist den Erlang baut.

Der Versuchsaufbau ist einfach: Ich habe eine simple rekursive Funktion geschrieben, die Fibonaccizahlen berechnet. Dann wir 5-mal Fibonacci von 40 berechnet und die Zeit gemessen. Das ganze mache ich mit nur einem Kern. Diesen Test mache ich insgesamt 3-mal. Einmal mit nativem Erlangcode, einmal mit nicht nativem Erlangcode und einmal mit einem in C geschriebenen Programm. Der Benchmark besteht aus drei Dateien:

cpu_intensive.erl:

-module(cpu_intensive).
-compile(export_all).

fib_test() -&gt;
 fib(40), fib(40), fib(40), fib(40), fib(40).

fib(0) -&gt; 1;
fib(1) -&gt; 1;
fib(N) -&gt; fib(N-1) + fib(N-2).

cpu_intensive.c

unsigned int fib(unsigned int n) {
 if (n == 0 || n == 1) {
 return 1;
 }
 return fib(n-1) + fib(n-2);
}

int main() {
 fib(40); fib(40); fib(40); fib(40); fib(40);
 return 0;
}

Makefile:
all: native normal c

native:
@erlc +native cpu_intensive.erl
@echo “”
@echo “Fibonacci Erlang native code”
@time erl -noshell -s cpu_intensive fib_test -s erlang halt

normal:
@erlc cpu_intensive.erl
@echo “”
@echo “Fibonacci Erlang non-native code”
@time erl -noshell -s cpu_intensive fib_test -s erlang halt

c:
@gcc -O0 -o cpu_intensive cpu_intensive.c
@echo “”
@echo “Fibonacci written in C without optimizations”
@time ./cpu_intensive
Ich habe obige drei Dateien angelegt und die Makefile ausgeführt. Das Ergebnis war bei meinem Core 2 Duo 8400

Fibonacci Erlang native code
13,99 real        13,00 user         0,95 sys

Fibonacci Erlang non-native code
116,81 real       115,46 user         1,00 sys

Fibonacci written in C without optimizations
11,14 real        11,10 user         0,00 sys

Categories: Erlang探索 Tags: , ,

erlang到底能够并发发起多少系统调用

August 25th, 2009 5 comments

为了测试下erlang的多smp能够每秒并发发起多少系统调用,这个关系到erlang作为网络程序在高并发下的评估。

首先crack下otp_src,因为erlang:now() 是调用了clock_gettime这个系统调用,但是遗憾的是这个now里面设计到很多mutex会导致不可预期的futex调用,所以需要做如下修改,
调用最廉价的getuid系统调用:

root@ubuntu:~# emacs otp_src_R13B/erts/emulator/beam/erl_bif_info.c
BIF_RETTYPE statistics_1(BIF_ALIST_1)
{
Eterm res;
Eterm* hp;

if (BIF_ARG_1 == am_context_switches) {
Eterm cs = erts_make_integer(erts_get_total_context_switches(), BIF_P);
hp = HAlloc(BIF_P, 3);
res = TUPLE2(hp, cs, SMALL_ZERO);
BIF_RET(res);
<span style="color: red;"> } else if (BIF_ARG_1 == am_ok) { /* Line 2713 */
getuid();
BIF_RET( am_ok);
</span> } else if (BIF_ARG_1 == am_garbage_collection) {
...
}

重新make下otp_src

[root@localhost ~]# cat tsmp.erl
-module(tsmp).
-export([start/1]).

loop(I, N)->;
%%   erlang:now(),
%%   os:timestamp(),
erlang:statistics(ok), %% call getuid

case N rem 100000 of
0 ->;
io:format("#~p:~p~n", [I, N]);
_->;
skip
end,

loop(I, N + 1).

start([X])->;
N = list_to_integer(atom_to_list(X)),
[spawn_opt(fun () -> loop(I, 0) end, [{scheduler, I}]) || I <-lists:seq(1, N)],
receive
stop ->;
ok
after 60000 ->;
ok
end,
init:stop().
#otp_src_R13B02/bin/erl  -sct db  -s tsmp start 8
。。。
#7:226500000
#1:228000000
#8:152600000
#5:150200000
#4:225600000
#3:222000000
#2:224000000
#6:226400000
#7:226600000
#1:228100000
#4:225700000
#8:152700000
#3:222100000

对其中一个调度器线程的trace

[root@wes263 ~]#  /usr/bin/strace  -c -p 4667
Process 4667 attached - interrupt to quit
PANIC: attached pid 4667 exited with 0
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
99.87    0.230051           0   3979319           getuid
0.08    0.000189           0      1924           poll
0.05    0.000116           0      1924           clock_gettime
0.00    0.000000           0       147        48 futex
------ ----------- ----------- --------- --------- ----------------
100.00    0.230356               3983314        48 total

调用序列是非常的合理的

机器配置是:

[yufeng@wes263 ~]$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Xeon(R) CPU           E5450  @ 3.00GHz
stepping        : 10
cpu MHz         : 1998.000
cache size      : 6144 KB
physical id     : 0
siblings        : 4
core id         : 0
cpu cores       : 4
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
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 syscall nx lm constant_tsc pni monitor ds_cpl vmx est tm2 cx16 xtpr lahf_lm
bogomips        : 5988.98
clflush size    : 64
cache_alignment : 64
address sizes   : 38 bits physical, 48 bits virtual
power management:

8个核心。

1分钟 erlang发起了getuid()系统调个数 ecug的8核心机器 222,100,000 × 8个核心 = 1700M 合每秒30M个系统调用

结论是:如果合理安排的话 erlang的性能是非常高的 同时可以利用到erlang的smp的巨大优势。

Categories: Erlang探索 Tags: , , ,

研究Erlang 4000小时以后

August 25th, 2009 9 comments

历经2年半,花了4000小时以后,对erlang的研究有了很大的进步,从原来的兴趣, 到现在的随意的crack, 调优,改进, 指导erlang程序架构的设计,中间经历了很多。

从一个有20年历史的网络程序身上我学到很多,包括高级服务器程序的架构,调度公平性,网络事件处理, 内存管理, 锁管理, SMP管理, 平台移植, 虚拟机,语言的基本构件,用户交互,调试, 诊断, 调优,工具。 也学会了使用OS提供的工具如systemtap, oprofile,内存, CPU工具来诊断,来定位问题,这个可以参考rhel的调优白皮书。

这个成熟系统带来的经验感受如同你窥视一台精密设计的机器,一环套着一环。看似小小的系统,里面凝聚着多少片论文,多少方法改进,顺着Erlang的演化历史,你也随着成长,其中的快乐是无法抗拒的,从中学到的东西绝不是一个库或者一个小程序能够带给你的。从中你会体会到一个大型系统是如何变成一个活生生的系统,实现者如何妥协,如何稳健的持续的改进。每一个Roadmap都值得期待。

感谢erlang的开发小组给我们带来这么好的东西,研究还将继续。。。

距离上次写这篇blog的时候半年又过去了,Erlang代码已经看了3遍了。。。

Categories: Erlang探索 Tags:

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

August 23rd, 2009 2 comments

前篇文章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) [source][/source] [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) [source][/source] [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][/source][/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模式编译的哦。。。

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