Archive

Archive for the ‘网络编程’ Category

来自RHEL系统调优手册的几张经典图

July 20th, 2010 Yu Feng 2 comments

看图不说话:)

IO架构图:

内存管理图:

很容易误解的socket buffer:

Categories: 杂七杂八, 网络编程 Tags:

非阻塞connect的一个细节

May 18th, 2010 Yu Feng 3 comments

昨天听zhuzhaoyuan说的一个connect细节. 通常我们connect的时候都是非阻塞的, 在connect调用后把句柄挂到poll去, 等poll通知可写的时候, 我们就认为connect成功了. 但是在linux平台下实际上不一定成功, 具体的要用socket get_opt来检查下出错码来决定.

以下是从man 2 connnect摘抄的:

EINPROGRESS
The socket(2,7,n) is non-blocking and the connection cannot be com-
pleted immediately. It is possible to select(2,7,2 select_tut)(2) or poll(2) for
completion by selecting the socket(2,7,n) for writing. After select(2,7,2 select_tut)
indicates writability, use getsockopt(2) to read(2,n,1 builtins) the SO_ERROR
option at level SOL_SOCKET to determine whether connect com-
pleted successfully (SO_ERROR is zero) or unsuccessfully
(SO_ERROR is one of the usual error(8,n) codes listed here, explain-
ing the reason for the failure).

我们看下erlang的inet_drv是如何处理的.
./erts/emulator/drivers/common/inet_drv.c:

        {
            int error = 0;      /* Has to be initiated, we check it */
            unsigned int sz = sizeof(error); /* even if we get -1 */
            int code = sock_getopt(desc->inet.s, SOL_SOCKET, SO_ERROR,
                                   (void *)&error, &sz);

            if ((code < 0) || error) {
                desc->inet.state = TCP_STATE_BOUND;  /* restore state */
                ret = async_error(INETP(desc), error);
                goto done;
            }
        }

结论: 细节决定品质.

看图学TCP API以及状态变迁

January 28th, 2010 Yu Feng No comments

Categories: 网络编程 Tags: , , ,

用systemtap来修改下linux内核变量的值

October 29th, 2009 Yu Feng No comments

我们在探索linux内核的时候,经常需要调整下变量的值,看它对系统的影响。如果这个值没有透过/proc来修改的话,那只能编译内核。这个步骤是非常繁琐的。现在我们有systemtap这个利器来帮忙了。

演示如下:
我们通过修改过
extern int sysctl_tcp_fin_timeout;的值来达到目的。是因为这个值是proc导出的 我们好验证是否成功。

root@localhost ~]# cat /proc/sys/net/ipv4/tcp_fin_timeout
15000
[root@localhost ~]# cat test.stp
probe begin
{
        printf("ready go\n");
}

probe kernel.function("do_tcp_setsockopt")
{
        $sysctl_tcp_fin_timeout = $1
        printf("sysctl_tcp_fin_timeout = %d\n", $sysctl_tcp_fin_timeout);
        exit()
}

[root@localhost ~]# stap -g test.stp 18000
ready go

这个时候 stap在运行, 只是还没有触发do_tcp_setsockopt.
现在我们来触发

[root@localhost ~]# erl
Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.3  (abort with ^G)
1> {ok, LSock} = gen_tcp:listen(0, []).
{ok,#Port<0.437>}
2>
2> inet:setopts(LSock, [{nodelay,true}]).
ok
3>

Ok,这时候回头可以看到stap打出来以下:
sysctl_tcp_fin_timeout = 18000

我们来验证下:

root@localhost ~]# cat /proc/sys/net/ipv4/tcp_fin_timeout
18000

OK,成功。

Tips:
1. stap对全局变量的写需要-g guru模式。
2. 全局变量必须在一个单元内的函数里面才可以修改, 而且必须是在内核上下文。

Categories: 网络编程 Tags: , , , , ,

JVM 64位pointer compress, Erlang呢?

October 10th, 2009 Yu Feng No comments

前端时间看到JVM的 64 pointer compress技术,蛮多感慨的。具体的可以 google
64位 pointer compress 来了解更多。

好不容易从32位系统中逃脱,解决了4G内存的问题,而且64位的cpu更多的寄存器,可以带来更好的性能。但是怎么又碰到问题了。64位的系统,64位的指针,意味着更多的数据访问, cpu速度是提高了,但是内存的带宽和访问速度没有大的提高。而且内存的访问速度和cpu的cycle差几个数量级别,所以对于普通的网络程序来讲,大部分是处理信息的变形,也就是说是把内存里面的数据从一个形式变成另外一个形式。 cpu性能的提高对这种程序来讲 影响不是很大。倒是因为数据的量加大了1倍, 导致整体的性能降低了百分几十。实际的硬件系统也没有那么多内存,一般都是16G以下,所以才有人去想在64位系统下,用36位的指针,减少内存的访问。

erlang的系统基本上是个网络程序,所以这个问题就非常突出。 目前没看到otp vm的这方面的打算, 我还是乖乖的用我的32位系统

Categories: 网络编程 Tags: ,

erlang的profile工具原理和优缺点

October 6th, 2009 Yu Feng No comments

erlang的tools application下包含了一系列的profile工具, 包括 eprof cprof fprof, 具体的使用可以参看文档和<< erlang effective guide>>.

我这里要说的是他们的工作原理。 这些模块的核心都是根据erlang的trace机制实现的。在模块执行的时候,trace机制会通知那个函数被调用 返回。根据这些信息就可以统计出来函数调用的频度,调用栈等。

但是利用这个机制会有严重的性能损失。因为每个函数调用都要发送一条trace信息,每个trace 信息会引起上下文切换 而且要耗费2-3的时间。这个对大型的系统是不可接受的。

所以知道这些原理以后, 我们在profile大型的系统的时候,我们可以在dbg模块的帮助下, 只收集我们感兴趣的东西,而且严格限定范围,避免对系统造成大的干扰,这样收集出来的东西才有意义。

Categories: 网络编程 Tags:

如何用gdb调试erlang运行期(高级)

October 6th, 2009 Yu Feng No comments

前些天在erlang的源码里面闲逛的时候发现了 bin目录下的cerl,一看原来是个调试的高级货。

我之前写过一篇文章http://mryufeng.javaeye.com/blog/113852 如何调试erlang 但是这是土八路的方法, cerl才是现代化工业。

# This is a script to start Erlang/OTP for debugging. PATH is set to
# include this script so if slave nodes are started they will use this
# script as well.
#
# usage: cerl [ OPTIONS ] [ ARGS ]
#
# The OPTIONS are
#
# -rootdir $MYROOTDIR
# Run an installed emulator built from this source
# -debug Run debug compiled emulator
# -gdb Run the debug compiled emulator in emacs and gdb.
# You have to start beam in gdb using “run”.
# -break F Run the debug compiled emulator in emacs and gdb and set break.
# The session is started, i.e. “run” is already don for you.
# -xxgdb FIXME currently disabled
# -purify Run emulator compiled for purify
# -quantify Run emulator compiled for quantify
# -purecov Run emulator compiled for purecov
# -gcov Run emulator compiled for gcov
# -valgrind Run emulator compiled for valgrind
# -lcnt Run emulator compiled for lock counting
# -nox Unset the DISPLAY variable to disable us of X Windows
#

要使用cerl 我们最好准备个调试版本的erlang。R13B 修正了些编译错误,可以编译出debug版本的系统:./configure && make TYPE=debug && make

这样就生成了个beam.debug的运行期。

我们要调试的时候 就可以在otp的binx目录下运行 cerl -debug -gdb -break main

这时候cerl自动会加载 emacs 启动 gud, 整个过程都是自动的。但是这个脚本有点小问题, gud模型下没有把源码和当前对应的调试对应起来。可以通过以下方式修正:

yu-fengdemacbook-2:bin yufeng$ diff cerl cerl2
284c284
<     exec $EMACS --eval "(progn (gdb \"gdb $EMU\") $gdbcmd)"
---
>     exec $EMACS --eval "(progn (gdb \"gdb --annotate=3  $EMU\") $gdbcmd)"

具体的操作和界面可以参照这篇文章:

http://www.nabble.com/printing-of-Eterm%27s-from-gdb-td19240493.html

在调试的时候 我们会希望查看 eterm的值,但是由于eterm的格式非常复杂, gdb的print什么的无法满足我们的需求。 otp开发团队于是开发出了一套方法来减轻我们的负担:

1. erts/etc/unix/etp-commands 这是gdb的脚本 包含了几十个etp方法,而且文档非常详细。

2. 源码里面的 pp, ps等函数, 这些函数是专门为gdb调试开发的。 可以用gdb的 call pp(xxx)来调用。

有了这些工具 调试和研究erts变成了一件很快乐的事情!

Categories: 网络编程 Tags: