Xinfeng Liu

http://developers.sun.com.cn/blog/lxf/date/20080912 星期五 九月 12, 2008

使用Sun Studio 和Solaris工具解决Java的性能问题

Sun Studio的performance analyzer是能同时对JVM和Java代码的profiling工具,而且比 起那些基于Java的Profiling工具要好用的多。使用Netbeans Profiler时候最好把项目工程放进Netbeans IDE里才好用,否则不方便对被profiling的应用做细粒度的profiling控制,导致大型应用被profiling后运行非常慢。而Sun Studio的performance analyzer对应用性能的影响要小得多,而且使用起来很简便。只要 collect -j on java <arguments> 就可以了。运行完后会生成一个结果数据目录比如test.1.er,然后用analyzer test.1.er 进行图形化的显示和分析,或使用er_print test.1.er进行命令行的显示。

Sun Studio performance analyzer对java profiling结果的分析,可以按三种模式显示: user, expert, machine。因此可以同时分析用户的Java代码和JVM的C++代码。如果你要分析JNI的代码,这个工具更是离不开了。下面是一个例子:

er_print test.1.er

(er_print) limit 20
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
218.053   218.053    <JVM-System>
 44.511    44.581    <Unknown>
 33.123    35.195    oracle.jdbc.driver.NumberCommonAccessor.getBigDecimal(int)
 21.145    52.287    oracle.jdbc.driver.ClobAccessor.getString(int)
 15.401    30.982    java.util.HashMap.get(java.lang.Object)
 14.630    20.364    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 13.209    13.259    oracle.jdbc.driver.OracleStatement.prepareAccessors()
 13.159    81.157    org.apache.jsp.home_jsp._jspService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 12.429    15.271    oracle.jdbc.driver.T4C8TTIClob.read(byte[], long, long, boolean, char[])
 12.369    16.121    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 11.258    11.258    java.lang.String.equals(java.lang.Object)
 10.667    10.667    java.lang.Throwable.<init>()
  9.517     9.517    oracle.jdbc.driver.T4CConnection.createClobDBAccess()
  8.856    30.671    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
  6.364     6.364    java.lang.String.indexOf(int, int)
  5.844    21.935    java.lang.String.equalsIgnoreCase(java.lang.String)
  5.674     5.674    java.nio.CharBuffer.arrayOffset()
  4.733     4.733    java.util.Arrays.copyOfRange(char[], int, int)
  4.703     4.703    oracle.net.ns.DataPacket.getDataFromBuffer(byte[], int, int)

(er_print) viewmode expert
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
 33.123    35.195    oracle.jdbc.driver.NumberCommonAccessor.getBigDecimal(int)
 21.145    52.287    oracle.jdbc.driver.ClobAccessor.getString(int)
 19.534    19.534    lwp_yield
 17.232    17.232    OopStarTaskQueueSet::peek()
 15.401    30.982    java.util.HashMap.get(java.lang.Object)
 14.630    20.364    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 13.980    21.855    PhaseChaitin::build_ifg_physical(ResourceArea*)
 13.209    13.259    oracle.jdbc.driver.OracleStatement.prepareAccessors()
 13.159    81.137    org.apache.jsp.home_jsp._jspService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 13.129    13.289    IndexSetIterator::advance_and_next()
 12.429    15.271    oracle.jdbc.driver.T4C8TTIClob.read(byte[], long, long, boolean, char[])
 12.369    16.121    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 11.258    11.258    java.lang.String.equals(java.lang.Object)
 10.667    10.667    java.lang.Throwable.<init>()
  9.517     9.517    oracle.jdbc.driver.T4CConnection.createClobDBAccess()
  8.856    30.671    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
  7.475     7.475    arrayof_oop_disjoint_arraycopy
  6.585     8.736    PhaseChaitin::Split(unsigned)
  6.364     6.364    java.lang.String.indexOf(int, int)

(er_print) viewmode machine
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
111.688   546.232    Interpreter
 57.850    60.702    typeArrayKlass::allocate(int,Thread*)
 20.324    20.394    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 19.534    19.534    lwp_yield
 17.232    17.232    OopStarTaskQueueSet::peek()
 16.291    16.291    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 14.850    31.062    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
 13.980    21.855    PhaseChaitin::build_ifg_physical(ResourceArea*)
 13.129    13.289    IndexSetIterator::advance_and_next()
 11.638    11.638    java.lang.String.equals(java.lang.Object)
 11.588    15.000    java.lang.Object.hashCode()
  7.475     7.475    arrayof_oop_disjoint_arraycopy
  6.585     8.736    PhaseChaitin::Split(unsigned)
  6.545     6.545    java.lang.String.indexOf(int, int)
  5.754     5.754    jshort_disjoint_arraycopy
  5.484     5.484    flush_callers_register_windows
  5.324    16.742    java_lang_Throwable::fill_in_stack_trace(Handle,Thread*)
  5.284     5.284    memcpy
  5.014    18.333    java.util.Collections$SynchronizedMap.get(java.lang.Object)

有时,单单通过Java本身的工具(如jstat, jmap, jinfo, jconsole, java thread dump等)不足以分析出问题,还是需要依靠操作系统的工具来定位。比如pstack, prstat -mL -p <pid>,pmap -xs, DTrace等。假如通过prstat发现Java应用总是不能充分利用CPU,可以通过一个简单的DTrace脚本来找出原因:

offcpu.d
--------
#!/usr/sbin/dtrace -s
off-cpu
/pid == $target/
{
@[jstack(20,200)]=count();
}
tick-2sec
{
trunc(@,10);
printa(@);
clear(@);
}

# ./offcpu.d -p <java process id>

无论你愿不愿意承认,总之Java在Solaris上运行的最好,道理就不用说了。 


使用SUN Studio编译C++程序几个注意问题

不喜欢C++,不规范的C++代码的移植简直就是一场恶梦,即使是在同一种编译器的不同版本间移植也会令人痛苦不堪。Mozilla甚至给出了一个编码规范,以减少跨平台/跨编译器移植的麻烦。不符合该规范的代码一律被认为BUG,即使代码的功能正确。

不同编译器编出来的C++代码通常是不能混用的。因为C++有个符号mangling的问题,不同的编译器有不同的mangling方法,导致符号不通用。Solaris上的Java虚拟机是用Sun compiler编译的,因此如果你有JNI代码是C++写的,你应该用Sun compiler编译JNI代码。(当然Sun compiler是免费的)。编译各种操作系统平台的JNI代码的建议编译选项见Kelly O'Hair的blog。

Sun compiler编译可执行程序时会自动链接 -lCstd -lCrun -lm -lc ,但编共享库时却不会。所以编共享库时应该显式地加上这些链接选项。

Sun compiler 也同时提供标准C++库的stlport实现,编译时可以加上-library=stlport4以使用stlport的实现而不是自带的libCstd.so.1。但这二者在同一程序中不能混用。

如果用DTrace来调试C++程序,函数名要使用mangle过的符号,因为DTrace不认识C++(mdb也是这样)。想得到mangle过的符号可以通过nm -C <binary name> 得到。如果要跟踪函数的参数,第一个参数通常应该是arg1而不是arg0,因为C++中类成员函数映射成C代码后第一个参数一般都是this指针。比如下面的DTrace脚本跟踪某个函数的调用过程:

#!/usr/sbin/dtrace -qFs
pid$target::__xxxxxx_:entry
{
self->traced=1;
printf("thread #%d is doing %s \n", tid, copyinstr(arg1)); /* suppose arg1 type is char* */
}
pid$target::__xxxxxx_:return
{
self->traced=0;
}
pid$target:::entry
/self->traced/
{
printf("thread #%d is calling %s .\n", tid, probefunc);
}

pid$target:::return
/self->traced/
{
printf("thread #%d returns from %s .\n", tid, probefunc);
}

 

http://developers.sun.com.cn/blog/lxf/date/20080820 星期三 八月 20, 2008

Opensolaris 2008.05 Getting Started 中文版

入门指南已经有10种语言了。

http://dlc.sun.com/osol/g11n/content/IPS/zh/partition.html

http://www.opensolaris.com/learn/#localized

http://developers.sun.com.cn/blog/lxf/date/20080806 星期三 八月 06, 2008

Sun宣布Facebook应用myPicks Beijing 2008 (预测北京奥运结果的游戏)

今天打开我的facebook,发现这个游戏http://apps.facebook.com/mypicksbeijing/Home已经跳到了我的首页上,问我要不要加入。 这里面有太多可以说的东西:

这个应用运行在Sun的network.com上,基于Solaris 10, Glassfish和MySQL。

这个应用由Pramati Technologies开发,使用了zembly的开发平台。

zembly公司是SUN公司的一部分,它提供了一个基于浏览器的social应用开发环境,可以方便地创建和发布Facebook apps, Meebo apps, OpenSocial apps, iPhone apps, Google Gadgets, embeddable widgets, and other social applications.

Zembly由Sun公司的 Todd Fast 秘密开发了18个月,今年6月得以问世。

新闻原文:http://biz.yahoo.com/bw/080806/20080806005255.html?.v=2

 

http://developers.sun.com.cn/blog/lxf/date/20080730 星期三 七月 30, 2008

Sun Studio Express 7/2008发布,支持OpenMP 3.0

真够快的。OpenMP 3.0的 API规范2008年5月才发布,现在东西已经做出来了。当然Sun Studio Express不是Sun Studio的正式版本,是下一版本的预览版。GCC上月也加进了支持OpenMP 3.0的代码,但目前还没有发布,估计是在GCC 4.4里加进OpenMP 3.0的支持。

免费下载使用:
http://developers.sun.com/sunstudio/downloads/express/index.jsp

推荐有关Blog:

On the Record: http://blogs.sun.com/ontherecord/entry/sun_studio_express_07_08

Darryl Gove: http://blogs.sun.com/d/entry/sun_studio_express_release

Richard: http://blogs.sun.com/rchrd
also:  http://openmp.org/
also:  http://hpc.sun.com/
Yuan Lin: http://blogs.sun.com/yuanlin
Josh Simons: http://blogs.sun.com/simons/category/HPC
Kuldip Oberoi:  http://koberoi.com/
Vijay: http://blogs.sun.com/tatkar

http://developers.sun.com.cn/blog/lxf/date/20080729 星期二 七月 29, 2008

为什么opensolaris 2008.05关于系统调用的手册页都是空的

man -s 2 open (你看到了什么?) 

这是我在内部问到的答案:

Short answer: 系统调用的手册页是第三方写的,其license不允许包含在opensolaris 2008.05里。

Long answer: 为什么Solaris, Solaris Community Express, Solaris Developer Express包含系统调用的手册页?因为分发这些软件的人需要签协议同意那些License条款。 Opensolaris 2008.05 允许任何人分发/镜像,而无需签署协议。所以不能包含那些文件。

这可苦了软件开发人员了:要么上网访问联机手册页,要么登录到另一台Solaris机器看系统调用的man page。

用Opensource快把人培养成律师了:-) 一个小测验:假设opensolaris不放弃CDDL,Linux kernel不放弃GPL,如果要让Linux kernel 包含ZFS支持(不是User-level的),opensolaris和linux kernel需要怎样修改各自的License?


http://developers.sun.com.cn/blog/lxf/date/20080724 星期四 七月 24, 2008

SUN的开源产品列表

最近,SUN的开源产品大家族里新增了Sun Webserver 7.0和webproxy server。Sun Webserver和webproxy server是真正多线程的Web Server,在Specweb2005基准测试中屡创世界纪录。下面是我整理的SUN的开源列表,有问题或补充请写在comments里。

 软件名称 License 链接备注 
 OpenSolaris CDDL http://www.opensolaris.org 
 Java GPLv2 + classpath exception
 http://openjdk.java.net/ 
 JavaFX
 部分组件开源 GPLv2
 https://openjfx.dev.java.net/
今年秋季将公布开源计划
 Openoffice/staroffice source code: LGPL document: PDL
 http://www.openoffice.org 从openoffice 3.0 beta 起 LGPLv3
 MySQL Many license options including GPL
 http://www.mysql.com/ 
 Netbeans Dual license (CDDL and GPLv2 + classpath exception)
 http://www.netbeans.org/ 从Netbeans 6.1起
 Glassfish Most components are CDDL and GPLv2 + classpath exception, several are Apache License or Mozilla Public License
 https://glassfish.dev.java.net/ 
 OpenESB
 CDDL  https://open-esb.dev.java.net/

 OpenSSO CDDL https://opensso.dev.java.net/  也就是 Sun Access Manager的开源版本。
 OpenPortal CDDL https://portal.dev.java.net/ 也就是 Sun Portal Server的开源版本。
 OpenDS
 CDDL https://www.opends.org/
 全新的基于Java的目录服务器
 OpenMQ
 CDDL  https://mq.dev.java.net/
 也就是Sun Java Message Queue的开源版本。Open MQ 是Glassfish的一部分。
 Sun webserver 7.0 and proxy server
 BSD
 TBD

 OpenSparc
 GPLv2
 http://www.opensparc.net
 Sun CMT 架构处理器 UltraSparc T1, T2
 Lighttpd
  BSD Lighttpd的作者Jan Kneschke是MySQL现在是SUN的员工
 Sun Spot
 GPLv2
 http://www.sunspotworld.com/
 Sun Small Programmable Object Technology
 Grid engine
 SISSL  http://gridengine.sunsource.net/
 Virtual Box
 GPLv2
 http://www.virtualbox.org/
 桌面虚拟化的开源产品
 Lustre
 GPL

http://www.lustre.org
 高性能集群文件系统
 Open HA cluster
 CDDL http://opensolaris.org/os/community/ha-clusters/ohac/
 opensolaris的一部分

 

还有什么没有开源?Sun Identity Manager, Sun Directory Server Enterprise, SunRay Server, Sun Secure Global Desktop, Sun Studio 12(不开源但免费),Sun JCAPS, 不多了。

除非你是Microsoft的追随者,作为软件开发人员想不用上面任何一种产品恐怕很难。 

 

 

http://developers.sun.com.cn/blog/lxf/date/20080722 星期二 七月 22, 2008

LoadRunner测试Web的常见问题

性能测试是一件非常严谨的事情,就像我以前写过的一样,很多用户的性能测试的问题在于测试本身。以下列举几条LoadRunner测试Web的常见问题。

  • 网络带宽问题。

对Web进行压力测试时,通常百兆网络是不够的,当网络带宽不够的时候server端没有足够压力。用LoadRunner所在的Windows的性能管理器看一下网络利用率就知道了。

  • Vuser脚本的检查。

虽然Loadrunner提供了方便的脚本录制功能,但由于录制时可能出现的操作偏差,也应手工检查生成的Vuser脚本。 去除某些与压力测试无关的东西。否则可能会出现Loadrunner测试结果有误或压力上不去的情况(比如vuser访问一些不存在的资源)。

  • Runtime setting。

在创建Loadrunner scenario时,每台机器的vuser的runtime setting都应该分别设置并检查,不能只对第一个vuser的runtime setting进行设置。通常你会关掉think time,以便能用较少的机器达到较大的压力。另外,如果返回页面里包含了一些访问其它资源的链接比如图片服务器,这时应关掉 download non-html resources。

  • 没有检查返回页面。

当server端出错时应用程序有可能返回错误信息,但对HTTP来讲仍是成功的响应,返回码为200 O.K. 这样在Loadrunner就被记为成功的transaction。于是,server端出错越多,Loadrunner测出的性能越好。解决办法:开启并检查应用的错误日志;或者启用Loadrunner的返回内容检查功能。

  • 当心Loadrunner所在机器的磁盘空间。

缺省情况下Loadrunner会把运行结果的详细信息放在C盘的Documment and Settings的用户目录下,当大压力长时间运行或有大量出错时,Loadrunner会生成大量的数据到该目录下。当磁盘空间满了后,机器的响应将变得很慢。

  • 结语。

还是那句话,性能测试是一件非常严谨的事情。本身在实验室里的性能测试就很难模拟真实情况,另外世界上没有两个一模一样的系统,要做到apple-apple的比较很难。 所以做性能测试一定要仔细,测试条件一定要定义清楚。否则,最后的结果是:上了生产系统后被最终客户折磨地吃不下饭睡不着觉。这不是开玩笑,我在别人那里见过了太多的这种情况。