Archive

Archive for the ‘Erlang探索’ Category

erl_nif Erlang的ffi 扩展erlang的另外一种方法

November 26th, 2009 11 comments

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

本文链接地址: erl_nif Erlang的ffi 扩展erlang的另外一种方法

我们知道扩展erl有2种方法, driver和port. 这2个方法效率都低,因为都要经过 port机制,对于简单的模块,这个开销有时候是不可接受的。这时候nif来救助了。今天发布的R13B03已经支持了,虽然是实验性质的。 erl_nif的代表API functions for an Erlang NIF library。 参考文档:
erl_nif.html 和 erlang.html#erlang:load_nif-2 以及 reference_manual/code_loading.html#id2278318 。

我们来用nif写个最简单的hello, 来展现nif的威力和简单性。
不啰嗦,直接上代码:

root@nd-desktop:~/niftest# cat niftest.c
/* niftest.c */
#include "erl_nif.h"
static ERL_NIF_TERM hello(ErlNifEnv* env)
{
return enif_make_string(env, "Hello world!");
}
static ErlNifFunc nif_funcs[] =
{
{"hello", 0, hello}
};
ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)
root@nd-desktop:~/niftest# cat niftest.erl
-module(niftest).
%-on_load(init/0).
-export([init/0, hello/0]).
init() ->
ok=erlang:load_nif("./niftest", 0), true.
hello() ->
"NIF library not loaded".

编译:

root@nd-desktop:~/niftest# gcc -fPIC -shared -o niftest.so niftest.c -I   /usr/local/lib/erlang/usr/include  #你的erl_nif.h路径

运行:

root@nd-desktop:~/niftest# erl
Erlang R13B03 (erts-5.7.4) [source][/source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]</code>

Eshell V5.7.4  (abort with ^G)
1> c(niftest).
{ok,niftest}
2> niftest:hello().
"NIF library not loaded"
3> niftest:init().
ok
4> niftest:hello().
"Hello world!"
5>

现在重新修改下 niftest.erl 把on_load的注释去掉

root@nd-desktop:~/niftest# erl
Erlang R13B03 (erts-5.7.4) [source][/source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]</code>

Eshell V5.7.4  (abort with ^G)
1&gt; c(niftest).
{ok,niftest}
2&gt; niftest:hello().
"Hello world!"
3&gt;

综述: nbif很简单,而且高效。

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

Categories: Erlang探索 Tags:

escript的高级特性

November 25th, 2009 7 comments

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

本文链接地址: escript的高级特性

escript Erlang scripting support, 可以让erl模块转身变成unix script来使用,大大方便用户,具体的使用参看otp文档。我这里要演示的是些比较被忽视的高级特性:

首先crack erts/etc/common/escript.c:33 static int debug = 1; 让之显示调用参数。

root@nd-desktop:~# cat &gt;factorial
[color=red]#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose[/color]
main([String]) ->
try
N = list_to_integer(String),
F = fac(N),
io:format("factorial ~w = ~w\n", [N,F])
catch
_:_ ->
usage()
end;
main(_) ->
usage().

usage() ->
io:format("usage: factorial integer\n"),
halt(1).

fac(0) -> 1;
fac(N) -> N * fac(N-1).

CTRL+D

root@nd-desktop:~# chmod +x factorial
root@nd-desktop:~# ./factorial  10

[color=red]erl +B -boot start_clean -noshell -smp enable -sname factorial -mnesia debug verbose -run escript start -extra ./factorial 10[/color]
factorial 10 = 3628800

特性1:

摘抄文档。。。
On the third line (or second line depending on the presence of the Emacs directive), it is possible to give arguments to the emulator, such as

%%! -smp enable -sname factorial -mnesia debug verbose

Such an argument line must start with %%! and the rest of the line will interpreted as arguments to the emulator.

我们可以看到 这些选项被传递给了 erl

特性2:
-mode(compile).

这个选项是在escript.erl这个模块处理的。默认情况下 escript是被解释执行的,如果你的脚本很复杂,那么效率估计会是瓶颈。这种情况下, 你可以通过这个选项来让escript来先编译你的模块成opcode, 在vm里面运行。

特性3:
-d 选项 用来调试script的
-c 编译执行
-i 解释执行
-s 只检查不执行
root@nd-desktop:~# escript -d ./factorial 10
我们就可以看到 调试界面如下图
escript_debug

特性4:
可以把一个beam文件作为script

root@nd-desktop:/usr/src# cat hello.erl
-module(hello).
-export([start/0,main/1]).

main(_)->
start().

start()->
io:format("hello world~n",[]).
root@nd-desktop:/usr/src# erlc hello.erl
root@nd-desktop:/usr/src# cat &gt;hello
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose

CTRL+D

root@nd-desktop:/usr/src# cat hello.beam &gt;&gt;hello
root@nd-desktop:/usr/src# chmod +x hello
root@nd-desktop:/usr/src# ./hello
hello world

特性5:
可以把一个zip文件作为script

root@nd-desktop:/usr/src# cat hello.erl
-module(hello).
-export([start/0,main/1]).

main(_)->
start().

start()->
io:format("hello world, fac(10)=~w ~n",[fac:fac(10)]).
root@nd-desktop:/usr/src# cat fac.erl
-module(fac).
-export([fac/1]).

fac(0) ->
1;
fac(N) -> N * fac(N-1).
root@nd-desktop:/usr/src# erlc *.erl
root@nd-desktop:/usr/src# erl
Erlang R13B03 (erts-5.7.4)
[smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1&gt; zip:zip("hello.zip", ["hello.beam", "fac.beam"]).
{ok,"hello.zip"}
2&gt;
root@nd-desktop:/usr/src# cat &gt;hello
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose -escript main hello

CTRL+D

root@nd-desktop:/usr/src# cat hello.zip &gt;&gt;hello
root@nd-desktop:/usr/src# chmod +x hello
root@nd-desktop:/usr/src# ./hello
hello world, fac(10)=3628800

特性6:
在独立的包里面 把escript伪装成我们的应用程序

root@nd-desktop:/usr/src# cat &gt;hello.escript
-module(hello).
-export([start/0,main/1]).

main(_)->
start().

start()->
io:format("hello world~n",[]).

CTRL+D

root@nd-desktop:/usr/src#  cp `which escript` hello
root@nd-desktop:/usr/src# ./hello
hello world

规则是 escript 改名成xxxx 执行xxxx的时候 实际上要读取的脚本是 xxxx.escript

综述: escript是很强大的 未来的erlang standalone全靠它。

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

Categories: Erlang探索 Tags: , , , ,

erl命令行工具链的设计思路

November 25th, 2009 2 comments

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

本文链接地址: erl命令行工具链的设计思路

erlang otp标准发布包里面的命令行工具都在bin目录下
dialyzer
erlc
escript
typer

erlang的这些命令行工具基本上都是erl模块的c的wrapper, 最后都是调用erl来运行相应的模块完成任务。

实验如下:

root@nd-desktop:~# touch test.erl

root@nd-desktop:~# erlc -d test.erl
 erl -noinput -mode minimal -boot start_clean -s erl_compile compile_cmdline @cwd /root @files test.erl

首先crack erts/etc/common/escript.c:33 static int debug = 1; 让之显示调用参数

root@nd-desktop:~# escript test.erl
 erl +B -boot start_clean -noshell -run escript start -extra test.erl

我们可以清楚的看到是如何调用相应的模块的。

那我们再看下 erl

root@nd-desktop:/usr/src/otp_src_R13B03# cat bin/erl
#!/bin/sh
#
# %CopyrightBegin%
# 
# Copyright Ericsson AB 1996-2009. All Rights Reserved.
# 
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
# 
# %CopyrightEnd%
#
ROOTDIR=/usr/src/otp_src_R13B03
BINDIR=$ROOTDIR/bin/i686-pc-linux-gnu
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
exec $BINDIR/erlexec ${1+"$@"}

这个erl程序其实是个shell script, 简单的设置下环境变量 然后调用erlexec来调用相应的VM。

但是为什么其他的都是binary程序, 唯独erl是script呢。 我能想出的唯一理由是: OTP team的人为了我们方便修改erl的行为 特地用脚本来写, 这样用户就可以很方便的定制erl.

如果我的猜测没错的话,那么erlang真的很细心。

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

Categories: Erlang探索 Tags: , ,

ECUG IV归来

November 10th, 2009 1 comment

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

本文链接地址: ECUG IV归来

昨天从杭州参加ECUG IV归来,日程安排的很满,虽然大家都很辛苦,但是到最后一个下午,还是很多人在会场,让人感觉气氛非常好。总的感觉是用erlang的人越来越多。 我这次演讲的topic: erlang系统的调优。 不少人感兴趣。附上现场照片一张。

现场照片

现场照片

猛击下载演讲稿
猛击下载视频

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

Categories: Erlang探索 Tags:

最快的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) [source][/source] [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) [source][/source] [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) [source][/source] [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) [source][/source] [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: , , , ,

Erlang如何查看gen_server系列的状态 (高级)

October 29th, 2009 1 comment

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

本文链接地址: Erlang如何查看gen_server系列的状态 (高级)

gen_server在erlang otp编程中的地位是无可撼动的,几乎都是gen_server或者gen_fsm的模型。那么程序运行起来的时候 我们如何查看gen_server的内部状态呢。有2种方法:
1. 自己写个类似于info这样的函数,来获取状态。
2. 利用系统现有的架构。sasl应用带了一个si的东西 全名是status inspector, 这个东西就是设计来帮用户解决这个问题的。

实验开始:

root@nd-desktop:~# cat abc.erl
-module(abc).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

-export([format_status/2]).
-export([test/0]).

-record(state, {a, b}).

-define(SERVER, ?MODULE).

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

test()->
    gen_server:call(?SERVER, {test, "param1"}).

init([]) ->
    {ok, #state{a=hello, b=world}}.

handle_call({test, _} = Request, _From, State) ->
    io:format("got msg ~p~n", [Request]),
    {reply, ok, State};

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

format_status(_Opt, [_PDict, #state{a=A,
                                    b = B
                                    }]) ->
   
    [{data, [{"a===", A},
             {"b===", B}]}].
root@nd-desktop:~# erl -boot start_sasl
Erlang R13B03 (erts-5.7.4) [source][/source][/source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]


=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.35.0>},
                       {name,alarm_handler},
                       {mfa,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.36.0>},
                       {name,overload},
                       {mfa,{overload,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.34.0>},
                       {name,sasl_safe_sup},
                       {mfa,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.37.0>},
                       {name,release_handler},
                       {mfa,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
         application: sasl
          started_at: nonode@nohost
Eshell V5.7.4  (abort with ^G)
1> si:start(). %必须手动启动

=PROGRESS REPORT==== 29-Oct-2009::16:07:31 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.43.0>},
                       {name,si_server},
                       {mfa,{si_sasl_supp,start_link,[[]]}},
                       {restart_type,temporary},
                       {shutdown,brutal_kill},
                       {child_type,worker}]
{ok,<0.43.0>}
2> si:help().

Status Inspection tool - usage
==============================
    For all these functions, Opt is an optional argument
    which can be 'normal' or 'all'; default is 'normal'.
    If 'all', all information will be printed.
    A Pid can be: "<A.B.C>", {A, B, C}, B, a registered_name or an abbrev.
ANY PROCESS
si:pi([Opt,] Pid)   - Formatted information about any process that
                      SI recognises.
si:pi([Opt,] A,B,C) - Same as si:pi({A, B, C}).
si:ppi(Pid)         - Pretty formating of process_info.
                      Works for any process.
MISC
si:abbrevs()        - Lists valid abbreviations.
si:start_log(Filename) - Logging to file.
si:stop_log()
si:start()          - Starts Status Inspection (the si_server).
si:start([{start_log, FileName}])
si:stop()           - Shut down SI.
ok
3> abc:start_link().
{ok,<0.46.0>}
4> abc:test().
got msg {test,"param1"}
ok
5> sys:log(abc,true). %打开gen_server的消息log功能
ok
6> abc:test().  %这个请求消息被记录
got msg {test,"param1"}
ok
7> si:pi(abc). %好戏开始

Status for generic server abc                                                 
===============================================================================
Pid                                                                    <0.46.0>
Status                                                                  running
Parent                                                                 <0.41.0>
Logged events  %这个是log到的消息
         {10,
         [{{out,ok,<0.41.0>,{state,hello,world}},
           abc,
           {gen_server,print_event}},
          {{in,{'$gen_call',{<0.41.0>,#Ref<0.0.0.85>},{test,"param1"}}},
           abc,
           {gen_server,print_event}}]}

%这个是format_status的结果  如果没有format_status那么导出是 {a=hello, b=world}

a===                                                                      hello
b===                                                                      world

ok
8> si:ppi(abc).

Pretty Process Info
-------------------
[{registered_name,abc},
{current_function,{gen_server,loop,6}},
{initial_call,{proc_lib,init_p,5}},
{status,waiting},
{message_queue_len,0},
{messages,[]},
{links,[<0.41.0>]},
{dictionary,[{'$ancestors',[<0.41.0>]},{'$initial_call',{abc,init,1}}]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.25.0>},
{total_heap_size,233},
{heap_size,233},
{stack_size,9},
{reductions,117},
{garbage_collection,[{fullsweep_after,65535},{minor_gcs,0}]},
{suspending,[]}]
ok

9> sys:get_status(abc).
{status,<0.46.0>,
        {module,gen_server},
        [[{'$ancestors',[<0.41.0>]},{'$initial_call',{abc,init,1}}],
         running,<0.41.0>,
         [{log,{10,
                [{{out,ok,<0.41.0>,{state,hello,world}},
                  abc,
                  {gen_server,print_event}},
                 {{in,{'$gen_call',{<0.41.0>,#Ref<0.0.0.85>},
                                   {test,"param1"}}},
                  abc,
                  {gen_server,print_event}}]}}],
         [abc,{state,hello,world},abc,infinity]]}

结论:
这个是文档未公开的功能。上面演示了如何sys打开log, 如何察看gen_server的状态

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

Categories: Erlang探索 Tags: , , , ,

Erlang和port通讯的数据格式

October 22nd, 2009 3 comments

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

本文链接地址: Erlang和port通讯的数据格式

erlang内置的port非常强大,是erlang通往外面世界的通道,所以port和erlang程序的通讯的数据格式影响了通讯的效率,和稳定性。我们在选择格式的时候, 会优先考虑到erlang的特性和port程序编写语言的特点,选出一种2者都容易处理的格式。

通讯通常有2种,基于行的文本和2进制格式。

行通讯最容易,因为是文本,调试起来就很方便。 形如这样的格式:
request args\n erlang编码这种格式就是加个\n, 解码可以用driver的{line, xxx}选项。而外部程序比如说c 解码可以用fgets, 编码也是加个\n. 缺点是: 表达上比较受限 不好表示结构数据。

2进制格式,形如这样的格式:
4个字节包长度 包体 . erlang和解码都可以利用driver的{packet,4} 自动把包体接处理。而外部程序比如说c 处理这样的也非常轻松。

包体有以下几种留下的格式:
1. 自定义格式。 比如: 4个字节cmd + 2个字节字符长度 + 字符
只要erlang和外部程序都能同样这种格式就好。erlang有很强大的binary处理这种事情很轻松, c同样也是。 缺点是太繁琐,格式变化的时候 容易漏掉东西。

2. erlang的外部协议格式。 erlang编码可以用term_to_binary, 解码用binray_to_term. c程序用ei库俩编解码。 这样erlang端的工作量就很小, c端的麻烦些。

3. json这样的格式。 erlang和c都用现成的json库来编码解码。

4. asn.1格式。erlang有强大的内置的asn编码解码。c端也有asn1c这样的编解码器。 写个asn1规格 2边各自生成代码,这样最轻松 而且能表达数据很轻松,推荐使用。

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