上次说请 mryufeng 同学多写写研究心得,还推说不大爱写长东西。隔不了几天,跑到他的 blog 上一看,乖乖龙的东!整了一大堆秘笈,原来是要藏私!说不得,对于这样同志,只能揪出来示众了。注意,以下内容全部是“海贼版”,未经作者明确同意,请慎入!
1, erl CTRL+C 的未公开功能
在erl shell下按下CTRL+C的时候,显示:
- BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
- (v)ersion (k)ill (D)b-tables (d)istribution
注:*nix 下的 erl 才有,windows 下的 erl 按 ctrl+C 就直接退出了。
但是实际上可以有更多功能,看代码:
- while (1) {
- if ((i = sys_get_key(0)) <= 0)
- erl_exit(0, "");
- switch (i) {
- case 'q':
- case 'a':
- case '*': /*
- * The asterisk is an read error on windows,
- * where sys_get_key isn't that great in console mode.
- * The usual reason for a read error is Ctrl-C. Treat this as
- * 'a' to avoid infinite loop.
- */
- erl_exit(0, "");
- case 'A': /* Halt generating crash dump */
- erl_exit(1, "Crash dump requested by user");
- case 'c':
- return;
- case 'p':
- process_info(ERTS_PRINT_STDOUT, NULL);
- return;
- case 'm':
- return;
- case 'o':
- port_info(ERTS_PRINT_STDOUT, NULL);
- return;
- case 'i':
- info(ERTS_PRINT_STDOUT, NULL);
- return;
- case 'l':
- loaded(ERTS_PRINT_STDOUT, NULL);
- return;
- case 'v':
- erts_printf("Erlang (%s) emulator version "
- ERLANG_VERSION "\n",
- EMULATOR);
- erts_printf("Compiled on " ERLANG_COMPILE_DATE "\n");
- return;
- case 'd':
- distribution_info(ERTS_PRINT_STDOUT, NULL);
- return;
- case 'D':
- db_info(ERTS_PRINT_STDOUT, NULL, 1);
- return;
- case 'k':
- process_killer();
- return;
- #ifdef OPPROF
- case 'X':
- dump_frequencies();
- return;
- case 'x':
- {
- int i;
- for (i = 0; i <= HIGHEST_OP; i++) {
- if (opc[i].name != NULL) {
- erts_printf("%-16s %8d\n", opc[i].name, opc[i].count);
- }
- }
- }
- return;
- case 'z':
- {
- int i;
- for (i = 0; i <= HIGHEST_OP; i++)
- opc[i].count = 0;
- }
- return;
- #endif
- #ifdef DEBUG
- case 't':
- p_slpq();
- return;
- case 'b':
- bin_check();
- return;
- case 'C':
- abort();
- #endif
- case '\n':
- continue;
- default:
- erts_printf("Eh?\n\n");
- }
- }
注:就是说,除了 a c p i l v k D d 之外,还有 A m o X x z ,如果在 DEBUG 下编译的,还有 t b C 可以用。
好多调试用的功能 希望对大家有用。
2,如何看erts内部的状态
经常在性能优化的时候 要看下erts内部的允许状态 erlang有未公开的函数
erts_debug:get_internal_state(XX)
XX为atom有以下几个
DECL_AM(node_and_dist_references);
DECL_AM(DbTable_words);
DECL_AM(next_pid);
DECL_AM(next_port);
DECL_AM(check_io_debug);
DECL_AM(available_internal_state);
DECL_AM(monitoring_nodes);XX为list有以下几个
DECL_AM(link_list);
DECL_AM(monitor_list);
DECL_AM(channel_number);
DECL_AM(have_pending_exit);可以看的很细节的运行期数据,前提是先用 erts_debug:set_internal_state(available_internal_state, true). 否者调用 get_internal_state 会提示失败.
3,erlang inet:setopts 未公开选项
inet:setopt有packet设置选项:
- {packet, PacketType} (TCP/IP sockets)
- Defines the type of packets to use for a socket. The following values are valid:
- raw | 0
- No packaging is done.
- 1 | 2 | 4
- Packets consist of a header specifying the number of bytes in the packet, followed by that number of bytes. The length of header can be one, two, or four bytes; the order of the bytes is big-endian. Each send operation will generate the header, and the header will be stripped off on each receive operation.
- asn1 | cdr | sunrm | fcgi | tpkt | line
- These packet types only have effect on receiving. When sending a packet, it is the responsibility of the application to supply a correct header. On receiving, however, there will be one message sent to the controlling process for each complete packet received, and, similarly, each call to gen_tcp:recv/2,3 returns one complete packet. The header is not stripped off.
- The meanings of the packet types are as follows:
- asn1 - ASN.1 BER,
- sunrm - Sun's RPC encoding,
- cdr - CORBA (GIOP 1.1),
- fcgi - Fast CGI,
- tpkt - TPKT format [RFC1006],
- line - Line mode, a packet is a line terminated with newline, lines longer than the receive buffer are truncated.
文档中写的就这么多了 其实还有2个选项:http, httph 用于解释http的请求,实现在 otp_src_R11B-5\erts\emulator\drivers\common\inet_drv.c 里:
- #ifdef USE_HTTP
- ...
- #endif
- /*
- ** load http message:
- ** {http_eoh, S} - end of headers
- ** {http_header, S, Key, Value} - Key = atom() | string()
- ** {http_request, S, Method,Url,Version}
- ** {http_response, S, Version, Status, Message}
- ** {http_error, S, Error-Line}
- */
消息以上面的方式发给process,用于 gen_tcp 由于在driver层面实现的,所以效率就很高,对于编写http隧道之类的程序 很有帮助哦。
注:得到一个提示,如果要在 erlang 中以极高的效率来实现某个东西,可以在 driver 层面入手。
4,erl_call erlang cnode 功能强大
otp_src_R11B-5\lib\erl_interface\src\prog\erl_call.c 是个不错的工具, 就是ei的前端能够通过cnode给erlang的后端发各种请求。
具体的见主题: 如何把erlang应用在项目中?
- where: -a apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'
- -c cookie string; by default read from ~/.erlang.cookie
- -d direct Erlang output to ~/.erl_call.out.
- -e evaluate contents of standard input (e.g echo "X=1,Y=2,{X,Y}."|erl_call -e ...)
- -h specify a name for the erl_call client node
- -m read and compile Erlang module from stdin
- -n name of Erlang node, same as -name
- -name name of Erlang node, expanded to a fully qualified
- -sname name of Erlang node, short form will be used
- -q halt the Erlang node (overrides the -s switch)
- -r use a random name for the erl_call client node
- -s start a new Erlang node if necessary
- -v verbose mode, i.e print some information on stderr
- -x use specified erl start script, default is erl
使用方法 :
1. erl -name xx@192.168.0.98 启动后端
2. export EI_TRACELEVEL=6
i. erl_call -v -d -n xx@erl98.3322.org -m 模块方式 ( -v -d 调试和verbose模式)
如: -module(a).
CTRL+D
ii. erl_call -v -d -n xx@erl98.3322.org -e 表达式方式
如: 1+2.
CTRL+D
iii. erl_call -v -d -n xx@erl98.3322.org -a ‘erlang length [[a,b,c]]’这两种都是从stdin读 直到你按下CTRL+D, 然后你就可以看到结果。
另外,这只程序有内存泄漏
- * Note: We don't free any memory at all since we only
- * live for a short while.
而且 erl_call.c有bug,第812行
- free(mbuf); /* Allocated in read_stdin() */
注释掉这行就可以了
这个程序默认是不安装带标准发布目录去的。
从这个程序 我们可以知道cnode 能作的事情受限于你的想像力。
注:
ping erl98.3322.org
PING erl98.3322.org (192.168.0.98) 56(84) bytes of data.由于erl_call程序有点小问题 -n xx@erl98.3322.org 最好用域名 否者erl_call就抓狂了。
copy & paste 后感:“非业余研究”就是不一样啊,硕果累累的。mryufeng 同学,好样的!