淘宝商城(天猫)高级技术专家.3年研发+3年性能测试调优/系统测试+4年团队管理与测试架构、研发系统实践. 新舞台新气象, 深化测试基础架构及研发架构,希望能在某个技术领域成为真正的技术大牛。欢迎荐才http://bbs.51testing.com/viewthread.php?tid=120496&extra=&page=1 .邮件: jianzhao.liangjz@alibaba-inc.com,MSN:liangjianzhao@163.com.微博:http://t.sina.com.cn/1674816524

发布新日志

  • HTTP GET请求传输汉字给SPRING MVC的处理

    2008-09-15 12:52:20

    HTTP GET请求在提交数据给服务器方面和POST有很多差异。比如传输字节数大小,编码要求等。

    HTTP GET请求要求对汉字进行URL 编码。

     

    IE客户端javascrīpt/vbscrīpt代码。

        

     

    <scrīpt language="vbscrīpt">

    Function GetByteCode(ch)   

        code = Asc(ch)          ' -20001

        GetByteCode = Hex(code) ' "B1DF"

    End Function

    </scrīpt>


    <scrīpt language="javascrīpt">

    String.prototype.urlEncode = function() {

        var r = "";

        for (var i = 0; i < this.length; i++) {

            var code = "" + GetByteCode(this.charAt(i));

            if (code.length > 2) {

                var b1 = code.substr(0, code.length - 2);

                var b2 = code.substr(code.length - 2);

                if (i == 0) {

                    //alert("" + code + ", " + b1 + ", " + code.length + ", " + b2);

                }

                r += "%" + b1 + "%" + b2;

            } else {

                r += "%" + code;
            }
        }
        return r;
    }

    </scrīpt>

     

     

     

    调用上述函数编码

    Var  projectname=”项目1”;

    var urlEncoded=projectname.urlEncode();

     var url="insertCheckList.do?projectname="+urlEncoded;

    接下来就是用AJAX  httprequest发送给JBOSS/TOMCAT。

     

     

     

    服务器端SPRING 接收到字符串解码:

     

    public ModelAndView handleRequestInternal(HttpServletRequest request,

               HttpServletResponse response) throws Exception {

     

    String encodeProj = request.getParameter("projectname");

          

               //客户端经过编码后的汉字

              

               String projectname= new String( encodeProj.getBytes( "8859_1" ) , "gb2312" );

               System.out.println(projectname);      

     

    }

  • 实现JBOSS reload class文件

    2008-09-11 17:33:47

    以下操作在D:\jboss-4.2.2.GA\bin测试通过。

     

    怎样做到让JBOSS服务器检测到.class变化而重新加载相应的应用?

    这样不必没更改一个文件即重启JBOSS,然后是漫长的等待。 这个就是效率J

     

    测试发现修改一个应用的web.xml文件可以让jboss检测到应用变更从而重新reload web应用。

    更改web.xml后提示

     

    21:45:01,718 INFO  [TomcatDeployer] undeploy, ctxPath=/spring, warUrl=.../deploy

    /spring.war/

    21:45:01,718 INFO  [[/spring]] Destroying Spring FrameworkServlet 'dispatcherSer

    vlet'

    21:45:01,734 INFO  [XmlWebApplicationContext] Closing org.springframework.web.co

    ntext.support.XmlWebApplicationContext@12f68b8: display name [WebApplicationCont

    ext for namespace 'dispatcherServlet-servlet']; startup date [Mon Sep 08 21:38:5

    9 CST 2008]; parent: org.springframework.web.context.support.XmlWebApplicationCo

    ntext@12cc66f

     

     

    更加彻底的办法是:修改D:\jboss-4.2.2.GA\server\default\deploy\jboss-web.deployer\context.xml

    内容如:

    <Context cookies="true" reloadable="true"  crossContext="true">

     

    重启后即可以达到修改.class文件而重新reload应用的效果。

     

    Jboss起动日志:

    2008-09-08 21:55:14,515 INFO  [org.apache.catalina.core.StandardContext] Reloading this Context has started

    2008-09-08 21:55:14,515 INFO  [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/spring]] Destroying Spring FrameworkServlet 'dispatcherServlet'

    2008-09-08 21:55:14,531 INFO  [org.springframework.web.context.support.XmlWebApplicationContext] Closing org.springframework.web.context.support.XmlWebApplicationContext@a50395: display name [WebApplicationContext for namespace 'dispatcherServlet-servlet']; startup date [Mon Sep 08 21:53:13 CST 2008]; parent:

  • spring+ibatis+velocity+ajax开发WEB应用小结

    2008-09-06 23:09:10

    这二周闭关开发内部配置管理员用的发布需求流程工具。

    主要的技术为:java spring+ ibatis+ velocity+ ajax/javascrīpt/css+mysql。

    IDE: eclipse。

    以下简要描述各个技术点应用状况。

    (1) java spring: spring很好整合了当下成熟的框架,最突出的概念有2点: IOC 和 AOP。
    spring支持ibatis,hibernate等 O/R MAP工具。支持 JSP/Velocity/struct等V层展现。
    另外,有jpetstore经典的例子、台湾林信良的spring2技术手册引导入门。

    可以运行在JBOSS/TOMCAT上,且其轻量。第一个念头就是用它实现。

    偶高频率应用SimpleFormController完成http请求以及响应。

    比较不爽的是,一堆的XML 配置文件。

    2) 数据方面有同步 confluence数据的需求、导入EXCEL数据需求,且数据量不大。故用单机版的MYSQL足够了。

    本次采用gb2312编码保存数据、页面信息。

    3)  O/R映射方面采用ibatis。 ibatis比hibernate轻量,又能自由操作SQL。

    ibatis 在被JBOSS/TOMCAT运行时加载 sql-map文件,如果SQL和数据库、配置文件有错误,将导致deploy失败。

    数据库如何设计得更合理,适应未来应用增加、环境增加是我考虑最多的点。

    4)  界面展现采用velocity。 这个是偶最不熟悉的。

    感觉最麻烦是它的调试。貌似语言能力偏弱,一些复杂类型的读写有困难。 复杂运算都在SPRING内计算。

    后来直接在spring ModelAndView方法,将简单对象或者List、数组保存为 session 在页面间传递。如
    request.getSession().setAttribute("currUsername", user.getUsername());

    5) ajax/javascrīpt/css应用在2个场景:

     第一个是表格的动态增加, 采用ajax定期更新部分页面信息达到提醒功能,一些常用控件(如日期选取),客户端输入验证等
     
     第二个就是界面美化。 基本功能完成后,看到页面太简陋了。偶从http://www.okajax.com/a/200806/062322552008.html 找了一些特效嵌入。

  • spring + velocity实现分页程序2

    2008-09-01 18:02:58

    接续

    package com.ali;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.context.ApplicationContext;
    import org.springframework.validation.BindException;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.SimpleFormController;

    import com.ali.db.User;
    import com.ali.util.PageUtil;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class UserListController extends SimpleFormController {
     private IIbatisDAO currDAO;
     private String  m_pagesize;
     public UserListController() {
      setCommandClass(UserListForm.class);
     }

     public ModelAndView handleRequestInternal(HttpServletRequest request,
       HttpServletResponse response) throws Exception {
      
      if ( request.getMethod().equals("GET"))
      {
       //处理 http get请求
       System.out.println("do Get!!");
       
       UserListForm form = new UserListForm();
       form.setPage("1");
       form.setPageSize(getPageSize());
       System.out.println("handleRequestInternal");
       return onSubmit(request, response, form, null);
      }
      else
      {
       //return onSubmit(request, response, null, null);
       System.out.println("do Post!!");
       return super.handleRequestInternal(request, response);
      }
      
     }

     protected ModelAndView onSubmit(HttpServletRequest request,
       HttpServletResponse response, Object command, BindException errors)
       throws Exception {
      //处理http post请求
      UserListForm form = (UserListForm) command;
      System.out.println("user list:" + form);

      List list = this.getDAO().findUsers();
      ArrayList arrList = new ArrayList();
      for (Iterator i = list.iterator(); i.hasNext();) {
       User user = (User) i.next();
       System.out.println(user);
       arrList.add(user);
      }

      PageUtil util = new PageUtil(arrList, form.getPageSize(), form
        .getPage());
      System.out.println("list.size=" + arrList.size());
      request.setAttribute("userlist", util.getArrayList());

      request.setAttribute("pager", util);

      return new ModelAndView(this.getSuccessView());
     }

     public void setDAO(IIbatisDAO dao) {
      currDAO = dao;
     }

     public IIbatisDAO getDAO() {
      return currDAO;
     }
     public String getPageSize()
     {
      return m_pagesize;
     }
     
     public void setPageSize(String pagesize)
     {
      m_pagesize = pagesize;
     }
    }

    具体的velocity内容

     <BODY >
     
        <form name="userlist" method="post" action="/spring/userlist.do">
             <input type="hidden" name="page" >
             <input type="hidden" name="pageSize"  value=2>    
        </form>
     
     <table width="772"  border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#FFFFFF">
       <tr>
         <td>     
           <table width="750"  border="0" align="center" cellpadding="5" cellspacing="1">
             <tr align="center">
               <td background="images/q_12.gif"><span class="ff">用户名</span></td>
               <td background="images/q_12.gif" class="ff">站点</td>
               <td background="images/q_12.gif"><span class="ff">邮箱</span></td>
             </tr>
     #foreach($user in $userlist)
     #set($color="E9F4FF")
     #if($velocityCount%2==0)
     #set($color="FFFFFF")
     #end
             <tr align="center" bgcolor="$color">
                       <td class="ii">$user.getUsername()</td>         
                             <td>$user.getSite()</td>
                 <td class="style28">$user.getEmail()</td>
             
                     </tr>
     #end       
           </table>
     #set($pageFirst=1)
     
     #if ($pager)
     #set($pageEnd=$pager.getPageCount())
     #set($pagePrevious=$pager.getPreviousPage())
     #set($pageNext = $pager.getNextPage())
     #else
     #set($pageEnd=1)
     #set($pagePrevious=1)
     #set($pageNext =1)
     #end
     <scrīpt>
     
     function goto(p) {
             userlist.page.value=p;
             userlist.pageSize.value=2;
              userlist.submit();
     }
     </scrīpt>
     <table width="100%" border="0">
       <tr>
       <td width="98%" height="43" align="right">
        #if ($pager)
        总 $pager.rowCount 条
        第 $pager.currentPage/$pager.pageCount 页
        #else
        总 0 条
        第 0 页
        #end
        <a href="#$pageFirst" ōnclick="goto($pageFirst)">首页</a>
        <a href="#$pagePrevious" ōnclick="goto($pagePrevious)">上一页</a>
        <a href="#$pageNext" ōnclick="goto($pageNext)">下一页</a>
        <a href="#$pageEnd" ōnclick="goto($pageEnd)">末页</a>
       </td>
       </tr>
     </table>
         </td>
       </tr>
     </table>
     
     </BODY>
     

  • spring + velocity实现分页程序

    2008-09-01 17:52:25

    这段时间用 Spring + ibatis开发一个内部用的管理工具。麻雀随小,但五脏俱全。由于没有用公司的webx框架,重复发明轮子了,也碰到了一些问题。

     

    比如spring+ibatis 分页程序:) .

     

    偶参考网络上的一个实现。实现没有依赖数据库特性。如mysql limit。经过测试成功。

     

    具体的实现PageUtil

     package com.ali.util;

    import java.util.ArrayList;
    import com.ali.db.User;

    public class PageUtil {
     private int currentPage = 0;// 当前页

     private int rowCount = 0;// 总行数

     private int pageSize = 0;// 页大小

     private int pageCount = 0;// 总页数

     private int beginPosition = 0;// 页起始

     private int endPosition = 0;// 页终止

     private boolean hasNextPage = false;// 是否有下一页

     private boolean hasPreviousPage = false;// 是否上一页

     private ArrayList arrayList = new ArrayList();// 记录集

     /**
      * 初始化变量
      *
      * @param rowCount
      * @param pageSize
      * @param currentPage
      */
     public PageUtil(ArrayList arrayList, String pageSize, String currentPage) {
      this.arrayList = arrayList;
      this.rowCount = arrayList.size();

      this.pageSize = Integer.parseInt(pageSize);

      this.getPageCount();
      if (currentPage == null || currentPage.equals("")) {
       this.currentPage = 1;
      } else {
       try {
        this.currentPage = Integer.parseInt(currentPage);
       } catch (NumberFormatException nfe) {
        this.currentPage = 1;
       }
      }
      this.getCurrentPage();
      this.getBeginPosition();
      this.getEndPosition();
     }

     /**
      * 获取总行数
      *
      * @return rowCount
      */
     public int getRowCount() {
      return rowCount;
     }

     public int getPageSize() {
      return pageSize;
     }

     public int getCurrentPage() {
      if (currentPage >= pageCount) {
       currentPage = pageCount;
      } else if (currentPage <= 1) {
       currentPage = 1;
      }
      return currentPage;
     }

     public int getPageCount() {
      // 计算出总页数
      pageCount = (rowCount + pageSize - 1) / pageSize;
      return pageCount;
     }

     public int getBeginPosition() {
      // 计算出页起始
      beginPosition = (currentPage - 1) * pageSize + 1;
      return beginPosition;
     }

     public int getEndPosition() {
      // 计算出页终止
      if (currentPage >= pageCount) {
       endPosition = rowCount;
      } else {
       endPosition = currentPage * pageSize;
      }
      return endPosition;
     }

     public boolean isHasNextPage() {
      // 计算出是否有下一页
      if (currentPage >= pageCount) {
       hasNextPage = false;
      } else {
       hasNextPage = true;
      }
      return hasNextPage;
     }

     public boolean isHasPreviousPage() {
      // 计算出是否有上一页
      if (currentPage <= 1) {
       hasPreviousPage = false;
      } else {
       hasPreviousPage = true;
      }
      return hasPreviousPage;
     }

     public int getFirstPage() {
      return 1;
     }

     public int getPreviousPage() {
      if (this.isHasPreviousPage()) {
       return currentPage - 1;
      }
      return currentPage;
     }

     public int getNextPage() {
      if (this.isHasNextPage()) {
       return currentPage + 1;
      } else {
       return currentPage;
      }
     }

     public int getLastPage() {
      return pageCount;
     }

     /**
      * 获取页数据
      *
      * @return ArrayList
      */
     public ArrayList getArrayList() {

      ArrayList list = new ArrayList();
      for (int i = beginPosition; i <= endPosition; i++) {
       list.add(arrayList.get(i - 1));
      }
      return list;

     }
    }

  • 分布式计算hadoop部署

    2008-08-22 20:24:35

     

    很多人听说google 的云计算,基础mapreduce、gfs,但都停留于纸面。apache和yahoo 合作有一个类似项目hadoop,国内已经有实际公司在应用,如阿里妈妈,国外有hive项目。

    说这么多,不如实际部署一个体验下。

     

    hadoop要求sun jdk1.5或者以上,linux 平台。


    更多参考 http://www.infoq.com/cn/articles/hadoop-config-tip
    http://www.michael-noll.com/wiki/Running_Hadoop_On_Ubuntu_Linux_(Single-Node_Cluster)#Prerequisites

     

    分布式部署

    参考Hadoop Cluster Setup

     

    2台机器10.0.4.145 (NameNodeJobTracker角色),10.0.4.146(DataNodeTaskTracker的角色)

    都建立同样的目录/home/search/hadoop-0.17.1

     

    在主节点145  [search@b2bsearch145 ~]$ cat .bash_profile

    export HADOOP_HOME=/home/search/hadoop-0.17.1

    export PATH=$PATH:$HADOOP_HOME/bin

     

    方便命令行操作

    1.1    创建证书建立信任登录过程

    建立Master到每一台SlaveSSH受信证书。

     

    确保~/.ssh/authorized_keys 的文件权限为 600

    [search@b2bsearch145 hadoop-0.17.1]$ ll  ~/.ssh/authorized_keys

    -rw-r--r--  1 search search 2529  6 25 10:01 /home/search/.ssh/authorized_keys

    [search@b2bsearch145 hadoop-0.17.1]$ cat ~/.ssh/authorized_keys |grep 146

    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA7naNGEpcbuon2/4M+0FDRp594MNk7jV0U3SaDLlT4vLvo0viCSP/2mEMi7iadaogkSr3FbIHryUsOhZ1MSwiDc2nv3TgxAh3K/jQkbP1MDGdHzOVvScrWcTfpFhDtL29HQJit5fpST0aZDlbCn8LsYX+y171Pun9Q4HyT9TkUL0= search@alitest146

    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA06pe9YZTEEqmiutmjWQ1CgnmOWd3xh2YkqDinSuZi7t/Uyg/u/l0vJ5nv196dnYqdJJTyaVUU+ydcS7UJu+ykpeIYZGSL6XC2MqTMCpEVAtqP9WUhFXToJmq0tDrlYTfnYZOCIrDt+hjp+c7E7EH3phtEHdrlaAs9ZvcM/6/4L0= search@intl_search38146

     

    1.2    配置文件

    解压后进入conf目录,主要需要修改以下文件:hadoop-env.shhadoop-site.xmlmastersslaves

     

    默认的hadoop-default.xml 仅仅更改dfs.permissions.supergroup属性值为当前用户组名称。 bash -c groups获取group名称

    <property>

      <name>dfs.permissions.supergroup</name>

      <value>search</value>

      <descrīption>The name of the group of super-users.</descrīption>

    </property>

     

     

    hadoop-env.sh 仅仅更改 JAVA_HOME

     

    # export JAVA_HOME=/usr/lib/j2sdk1.5-sun

    export JAVA_HOME=/usr/ali/jdk1.6

     

     

    一个可用的hadoop-site.xml

     

     

    [search@b2bsearch145 conf]$ vi  hadoop-site.xml

     

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

    <!-- Put site-specific property overrides in this file. -->

    <configuration>

    <property>

    <name>fs.default.name</name>

    <value>hdfs://10.0.4.145:54310/</value></property>

    <property>

    <name>mapred.job.tracker</name>

    <value>hdfs://10.0.4.145:54311/</value>

    </property>

    <property>   <name>dfs.replication</name>

    <value>1</value></property><property>

    <name>hadoop.tmp.dir</name>

    <value>/home/search/hadoop-0.17.1/tmp/</value></property>

    <property>

    <name>mapred.child.java.opts</name>

    <value>-Xmx512m</value></property>

    <property>  <name>dfs.block.size</name>

    <value>5120000</value>  <descrīption>The default block size for new files.</descrīption>

    </property></configuration>

     

    ~                                           

    [search@b2bsearch145 conf]$ cat masters

    10.0.4.145

    [search@b2bsearch145 conf]$ cat slaves

    10.0.4.146

     

     

    1.3    初始化dfs以及启动进程

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop  namenode  -format

    08/08/21 19:48:54 INFO dfs.NameNode: STARTUP_MSG:

    /************************************************************

    STARTUP_MSG: Starting NameNode

    STARTUP_MSG:   host = b2bsearch145/10.0.4.145

    STARTUP_MSG:   args = [-format]

    STARTUP_MSG:   version = 0.17.1

    STARTUP_MSG:   build = http://svn.apache.org/repos/asf/hadoop/core/branches/branch-0.17 -r 669344; compiled by 'hadoopqa' on Thu Jun 19 01:18:25 UTC 2008

    ************************************************************/

    08/08/21 19:48:54 INFO fs.FSNamesystem: fsOwner=search,search

    08/08/21 19:48:54 INFO fs.FSNamesystem: supergroup=search

    08/08/21 19:48:54 INFO fs.FSNamesystem: isPermissionEnabled=true

    08/08/21 19:48:54 INFO dfs.Storage: Storage directory /home/search/hadoop-0.17.1/tmp/dfs/name has been successfully formatted.

    08/08/21 19:48:54 INFO dfs.NameNode: SHUTDOWN_MSG:

    /************************************************************

    SHUTDOWN_MSG: Shutting down NameNode at b2bsearch145/10.0.4.145

    ************************************************************/

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/start-dfs.sh

    starting namenode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-namenode-b2bsearch145.out

    10.0.4.146: starting datanode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-datanode-alitest146.out

    10.0.4.145: starting secondarynamenode, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-secondarynamenode-b2bsearch145.out

    [search@b2bsearch145 hadoop-0.17.1]$ bin/start-mapred.sh

    starting jobtracker, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-jobtracker-b2bsearch145.out

     

    10.0.4.146: starting tasktracker, logging to /home/search/hadoop-0.17.1/bin/../logs/hadoop-search-tasktracker-alitest146.out

     

    [search@b2bsearch145 hadoop-0.17.1]$ /usr/ali/jdk1.6/bin/jps

    18390 NameNode

    18589 JobTracker

    18721 Jps

    18521 SecondaryNameNode

     

     

    1.4    执行分布式统计词

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs -copyFromLocal  input/  test-in

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls

    Found 1 items

    /user/search/test-in    <dir>           2008-08-21 19:53        rwxr-xr-x       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls /user/search/test-in

    Found 2 items

    /user/search/test-in/hadoop-default.xml <r 1>   37978   2008-08-21 19:53        rw-r--r--       search  search

    /user/search/test-in/hadoop-site.xml    <r 1>   178     2008-08-21 19:53        rw-r--r--       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -cat  /user/search/test-in/hadoop-default.xml

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

     

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop jar hadoop-0.17.1-examples.jar wordcount  /user/search/test-in  test-out

    08/08/21 19:55:45 INFO mapred.FileInputFormat: Total input paths to process : 2

    08/08/21 19:55:46 INFO mapred.JobClient: Running job: job_200808211951_0001

    08/08/21 19:55:47 INFO mapred.JobClient:  map 0% reduce 0%

    08/08/21 19:55:52 INFO mapred.JobClient:  map 66% reduce 0%

    08/08/21 19:55:54 INFO mapred.JobClient:  map 100% reduce 0%

    08/08/21 19:56:01 INFO mapred.JobClient:  map 100% reduce 100%

    08/08/21 19:56:02 INFO mapred.JobClient: Job complete: job_200808211951_0001

    08/08/21 19:56:02 INFO mapred.JobClient: Counters: 16

    08/08/21 19:56:02 INFO mapred.JobClient:   File Systems

    08/08/21 19:56:02 INFO mapred.JobClient:     Local bytes read=36202

    08/08/21 19:56:02 INFO mapred.JobClient:     Local bytes written=72658

    08/08/21 19:56:02 INFO mapred.JobClient:     HDFS bytes read=39559

    08/08/21 19:56:02 INFO mapred.JobClient:     HDFS bytes written=19133

    08/08/21 19:56:02 INFO mapred.JobClient:   Job Counters

    08/08/21 19:56:02 INFO mapred.JobClient:     Launched map tasks=3

    08/08/21 19:56:02 INFO mapred.JobClient:     Launched reduce tasks=1

    08/08/21 19:56:02 INFO mapred.JobClient:     Data-local map tasks=3

    08/08/21 19:56:02 INFO mapred.JobClient:   Map-Reduce Framework

    08/08/21 19:56:02 INFO mapred.JobClient:     Map input records=1239

    08/08/21 19:56:02 INFO mapred.JobClient:     Map output records=3888

    08/08/21 19:56:02 INFO mapred.JobClient:     Map input bytes=38156

    08/08/21 19:56:02 INFO mapred.JobClient:     Map output bytes=51308

    08/08/21 19:56:02 INFO mapred.JobClient:     Combine input records=3888

    08/08/21 19:56:02 INFO mapred.JobClient:     Combine output records=1428

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce input groups=1211

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce input records=1428

    08/08/21 19:56:02 INFO mapred.JobClient:     Reduce output records=1211

     

    1.5    观察结果

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -ls   /user/search/test-out 

    Found 2 items

    /user/search/test-out/_logs     <dir>           2008-08-21 19:55        rwxr-xr-x       search  search

    /user/search/test-out/part-00000        <r 1>   19133   2008-08-21 19:55        rw-r--r--       search  search

    [search@b2bsearch145 hadoop-0.17.1]$ bin/hadoop dfs  -cat  /user/search/test-out/part-00000 |more

    "_logs/history/"        1

    "all".</descrīption>    1

    "block"(trace   1

    "dir"(trac      1

    "false",        1

    "local",        1

     

    更多命令参考:Hadoop Shell Commands

     

     

    1.6    Web UI 浏览NameNode

     

     

    1.7    Web UI 浏览DataNode

     

     

     

    1.8    WEB UI浏览JobTracker

     

     

     

    1.9    Web UI 浏览TaskTracker

     

    1.10       停止应用

     

    后续比较有意思的一些使用体验也将陆续上传。

  • Jmeter图形化框架

    2008-08-10 14:54:48

    最近在看Jmeter源代码,顺便温习JAVA SwingAPI

     

    为了看得更清楚Jmeter图形化处理,偶尽量剥离Jmeter相关的API ,使用SUN JAVA API

     

    更多请参考经典的JAVA书籍:《Java 2核心技术》。偶的JAVA知识从这2本书开始J

     

    最核心的技术点:

    Ø         JframeJPanel 等容器

    Ø         ActionListener 事件处理

    Ø         ImageIcon 图片展现

    Ø         反射,如commandClass.newInstance

     

     

    package org.apache.jmeter;

    import java.awt.BorderLayout;

    import java.awt.Color;

    import java.awt.Component;

    import java.awt.Container;

    import java.awt.Dimension;

    import java.awt.GridLayout;

    import java.awt.HeadlessException;

    import java.awt.Point;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.KeyEvent;

    import java.awt.event.MouseAdapter;

    import java.awt.event.MouseEvent;

    import java.lang.reflect.Modifier;

    import java.util.HashMap;

    import java.util.HashSet;

    import java.util.Iterator;

    import java.util.List;

    import java.util.Map;

    import java.util.Set;

     

    import javax.swing.BorderFactory;

    import javax.swing.Box;

    import javax.swing.BoxLayout;

    import javax.swing.ImageIcon;

    import javax.swing.JButton;

    import javax.swing.JComponent;

    import javax.swing.JDialog;

    import javax.swing.JFrame;

    import javax.swing.JLabel;

    import javax.swing.JMenu;

    import javax.swing.JMenuBar;

    import javax.swing.JMenuItem;

    import javax.swing.JOptionPane;

    import javax.swing.JPanel;

    import javax.swing.JScrollPane;

    import javax.swing.JSplitPane;

    import javax.swing.JMenu;

    import javax.swing.JMenuBar;

    import javax.swing.KeyStroke;

    import javax.swing.SwingUtilities;

    import javax.swing.border.EmptyBorder;

     

    import org.apache.jmeter.gui.action.Command;

     

    //为了事件处理,实现ActionListener

    public class JFrameTest extends JFrame  implements ActionListener {

        private Map commands = new HashMap();

        private Map preActionListeners = new HashMap();

        private Map postActionListeners = new HashMap();

        JDialog about = null;

       

        //actionPerformed事件处理入口

        public void actionPerformed(final ActionEvent e) {

           SwingUtilities.invokeLater(new Runnable() {

               public void run() {

                  performAction(e);

               }

     

           });

        }  

        //加入命令映射器

        //核心代码就是反射技术

        private void populateCommandMap() {

           List listClasses;

           Command command;

           Iterator iterClasses;

           Class commandClass;

           try

           {

           commands = new HashMap(1);

           commandClass = Class.forName("org.apache.jmeter.gui.action.AboutCommand");

            if (!Modifier.isAbstract(commandClass.getModifiers())) {

                command = (Command) commandClass.newInstance();

                Iterator iter = command.getActionNames().iterator();

                while (iter.hasNext()) {

                    String commandName = (String) iter.next();

                    Set commandObjects = (Set) commands.get(commandName);

                    if (commandObjects == null) {

                        commandObjects = new HashSet();

                        commands.put(commandName, commandObjects);

                    }

                    commandObjects.add(command);

                }

            }

           }catch(Exception e)

           {

               e.printStackTrace();

           }

          

        }

        /**

         * Allows an ActionListener to receive notification of a command being

         * executed prior to the actual execution of the command.

         *

       

  • MSXML6 SDK解析中文XML文件

    2008-08-10 01:36:58

    1.1       下载msxml6_SDK.msi安装

     

    http://www.microsoft.com/downloads/details.aspx?familyid=993C0BCF-3BCF-4009-BE21-27E85E1857B1&displaylang=en

     

    默认安装在C:\Program Files\MSXML 6.0\

     

    1.2       vc6上建立编译环境

    Preprocessor 编译加入 Additional include directorie加入C:\Program Files\MSXML 6.0\inc

     

    LINK module加入: msxml6.lib

     

    Link Additional  library path加入:C:\Program Files\MSXML 6.0\lib

    1.3       解决vc6 link错误问题

     

    msxml6.lib(msxml6_i.obj) : fatal error LNK1103: debugging information corrupt; recompile module

     

    参见

    http://www.armleg.com/forum/viewtopic.php?p=388&sid=414fd259dcf02a90f150708296924178&mforum=diodiaforum

     

    All I get from Google is that VS6 doesn't work with platform SDK's later than february 2003.

     

    必须采用release版本编译、链接才成功。(build->set active project configuration->win32 release)

     

     

    1.4       汉语问题

     

           //解决汉语问题

           setlocale(LC_ALL,"chinese-simplified");

     

    1.5       源代码

     

    #include <objbase.h>

    #include <msxml6.h>

    #include <stdio.h>

    #include <windows.h>

    #include <stdarg.h>

    #include <locale.h>

    #include <AtlBase.h>

     

    #import <msxml6.dll> raw_interfaces_only

     

    // Macro that calls a COM method returning HRESULT value:

    #define HRCALL(a, errmsg) \

    do { \

        hr = (a); \

        if (FAILED(hr)) { \

            dprintf( "%s:%d  HRCALL Failed: %s\n  0x%.8x = %s\n", \

                    __FILE__, __LINE__, errmsg, hr, #a ); \

            goto clean; \

        } \

    } while (0)

     

    // Helper function that put output in stdout and debug window

    // in Visual Studio:

    void dprintf( char * format, ...)

    {

        static char buf[1024];

        va_list args;

        va_start( args, format );

           sprintf(buf, format, args);

        vsprintf(buf, format, args );

        va_end( args);

        OutputDebugStringA( buf);

        printf("%s", buf);

    }

     

    // Helper function to create a DOM instance:

    IXMLDOMDocument3 * DomFromCOM()

    {

       HRESULT hr;

       IXMLDOMDocument3 *pxmldoc = NULL;

     

       HRCALL( CoCreateInstance(CLSID_DOMDocument60,

                      NULL,

                      CLSCTX_INPROC_SERVER,

                      //__uuidof(IXMLDOMDocument),

                                  IID_IXMLDOMDocument3,

                      (void**)&pxmldoc),

                      "Create a new DOMDocument");

     

        HRCALL( pxmldoc->put_async(VARIANT_FALSE),

                "should never fail");

        HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE),

                "should never fail");

        HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE),

                "should never fail");

     

        return pxmldoc;

    clean:

        if (pxmldoc)

        {

            pxmldoc->Release();

        }

        return NULL;

    }

     

    int Get_nodeValue(IXMLDOMElement * pRoot , char * tagName,char *ret_text)

    {

           USES_CONVERSION;

        IXMLDOMNodeList  * pNodeList = NULL;

           IXMLDOMNode  * pNode = NULL;

           HRESULT hr;

           BSTR bstr = NULL;

     

           hr=pRoot->getElementsByTagName(_bstr_t(tagName),&pNodeList) ;

           if (FAILED(hr))

                  return -1;

     

           //取第一个满足条件的

           hr= pNodeList->get_item(0,&pNode);

           if (FAILED(hr))

                  return -1;

          

           hr=pNode->get_text(&bstr);

           if (FAILED(hr))

                  return -1;

           //dprintf("v=%s\n",W2A(bstr));

           sprintf(ret_text,W2A(bstr));

           return 0;

    }

     

    int main(int argc, char* argv[])

    {

      /*

      HRESULT hr;

      IXMLDOMDocument3 *pXMLDoc = NULL;

      CoInitialize(NULL);

      hr = CoCreateInstance(CLSID_DOMDocument60,

                         NULL,

                         CLSCTX_INPROC_SERVER,

                         IID_IXMLDOMDocument3,

                         (void**)&pXMLDoc);

       if (FAILED(hr))

       {

          printf("Error code: %x\n", hr);

       }

    */

           USES_CONVERSION;

        IXMLDOMDocument3 *pXMLDom=NULL;

        IXMLDOMParseError *pXMLErr=NULL;

        BSTR bstr = NULL;

        VARIANT_BOOL status;

        VARIANT var;

        HRESULT hr;

           IXMLDOMElement * pRoot = NULL;

           VARIANT_BOOL isHasChild=VARIANT_FALSE;

           long listLen=0;

           long i=0;

           char ret_scrīpttext[48]={0};

           char ret_steptime[48]={0};

           char sz_xmlFile[]="lr.xml";

          

        CoInitialize(NULL);

           //解决汉语编码问题

           setlocale(LC_ALL,"chinese-simplified");

     

        pXMLDom = DomFromCOM();

        if (!pXMLDom) 

                  goto clean;

          

        VariantInit(&var);

        V_BSTR(&var) = SysAllocString(_bstr_t(sz_xmlFile));

        V_VT(&var) = VT_BSTR;

        HRCALL(pXMLDom->load(var, &status), "");

     

        if (status!=VARIANT_TRUE) {

            HRCALL(pXMLDom->get_parseError(&pXMLErr),"");

            HRCALL(pXMLErr->get_reason(&bstr),"");

            dprintf("Failed to load DOM from stocks.xml. %S\n",

                        bstr);

            goto clean;

          

     

        }

        HRCALL(pXMLDom->get_xml(&bstr), "");

     

        dprintf("XML DOM loaded from stocks.xml:\n%S\n",bstr);

     

           HRCALL( pXMLDom->get_documentElement(&pRoot) ,"get_documentElement");

      

           Get_nodeValue(pRoot,"scrīpt",ret_scrīpttext);

           Get_nodeValue(pRoot,"steptime",ret_steptime);

          

           printf("%s %d",ret_scrīpttext,atoi(ret_steptime));

     /*

        HRCALL(pNode->get_nodeValue(&value),"get_nodeValue");

           USES_CONVERSION;  

        dprintf("v=%s\n",OLE2A(value.bstrVal));

           SysFreeString(bstr);

    */

     

    clean:

        if (bstr) SysFreeString(bstr);

        if (&var) VariantClear(&var);

        if (pXMLErr) pXMLErr->Release();

        if (pXMLDom) pXMLDom->Release();

     

        CoUninitialize();

        return 0;

    }

     

    Lr.Xml文件如下(notepad保存为ascii格式)

    <?xml version="1.0" encoding="GB2312"?>

     

    <root>

        <scrīpt type="string">d:\工程\1.lrr</scrīpt>

        <steptime>30</steptime>

    </root>

  • win32 下解决数字四舍五入问题

    2008-08-04 20:43:38

     

    今天在windows下用vc6 编写一程序,需要做四舍五入。
    想到c99标准有round函数。可以很遗憾编译成功,LINK出错:
    Linking...
    run.obj : error LNK2001: unresolved external symbol _round
    run.exe : fatal error LNK1120: 1 unresolved externals
    Error executing link.exe.

    google的结果发现: round was added to C in the C99 standard. Microsoft still hasn't finished putting support for C99 in the compiler and round isn't in there yet.

    下面函数运行成功。


    #include  <stdio.h>
    #include <math.h>
    double Round(double num,int bit);
    int main()
    {
     printf("%f\n",Round(-100.5,0));
     printf("%f\n",Round(100.5,0));
     return 0;
    }

    //bit位数

    double Round(double num,int bit)
    {
     return floor( num * pow( 10 , bit ) + .5 ) / pow( 10 , bit );
    }
     

     

  • [论坛] 自动化友好、干净停止loadrunner运行场景的源代码

    2008-08-01 23:18:36

    最近针对loadrunner做功能扩展,其中一个环节是:尽力正常点击stop停止,如经过处理无法停止,则干净终止loadrunner进程。

      loadrunner手册有命令行方式启动wlrun.exe进程的方式,但没有停止wlrun.exe的方式。本方法用win32实现友好停止Loadrunner场景。

      窗口层次关系可以用spy++察看 .

      测试程序的方法,启动一个loadrunner运行场景。

    #include &lt;stdlib.h&gt;
    #include &lt;stdio.h&gt;
    #include  &lt;time.h&gt;
    #include  &lt;errno.h&gt;
    #include &lt;locale.h&gt;
    #include &lt;windows.h&gt;
    #include &lt;vdmdbg.h&gt;


    typedef struct
       {
          DWORD   dwID ;
          DWORD   dwThread ;
       } TERMINFO ;

      BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;


    DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
       {
          HANDLE   hProc ;
          DWORD   dwRet ;

          // If we can't open the process with PROCESS_TERMINATE rights,
          // then we give up immediately.
          hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,
             dwPID);

          if(hProc == NULL)
          {
             return FALSE ;
          }

          // TerminateAppEnum() posts WM_CLOSE to all windows whose PID
          // matches your process's.
          EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;

          // Wait on the handle. If it signals, great. If it times out,
          // then you kill it.
          if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)
             dwRet=(TerminateProcess(hProc,0)?TRUE:FALSE);
          else
             dwRet = TRUE ;

          CloseHandle(hProc) ;

          return dwRet ;
       }


    BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
    {
      DWORD dwID ;

      GetWindowThreadProcessId(hwnd, &dwID) ;

      if(dwID == (DWORD)lParam)
      {
         PostMessage(hwnd, WM_CLOSE, 0, 0) ;
      }

      return TRUE ;
    }

    //MyEnumWindow 函数本身只能枚举最top-level的窗口。
    //嵌套的窗口自己枚举

    //这里用spy++观察层次结构
    //模拟用户鼠标操作停止loadrunner的过程
    BOOL   CALLBACK    MyEnumWindow(HWND   hWnd,   LPARAM   lParam)
    {
       char    sz_text[MAX_PATH]={0};  
       int  len =0;
       char  * p_title = NULL;
       int  ret;
       HWND child_hWnd=NULL,dialog_hWnd=NULL,next_hWnd=NULL;
       int  i=0;
       BOOL isFound = FALSE;
       int try_time=10;
       WINDOWINFO  winInfo;
       DWORD dwID ;
       p_title=(char*)lParam;

       len= GetWindowText(hWnd,   sz_text,   sizeof(sz_text)/sizeof(sz_text[0]));   
       if (strstr(sz_text,"LoadRunner"))
            printf("%s\r\n",sz_text);  
       child_hWnd = hWnd;
       if(strstr(sz_text,p_title))   
       {   
          
       while(1)
       {
        //获取子窗口
        child_hWnd=GetWindow(child_hWnd, GW_CHILD);
        //恶意关闭loadrunner时,窗口是否为存在?防止死循环。
        if(child_hWnd!=NULL)
        {
         len= GetWindowText(child_hWnd, sz_text, sizeof(sz_text)/sizeof(sz_text[0]));      
         if (!strcmp(sz_text,"&Start Scenario"))
         {
         //获取兄弟窗口
         next_hWnd=GetWindow(child_hWnd, GW_HWNDNEXT);
         len= GetWindowText(next_hWnd,sz_text,   sizeof(sz_text)/sizeof(sz_text[0]));
         if (!strcmp(sz_text,"S&top") )
         {
          //找到停止的窗口
          isFound =TRUE;
          break;
         }   
         }
        }
        else   //child_hWnd!=NULL
        {
        break;
        }
       } //while

       
       if (FALSE ==isFound )
       {
        //失败退出
        printf("not found S&top!\r\n");
        return TRUE;
       }

       //尝试投递try_time次。
       //for(i=0;i &lt; try_time; i++)
       while(1)
       {

        //SendMessage(next_hWnd,  BM_CLICK,0,  0);
        PostMessage(next_hWnd,  BM_CLICK,0,  0); // 这里不能用SendMessage,否则阻塞进程
        dialog_hWnd  = FindWindow("#32770", "LoadRunner Controller");
       
        if (!dialog_hWnd)   
        {
         printf("Find dialog error.  ret=%d\r\n",GetLastError());
        }
        else  
        {      
         //if  (IsWindowVisible(dialog_hWnd))
         //{
          len= GetWindowText(dialog_hWnd,  sz_text, sizeof(sz_text)/sizeof(sz_text[0]));
          printf("GetWindowText  return %s\r\n",sz_text);           
          //查找对话框上按纽
          child_hWnd  =  FindWindowEx(dialog_hWnd,0,"Button","确定");
          if (!child_hWnd)
          {
           printf("确定 button  ret=%d\r\n",GetLastError());
           continue;
          }

          SendMessage(child_hWnd, BM_CLICK,0,  0);
          ret = GetLastError();
          if (ret)
          {
           printf("button  error. ret=%d\r\n",ret);
          }
          else
          {
            printf("正常停止loadrunner!\r\n");
          }
           //经过如上处理后
          printf("destroywindows\r\n");
           Sleep(10);
           //强行关闭loadrunner相关进程
             GetWindowThreadProcessId(hWnd, &dwID) ;
          TerminateApp(dwID,10);
          return   FALSE;   
         //}
        } //(!prev_hWnd)
       }//for
       }  

       return   TRUE;   
    }
    int stop_loadrunner()
    {

      char    sz_title[]="Mercury LoadRunner Controller ";
      //  char    sz_title[]="S&top";
      if (EnumWindows(MyEnumWindow,(long) sz_title) )
        printf("failed,errno=%d",GetLastError());

    }


    void main()

    {

    stop_loadrunner();

    }
  • [论坛] Open API测试畅想

    2008-07-28 12:48:20

    淘宝网新近开放了TOP平台,阿里软件的同事们根据平台测试的实践编写了《互联网单元测试及实践》,阿里巴巴技术部也在实现Open API给第三方开发商的项目,国内互联网公司Open API开放状况参考http://fairyfish.net/2008/07/16/chinese- open-api/。本月程序员杂志Open API大篇幅占据版面。chinaunix专门开辟openapi专栏 http://bbs.chinaunix.net/forum-137-1.html
       这些信息都表明,OPEN API是增强网站个性化、定制化的方式之一,将成为主流网站的一个趋势。

    一种新的研发模式也必然对测试带来一定的影响。对于开放API的平台商而言,Open API本身的测试也会有自己个性化的特征。

    (1) 安全测试要求更高。由于涉及关键数据众多,在用户输入验证、输出展现、安全交互、权限系统设计方面的要求更高。防止SQL注入、命令注入、XSS、缓冲区溢出、整数溢出等主要安全问题围绕整个软件生命周期。

    (2) 流量、资源消耗、计费等监控粒度更加细致。

       从第三方开发商过来的请求流量设计方面必须足够聪明,做到有效控制DOS攻击。
       
       需要评估审核第三方开发商研发能力,加强对其管理。
       
       API调用需要大量计算资源,有效监控资源变化包括系统级别的资源(如CPU\IO\网路\内存\进程间通信\打开文件描述符、数据库的CRUD等)以及业务级别资源(页面响应时间、资源下载时间等),全方位的监控体系保证网站安全。

    (3) 性能测试的需求更加迫切。
        大规模的应用访问会让系统感受到PV的强烈冲刺。
        一般应用程序关注用户访问模式,Open API更为关注API自身的调用频率。各种性能profile工具将发挥极致威力
              
    (4)非常适合应用单元测试、应用代码覆盖以及做到daily build/test。

       由于提供给第三方开发商使用,其接口必然比较稳定,以及复用程度较高。从成本效益角度衡量,适合单元测试。同时借助代码覆盖率度量工具,增加测试用例。
       由于存在良好的单元测试代码,daily build/test体系建立将让BUG主动跳出来。
         
    (5)demo应用程序以及API函数说明书。
       
       demo程序以及API函数说明书同样需要测试。第三方开发商借助这些demo应用程序以及API函数说明书才能有效发挥开放API的威力,由于分处两地,为了减少沟通成本,demo程序以及说明书应该相当详备。

    (6) 部署模式测试。

       API部署范围不应局限于在PC/PC Serer上, Open API也应该部署在流行的google application engine平台以及Amazon AWS上进行测试,以满足不同层次的开发商需求。

    (7)支持的开发语言调用测试

       针对Open API声称支持的各种开发语言对应的API都做测试。每种语言的数据类型都有差异,这个微小差异有时会导致致命的问题。
      
    (8)架构设计文档本身的测试,核心代码尽早执行性能测试
       
        应该有资深的架构师尽早介入,评审关键应用的设计文档,在早期介入减少设计失误。

        核心代码尽早执行性能测试,避免后期大规模修改。
       
      欢迎各位朋友拍砖。

    [ 本帖最后由 liangjz 于 2008-7-28 12:47 编辑 ]
  • [论坛] Valgrind 检测linux上c++内存泄露

    2008-07-15 21:23:13

    Linux c++上常用内存泄露检测工具有valgrind, Rational purify。Valgrind免费。Valgrind 可以在 32 位或 64 位 PowerPC/Linux 内核上工作。
    Valgrind工具包包含多个工具,如Memcheck,Cachegrind,Helgrind, Callgrind,Massif。下面分别介绍个工具的作用:
    Memcheck 工具主要检查下面的程序错误:
    •        使用未初始化的内存 (Use of uninitialised memory)
    •        使用已经释放了的内存 (Reading/writing memory after it has been free’d)
    •        使用超过 malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
    •        对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
    •        申请的空间是否有释放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
    •        malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
    •        src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
    Valgrind不检查静态分配数组的使用情况。
    Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试
    2.1.        下载安装
    http://www.valgrind.org
    安装
    ./configure;make;make install
    2.2.        编译程序
    被检测程序加入 –g  -fno-inline 编译选项保留调试信息。

    2.3.        内存泄露检测
    $   valgrind --leak-check=full --show-reachable=yes --trace-children=yes       ./iquery  -f ../conf/se.conf_forum    -t  ~/eragon/forum_thread_data/f.log   -NT  -cache 0
    其中--leak-check=full 指的是完全检查内存泄漏,--show-reachable=yes是显示内存泄漏的地点,--trace-children=yes是跟入子进程。当程序正常退出的时候valgrind自然会输出内存泄漏的信息。

    ==4591==
    ==4591== Thread 1:
    ==4591== Conditional jump or move depends on uninitialised value(s)
    ==4591==    at 0x805687B: main (TestQuery.cpp:478)
    ==4591==
    ==4591== Conditional jump or move depends on uninitialised value(s)
    ==4591==    at 0x8056894: main (TestQuery.cpp:478)
    ==4591==
    ==4591== Conditional jump or move depends on uninitialised value(s)
    ==4591==    at 0x80568AD: main (TestQuery.cpp:478)
    ==4591== Warning: set address range perms: large range 215212032 (noaccess)
    ==4591== Warning: set address range perms: large range 125145088 (noaccess)
    ==4591==
    ==4591== ERROR SUMMARY: 6 errors from 4 contexts (suppressed: 18 from 1)
    ==4591== malloc/free: in use at exit: 496 bytes in 2 blocks.
    ==4591== malloc/free: 928,605 allocs, 928,603 frees, 2,514,165,074 bytes allocated.
    ==4591== For counts of detected errors, rerun with: -v
    ==4591== searching for pointers to 2 not-freed blocks.
    ==4591== checked 10,260,564 bytes.
    ==4591==
    ==4591==
    ==4591== 144 bytes in 1 blocks are possibly lost in loss record 1 of 2
    ==4591==    at 0x4005906: calloc (vg_replace_malloc.c:279)
    ==4591==    by 0xB3671A: _dl_allocate_tls (in /lib/ld-2.3.4.so)
    ==4591==    by 0xD9491E: pthread_create@@GLIBC_2.1 (in /lib/tls/libpthread-2.3.4.so)
    ==4591==    by 0x8200C66: public_unit::CThread::start(void*) (Thread.cpp:25)
    ==4591==    by 0x80567C3: main (TestQuery.cpp:473)
    ==4591==
    ==4591==
    ==4591== 352 bytes in 1 blocks are still reachable in loss record 2 of 2
    ==4591==    at 0x40044F6: malloc (vg_replace_malloc.c:149)
    ==4591==    by 0xB9905E: __fopen_internal (in /lib/tls/libc-2.3.4.so)
    ==4591==    by 0xB9911C: fopen@@GLIBC_2.1 (in /lib/tls/libc-2.3.4.so)
    ==4591==    by 0x805940C: CSearchThread::run(void*) (TestQuery.cpp:363)
    ==4591==    by 0x8200D09: public_unit::CThread::thread_func(void*) (Thread.cpp:44)
    ==4591==    by 0xD94370: start_thread (in /lib/tls/libpthread-2.3.4.so)
    ==4591==    by 0xC0DFFD: clone (in /lib/tls/libc-2.3.4.so)
    ==4591==
    ==4591== LEAK SUMMARY:
    ==4591==    definitely lost: 0 bytes in 0 blocks.
    ==4591==      possibly lost: 144 bytes in 1 blocks.
    ==4591==    still reachable: 352 bytes in 1 blocks.
    ==4591==         suppressed: 0 bytes in 0 blocks.

    关键字在:ERROR SUMMARY, LEAK SUMMARY
            "definitely lost" means your program is leaking memory -- fix it!
            "possibly lost" means your program is probably leaking memory, unless you're doing funny things with pointers.
            "still reachable" means your program is probably ok -- it didn't free some memory it could have. This is quite common and often reasonable. Don't use --show-reachable=yes if you don't want to see these reports.
            "suppressed" means that a leak error has been suppressed. There are some suppressions in the default suppression files. You can ignore suppressed errors

    另外一种方式,激活加载调试器
    gcc -Wall   -g  -pg   -o get_XMLDOC  get_XMLDOC.c
    $ valgrind   --db-attach=yes  --leak-check=full       ./get_XMLDOC   ~/eragon/data/offer_gb.xml  1.xml  10
    ==8956== Memcheck, a memory error detector.
    ==8956== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
    ==8956== Using LibVEX rev 1606, a library for dynamic binary translation.
    ==8956== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
    ==8956== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
    ==8956== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
    ==8956== For more details, rerun with: -v
    ==8956==
    ==8956==
    ==8956== ---- Attach to debugger ? --- [Return/N/n/Y/y/C/c] ----
    ==8956==
    ==8956== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
    ==8956== malloc/free: in use at exit: 1,953 bytes in 2 blocks.
    ==8956== malloc/free: 4 allocs, 2 frees, 2,657 bytes allocated.
    ==8956== For counts of detected errors, rerun with: -v
    ==8956== searching for pointers to 2 not-freed blocks.
    ==8956== checked 52,840 bytes.
    ==8956==
    ==8956== 1 bytes in 1 blocks are definitely lost in loss record 1 of 2
    ==8956==    at 0x40044F6: malloc (vg_replace_malloc.c:149)
    ==8956==    by 0x80488C0: main (get_XMLDOC.c:38)
    ==8956==
    ==8956== LEAK SUMMARY:
    ==8956==    definitely lost: 1 bytes in 1 blocks.
    ==8956==      possibly lost: 0 bytes in 0 blocks.
    ==8956==    still reachable: 1,952 bytes in 1 blocks.
    ==8956==         suppressed: 0 bytes in 0 blocks.
    ==8956== Reachable blocks (those to which a pointer was found) are not shown.
    ==8956== To see them, rerun with: --show-reachable=yes
    Profiling timer expired

    2.4.        检查性能瓶颈
    $valgrind --tool=callgrind ./iquery  -f ../conf/se.conf_forum   -s "forum_thread?q=mp4"

    ==4607==
    ==4607== Events    : Ir
    ==4607== Collected : 251772397
    ==4607==
    ==4607== I   refs:      251,772,397

    4607为进程号。
    $ ll
    -rw-------  1 search search   712159  7月  9 22:31 callgrind.out.4607
    $ callgrind_annotate --auto=yes  callgrind.out.4607
    WARNING: header line 2 malformed, ignoring
        line: 'creator: callgrind-3.2.0'
    --------------------------------------------------------------------------------
    I1 cache:
    D1 cache:
    L2 cache:
    Timerange: Basic block 0 - 46942078
    Trigger: Program termination
    Profiled target:  ./iquery -f ../conf/se.conf_forum -s forum_thread?q=mp4 (PID 4607, part 1)
    Events recorded:  Ir
    Events shown:     Ir
    Event sort order: Ir
    Thresholds:       99
    Include dirs:     
    User annotated:   
    Auto-annotation:  on

    --------------------------------------------------------------------------------
             Ir
    --------------------------------------------------------------------------------
    251,772,397  PROGRAM TOTALS

    --------------------------------------------------------------------------------
            Ir  file:function
    --------------------------------------------------------------------------------
    54,769,656  ???:__mcount_internal [/lib/tls/libc-2.3.4.so]
    26,418,450  GBKNormalString.cpp:dictionary::CGBKNormalString::initNormalChars() [/home/search/eragon_yb/bin/iquery]
    22,820,690  ???:mcount [/lib/tls/libc-2.3.4.so]
    11,559,615  GBKNormalString.cpp:dictionary::CGBKNormalString::initCharKinds() [/home/search/eragon_yb/bin/iquery]

    更多说明参考:
    http://www-128.ibm.com/developerworks/cn/linux/l-pow-debug/

    2.5.        cache测试
    参考:http://www.wangcong.org/articles/valgrind.html
    [search@alitest146 /home/search/eragon_yb/bin]
    $ valgrind   --tool=cachegrind  ./iquery   -f ../conf/se.conf_forum   -s "forum_thread?q=mp3"
    ==8742==
    ==8742== I   refs:      267,968,791
    ==8742== I1  misses:         98,845
    ==8742== L2i misses:         13,382
    ==8742== I1  miss rate:        0.03%
    ==8742== L2i miss rate:        0.00%
    ==8742==
    ==8742== D   refs:      182,288,669  (120,222,370 rd + 62,066,299 wr)
    ==8742== D1  misses:        962,816  (    537,889 rd +    424,927 wr)
    ==8742== L2d misses:        707,813  (    340,925 rd +    366,888 wr)
    ==8742== D1  miss rate:         0.5% (        0.4%   +        0.6%  )
    ==8742== L2d miss rate:         0.3% (        0.2%   +        0.5%  )
    ==8742==
    ==8742== L2 refs:         1,061,661  (    636,734 rd +    424,927 wr)
    ==8742== L2 misses:         721,195  (    354,307 rd +    366,888 wr)
    ==8742== L2 miss rate:          0.1% (        0.0%   +        0.5%  )

    上面的是指令缓存,I1和L2i缓存,的访问信息,包括总的访问次数,丢失次数,丢失率。
    中间的是数据缓存,D1和L2d缓存,的访问的相关信息,下面的L2缓存单独的信息。Cachegrind也生成一个文件,名为cachegrind.out.pid,可以通过cg_annotate来读取。输出是一个更详细的列表。Massif的使用和cachegrind类似,不过它也会生成一个名为massif.pid.ps的PostScript文件,里面只有一幅描述堆栈使用状况的彩图。

    [search@alitest146 /home/search/Isearchv3_Script_yb/tools]
    $ ll  cachegrind.out*
    -rw-------  1 search search  7283 Jul 11 11:21 cachegrind.out. 8633

    $  cg_annotate  --8633  --auto=yes  ~/isearch_yb/src/test/core/TestQuery.cpp                                                      
    --------------------------------------------------------------------------------
    I1 cache:         16384 B, 32 B, 8-way associative
    D1 cache:         16384 B, 64 B, 8-way associative
    L2 cache:         2097152 B, 64 B, 8-way associative
    Command:          ./iquery -f ../conf/se.conf_forum -s forum_thread?q=mp3
    Data file:        cachegrind.out.8633
    Events recorded:  Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw
    Events shown:     Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw
    Event sort order: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw
    Thresholds:       99 0 0 0 0 0 0 0 0
    Include dirs:     
    User annotated:   /home/search/isearch_yb/src/test/core/TestQuery.cpp
    Auto-annotation:  on

    --------------------------------------------------------------------------------
             Ir   I1mr   I2mr          Dr    D1mr    D2mr         Dw    D1mw    D2mw
    --------------------------------------------------------------------------------
    267,968,791 98,845 13,395 120,222,370 537,889 340,938 62,066,299 424,927 366,883  PROGRAM TOTALS

    --------------------------------------------------------------------------------
            Ir  I1mr  I2mr         Dr    D1mr    D2mr         Dw    D1mw    D2mw  file:function
    --------------------------------------------------------------------------------
    56,779,152    28     6 14,194,788      82       3 14,194,788      34      13  ???:__mcount_internal
    26,418,450   108    54 12,868,530  22,710   3,028  1,943,010  79,943  30,480  GBKNormalString.cpp:dictionary::CGBKNormalString::initNormalChars()

           
    ……
    -- User-annotated source: get_XMLDOC.c
    --------------------------------------------------------------------------------
        Ir I1mr I2mr    Dr D1mr D2mr    Dw D1mw D2mw

         .    .    .     .    .    .     .    .    .  #include "stdio.h"
         .    .    .     .    .    .     .    .    .  #define LINE_MAX_LEN  10240
         .    .    .     .    .    .     .    .    .  //get part of  xml
         .    .    .     .    .    .     .    .    .  main(int argc,char *argv[])
        10    1    1     0    0    0     1    0    0   {
         .    .    .     .    .    .     .    .    .       FILE *fp;
         1    0    0     0    0    0     1    0    0       FILE *fpDst =NULL;
         .    .    .     .    .    .     .    .    .      
         8    1    0     0    0    0     4    1    1       char content[LINE_MAX_LEN+1]={0};
         .    .    .     .    .    .     .    .    .       int  inumOfdocs;
         1    0    0     0    0    0     1    0    0       int  currentdocs=0;
         1    1    1     0    0    0     1    0    0       int  isDocBegin = 0;     
         1    0    0     0    0    0     1    0    0       int  isDocEnd = 0;
         .    .    .     .    .    .     .    .    .  
         2    0    0     1    0    0     0    0    0      if (argc < 4)
         .    .    .     .    .    .     .    .    .       {
         .    .    .     .    .    .     .    .    .        printf("usage: get_XMLDOC srcxml dstxml  numOfdocs\n");
         .    .    .     .    .    .     .    .    .        exit(1);
         .    .    .     .    .    .     .    .    .       }           
         .    .    .     .    .    .     .    .    .      
         7    2    1     2    0    0     3    0    0       inumOfdocs = atoi(argv[3]);
         2    0    0     1    0    0     0    0    0       if (inumOfdocs <=0 )
  • [论坛] 如何引入代码覆盖率度量提高测试质量

    2008-07-12 13:44:31

    我们面临的困境
    1) 开发编写的单元测试代码可信度
    2) 功能测试或者自动化测试效果可信度

    为了提高测试过程的质量,是一个复杂系统过程。国外好些年前就引入代码覆盖率工具,比如
    EMMA/Clover。
    呵呵,据了解ebay中国的开发采用EclEmma。

    经过初步评估,针对java语言的EMMA 和针对 linux+ c/c++ +gcc的gcov/lcov都只能做到语句覆盖、函

    数覆盖、类覆盖。对于路径覆盖、条件覆盖等无法做。要做到更加精细,可以考虑结合Jester。

    代码覆盖率工具最让人震撼的是,无须单元测试代码,可以清楚看到执行过/未执行过的代码行,以及由

    宏观到微观的度量结果。另外引入代码覆盖率工具,无须修改代码,成本极低。

    这个结果对于开发而言,可以增加自己负责的模块的单元测试代码,或者去除死代码。
    对于测试而言,可以增加测试用例提高覆盖率,提高测试结果的信心度。

    尽管代码覆盖率工具有这样或者那样的不足,也极难做到100%覆盖,但综合权衡,引入工具还是有积极

    的意义。

    推广代码覆盖率的规划:

    1) 选取一个小型WEB应用代码覆盖工具,结果供测试工程师,分析代码覆盖率效益
    2) 大型项目应用代码覆盖工具
    3) 在研发部门推广EclEmma插件 和gcov/lcov
    4) 经过一段时间实践,在开发提交代码给测试时,要求一起提交代码覆盖率源文件。

    难点:

    1) 测试工程师面对未覆盖的代码行,要有阅读代码能力呼应到业务操作,以有针对性增加测试用例
    1) 加入代码覆盖率结果,意味对上游输出把握更加严格,要求研发部门经理和开发的意识转变以及实质

    性支持

    欢迎这方面有实践的朋友多提建议,谢谢
  • [论坛] 采用EMMA对JMeter执行代码覆盖率分析

    2008-07-12 12:19:01

    emma度量代码覆盖率不需要额外编写单元测试代码。
    支持JAVA GUI、JAVA CONSOLE、JAVA APP SERVER。

    一 安装与配置
    EMMA支持jdk1.2 或以上。

    下载: http://emma.sourceforge.net/
    在我的电脑里面设置CLASSPATH加入emma.jar.
    显示:
    E:\jakarta-jmeter-2.3.1\bin>echo %CLASSPATH%
    E:\alibaba\tools\emma-stable-2.1-lib\emma.jar;.


    二 收集应用的元信息

    这一步必须有.class文件或者包含.class文件的jar包。
    而且必须在应用执行的目录下进行(非源代码的路径),否则第四步收集信息时出现异常"emma ctl:

    coverage.get: RPC failure while executing [coverage.get]
    Exception in thread "main" com.vladium.emma.EMMARuntimeException: coverage.get:
    RPC failure while executing [coverage.get]
            at com.vladium.emma.ctl.CtlProcessor._run(CtlProcessor.java:242)"



    收集元信息(会改写ApacheJmeter.jar内容)
    java emma instr -m overwrite   -cp  ApacheJMeter.jar  -out coverage.em

    正常时当前目录生成coverage.em。

    三 执行应用程序

    jmeter.bat导致异常
    Exception in thread "main" java.lang.NoClassDefFoundError: com/vladium/emma/rt/R
    T
            at org.apache.jmeter.NewDriver.$VRi(NewDriver.java)
            at org.apache.jmeter.NewDriver.<clinit>(NewDriver.java)
    errorlevel=1

    分析确认由于java加载ApacheJMeter.jar包时ClassLoader顺序非预期,通过-

    Xbootclasspath/p:E:\alibaba\tools\emma-stable-2.1-lib\emma.jar  强制优先加载emma.jar。

    故修改jmeter.bat为
    %JM_START% %JM_LAUNCH%  -Xbootclasspath/p:E:\alibaba\tools\emma-stable-2.1-lib\emma.jar  %

    JVM_ARGS% %ARGS%   -jar "%JMETER_BIN%ApacheJMeter.jar" %JMETER_CMD_LINE_ARGS%

    再次启动jmeter.bat,出现提示

    EMMA: collecting runtime coverage data ...
    EMMA: runtime controller started on port [47653]

    netstat 检查47653端口处于Listening状态。

    在JMeter界面上操作。后台会记录代码执行状况

    四 收集代码行、函数、类覆盖信息

    在Jmeter不退出的情况下,执行
    java -cp %CLASSPATH%  emma ctl -connect localhost:47653 -command coverage.get,coverage.ec

    或者Jmeter正常退出的情况下,也会主动收集信息存放在默认的coverage.ec。

    五  生成报告

    java -cp %CLASSPATH%   emma report -r html -in  coverage.em,coverage.ec -

    Dreport.html.out.file=coverage.html -Dreport.metrics=class:50
  • [论坛] gcov和lcov对linux c++分析代码覆盖率

    2008-07-09 16:10:30

    gcov伴随gcc 发布。gcc编译加入-fprofile-arcs -ftest-coverage 参数生成二进制程序,执行测试用例生成代码覆盖率信息。
         fprofile-arcs参数使gcc创建一个程序的流图,之后找到适合图的生成树。只有不在生成树中的弧被操纵(instrumented):gcc添加了代码来清点这些弧执行的次数。当这段弧是一个块的唯一出口或入口时,操纵工具代码(instrumentation code)将会添加到块中,否则创建一个基础块来包含操纵工具代码。gcov主要使用.gcno和.gcda两个文件。
    .gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
    .gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息。
    Gcov执行函数覆盖、语句覆盖和分支覆盖。

       Lcov则是上的gcov 结果展现的一个前端,可从 http://ltp.sourceforge.net/coverage/lcov.php 下载。可以将覆盖率信息转换成html 展现。

       安装lcov:su  - root;make install

       Makefile 在编译和link环节都加入 -fprofile-arcs -ftest-coverage 选项
    GCC = g++   -fprofile-arcs -ftest-coverage
    .SUFFIXES: .o .cpp
    iquery: $(LIBS) TestQuery.o
            $(GCC) $(LDPATH) -g       -o $@ TestQuery.o -lsearch -lupdate -lbuild -lstore -lanalysis -lconfig -ldocument -lmxml -lonline -lutility -ldictionary -lpublic -lpthread -lrt
    .cpp.o:
            $(GCC)  -c -g  $(INCLUDE) -DLINUX    -o $@ $<
            

    执行完iquery命令行。
    [search@b2b_search_211 core]$./iquery   -f  ~/eragon_yb/conf/se.conf  -s "offer_gb?q=mp3"
           
    对于apache module的代码覆盖率分析,必须是启动apache httpd进程,执行查询最后退出apache httpd进程才能收集到信息。

    [search@b2b_search_211 core]$ ll
    总用量 36120
    drwxrwxr-x  4 search search     4096  7月  8 19:23 cpp
    -rwxrwxr-x  1 search search  8742605  7月  8 20:06 ibuild
    -rwxrwxr-x  1 search search 13490318  7月  8 20:06 idelete
    -rwxrwxr-x  1 search search 13711848  7月  8 20:06 iquery
    -rw-rw-r--  1 search search     3115  7月  8 20:04 Makefile
    drwxrwxr-x  3 search search     4096  7月  8 19:23 test
    -rw-rw-r--  1 search search      893  6月 12 18:18 TestAnalysis.cpp
    -rw-rw-r--  1 search search    10551  6月 12 18:18 TestBuild.cpp
    -rw-rw-r--  1 search search    15080  7月  8 20:06 TestBuild.gcno
    -rw-rw-r--  1 search search   115808  7月  8 20:06 TestBuild.o
    -rw-rw-r--  1 search search     1143  6月 12 18:18 TestConfig.cpp
    -rw-rw-r--  1 search search     5366  6月 12 18:18 TestDelete.cpp
    -rw-rw-r--  1 search search    11204  7月  8 20:06 TestDelete.gcno
    -rw-rw-r--  1 search search   252064  7月  8 20:06 TestDelete.o


    生成: TestQuery.gcda、 TestQuery.gcno

    [search@b2b_search_211 core]$ gcov  TestQuery.cpp
    File `TestQuery.cpp'
    Lines executed:22.32% of 336
    TestQuery.cpp:creating `TestQuery.cpp.gcov'


    [search@b2b_search_211 core]$ ll
    总用量 36620
    -rw-rw-r--  1 search search     7024  7月  8 20:08 allocator.h.gcov
    drwxrwxr-x  4 search search     4096  7月  8 19:23 cpp
    -rw-rw-r--  1 search search    12827  7月  8 20:08 GlobalDef.h.gcov
    -rwxrwxr-x  1 search search  8742605  7月  8 20:06 ibuild
    -rwxrwxr-x  1 search search 13490318  7月  8 20:06 idelete
    -rw-rw-r--  1 search search    44797  7月  8 20:08 ios_base.h.gcov
    -rw-rw-r--  1 search search     4638  7月  8 20:08 iostream.gcov
    -rwxrwxr-x  1 search search 13711848  7月  8 20:06 iquery
    -rw-rw-r--  1 search search   128499  7月  8 20:08 locale_facets.tcc.gcov
    -rw-rw-r--  1 search search     3115  7月  8 20:04 Makefile
    -rw-rw-r--  1 search search    12684  7月  8 20:08 MemCache.h.gcov
    -rw-rw-r--  1 search search    10158  7月  8 20:08 MemPool.h.gcov
    -rw-rw-r--  1 search search     6524  7月  8 20:08 new_allocator.h.gcov
    -rw-rw-r--  1 search search     5742  7月  8 20:08 new.gcov
    -rw-rw-r--  1 search search     1844  7月  8 20:08 QueryCache.h.gcov
    -rw-rw-r--  1 search search    44015  7月  8 20:08 stl_algobase.h.gcov
    -rw-rw-r--  1 search search     8328  7月  8 20:08 stl_construct.h.gcov
    -rw-rw-r--  1 search search    44016  7月  8 20:08 stl_function.h.gcov
    -rw-rw-r--  1 search search    31113  7月  8 20:08 stl_multiset.h.gcov
    -rw-rw-r--  1 search search    62978  7月  8 20:08 stl_tree.h.gcov
    -rw-rw-r--  1 search search    10365  7月  8 20:08 Svector.h.gcov

    [search@b2b_search_211 core]$ cat  TestQuery.cpp.gcov

            -:   47:static int  nAverageDocSize = 1024;         
    function _ZN9QueryStatC1EPKcxi called 0 returned 0% blocks executed 0%
        #####:   53:    QueryStat(const char* szQuery, n64_t d, n32_t docs){
        #####:   54:        query = szQuery;
        #####:   55:        dual = d;
        #####:   56:        docnum = docs;
            -:   57:    }
            -:   58:};
            -:   59:struct CmpQueryStat{
    function _ZN12CmpQueryStatclERK9QueryStatS2_ called 0 returned 0% blocks executed 0%
        #####:   60:    bool operator()(const QueryStat& a, const QueryStat& b){
        #####:   61:        return a.dual < b.dual;
            -:   62:    };
            -:   63:};
             1:  534:}
             
           带 #####表示未执行的行
          
    [search@b2b_search_211 core]$
    [search@b2b_search_211 core]$ ll *gcov*

    收集覆盖率数据生成app.info文件
    [search@b2b_search_211 core]$   lcov --directory  .   --capture --output-file app.info
    Capturing coverage data from .
    Found gcov version: 3.4.6
    Scanning . for .gcda files ...
    Found 1 data files in .
    Processing ./TestQuery.gcda
    Finished .info-file creation

    转换成html格式
    [search@b2b_search_211 core]$ genhtml  -o  results  app.info
    Reading data file app.info
    Found 18 entries.
    Found common filename prefix "/home/search/isearch_yb/src"
    Writing .css and .png files.
    Generating output.
    Processing file cpp/core/basis/GlobalDef.h
    Processing file cpp/core/search/QueryCache.h
    ...
    Writing directory view page.
    Overall coverage rate: 117 of 514 lines (22.8%)

    将results目录tar  cvf 打包sz到windows,打开目录夹包含:
    总体报告:

    单个cpp文件的覆盖率:


    还可以看到具体的行执行情况


    另外再运行一组更丰富的查询日志,测试结果截然不同。

    [ 本帖最后由 liangjz 于 2008-7-9 16:15 编辑 ]
  • [论坛] 电信网管系统编写DLL API供loadrunner调用的规范

    2008-07-05 23:16:25

    由于性能脚本开发工具一些固有的缺陷,加上网管系统多用事件触发,压力入口存在多个,录制采用的协议相对底层(非web),解决回放的成本高。
         故将前台用户操作部分的核心功能封装成纯C语言的dll,供loadrunner调用,具体要求:
    (1)将存在度量用例响应时间的程序段(存在用户等待的地方),封装成一个 dllexport function(in 变化参数,out 结果代码,out 错误消息)函数。in参数不用二维数组、函数指针等复杂类型。多用一维数组,字符串,指针,int/long等简单类型。in参数为界面上看到的友好名称或者能轻易从数据库查询出来的值。
    (2)若为触发的事件,外部调用能控制等待或者轮循的速率控制。 如sleep...
    (3)对于回调的事件,有专门的函数收包,可以不审核包的内容。
    (4) 对核心函数应该提供调用样例。如
    init(..);
    login(user,passwd.....);
    getalert(...)
    cofirmalert(...)  
    logout(..);
    注意参数都是对客户而言是友好的,非下层corba或者socket等私有key.
    若后台网元传送到采集机/服务器无法模拟峰值吞吐的 ,同样有如上要求。
    如何客户端主动发送的请求与服务器推送的告警所用端口分开,请说明两个端口。
    若核心程序为Java包,则请封装为JAR,暴露核心功能class以及方法。   

    另外,请厂家利用viso描述核心功能在采集机、应用服务器、DB之间的信息流图.

    [ 本帖最后由 liangjz 于 2008-7-5 23:20 编辑 ]
  • [论坛] loadrunner的不足与jmeter用武之地

    2008-06-20 22:08:49

    我们购买了LoadRunner 8.1 作为性能测试主流工具,商业工具确实用的蛮好的,在部门层面推行顺利。
    结合实践,发现有几点相当不错:

    1) LoadRunner controller运行稳定
    2) 支持多个load generator 一起施加压力
    3) 监控指标相对齐全
    4) 性能测试结果颗粒细致
    5) 预留有性能结果在monitor上的api 接口
    ...

      但LoadRunner是否足够完美了呢?答案:NO

    1) 对汉语的编码支持问题:utf-8/gbk设置导致有时仅用英文作web_reg_find的check point

    2) LoadRunner 8.1 Udp方式监控unix资源导致有断续, 呵呵,改天要电话咨询下HP有无补丁。
    (LR 8.0有的)

    3) 有时应用vugen 录制/回放异常退出程序

    4) 最为诟病的:昂贵

    5) 支持jboss/tomcat/mysql等的应用性能数据需要自己实现,实际上监控linux也无可用内存、iowait%、网络流量等指标

    ...

      我们把更多眼光关注开源社区,评估opensta、jmeter、webload...。 最终选取与公司主流技术平台( java+apache2+ jboss4.2 +oracle9i/10g + redhat linux)一致的jmeter做一个补充。

      对于Jmeter最为关键的几步:

    1) 分析性能测试结果和loadrunner不同的原因
    2) jmeter 产生压力的稳定性以及原理
    3) 监控扩展能力。 linux+oracle9i+jboss+mod_jk 等这些需要支持,呵呵,否则很可能需要手工收集各个平台性能数据,造成效率低下
    4) jmeter脚本调试能力,支持参数化、关联、检查点、http协议自主控制(超时、cookie、http头、是否下载non-html资源)等
  • [论坛] 容量规划问题列表,期待专家深入交流

    2008-06-15 21:44:20

    沙龙交流前自己准备的容量规划方面的问题列表,呵呵,也期待业界这方面的专家指点。

    1 瓶颈资源到达75%以后,容量预测偏差难以衡量,预测准确率陡降。
    现有容量规划软件包容这种情况?或者如何做能提升这个区域的预测准确度

    2 SAP 的容量规划工具可容忍偏差范围多大?
    3 SAP 内部有自己的监控软件么?包括应用级别的监控。

    现在的软件更多针对应用服务器、web server和os层面的监控,但对应用本身的监控是缺乏的

    假如没有这些细粒度的监控数据,SAP 如何更好为用户行为建模?

    4 SAP 容量规划软件建模算法是什么?是否为排队网络?

    可以调整客户到达分布与服务时间分布等参数?

    5 BELL实验室网络测试发现,用长相关或自相似随机模型比排队网络模型更符合web 网站客户到达分布? SAP 容量规划软件针对更合适的模型做调整么?

    6 SAP 容量规划软件内部有what-if 假设分析么?直接支持针对内存或者硬盘的what-if分析?

    7 SAP 针对跨机型的容量规划如何做?

    尤其是sun公司不参加TPCC评估后的机型 。

    8 如何做容量规划效果的反馈

    9 做容量规划的团队组员有几个,都是怎么样的专业背景(数学?计算机?)

    10 开源容量建模工具要求手工采集非常多数据,必然引入较大的误差?对于这种状况,有何建议


       经过和SAP 工程师交流。负责容量规划的工程师和负责测试的不属于同一个部门,容量规划工程师面对咨询公司,提供硬件建议。

      国内的SAP工程师更多是规划软件的应用者。SAP 软件相对成熟,且部署的机型相对单一。目前容量规划结果满足需求。
      
      SAP有商业逻辑的监控。SAP容量规划软件采集生产系统数据建模,在web页面上输入参数,降低建模门槛。目前SAP容量规划软件建模依赖经验值,而非各种复杂的数学模型。当下没有必要研究开源建模工具。

      SAP软件用内部开发的语言开发的。有很好的扩展性。
       
      由于上述背景,我自己碰到的一些问题就没有很深入交流。

      目前阿里巴巴需要自己建立模型,并需要长期校准模型,另外由于需求、应用的多变,容量规划的门槛依然需要具备较高的数学建模与计算机性能分析方面的背景。
  • [论坛] 容量规划沙龙4原则以及个人理解

    2008-06-15 01:18:08

    个人觉得今天容量规划沙龙最核心内容即4原则

    1)经过良好调优的系统才容量规划
    2)可扩展性好的系统才做容量规划
    3)人人有容量规划意识。执行T-shirt sizing是一个巨大进步
    4) 最关键的事情是测量

    其他的还有
    5) 用真实的产品数据做容量规划
    6) 特别区分对待的容量规划场景
    7) 追求响应时间与成本间平衡

      欢迎其他朋友补充。

    以上的点说得都很实在。
    根据自己的实践做一个发散说明

    1)容量规划有一个难点:在系统扩容和调优之间取得平衡。
    就是停止调优的标准是什么?

    目前我是根据经验值判断特定的硬件、配置参数支撑一定的访问模式、数据量、并发数、吞吐率且满足响应时间等SLA指标。 另外,检查系统不存在core dump或者大量连接超时,日志无异常等。
    有较大的主观性。

    2) 系统扩展性良好。

    根据了解,SAP 没有结合性能测试做系统的可扩展性判断。呵呵,也许SAP架构很多年稳定了,没有必要做这个事情。

    我们实践中,会设置多个场景执行性能测试或者了解系统架构判断。
    如是否采用多线程技术?集群是否采用session技术?

    建模采用的数学模型一般有很多的假设,就是公式成立有很多前提条件。性能测试需要判断结果是否违背了假设。同样预测时,也需要判断是否背离假设

    3) 人人容量规划意识

    从阿里巴巴的角度看,应该是从架构设计权衡系统扩展性、开发加入代码性能探针、性能测试判断是否该停止调优、运维部门长期跟踪反馈性能监控数据以及采购规划、数据仓库平台采集PV、运营部门预测下一年业务增长速度等多个环节。

    据目前看,要走的路还很长。
    对阿里巴巴而言,在网站购买的大量便宜的PC server背景下,容量规划的收益与成本不是足够一目了然,以及资源紧缺是最头大的问题。

    与前同事聊天,目前广东电信研究院的容量规划的驱动力不足是当下最头痛的事情。


    4) 第四个观点:测量是最关键的。


    这个论点放到阿里巴巴。我个人有不同的看法。
    测量是很重要。个人认为借助测量到的数据,如何构造一个合理的容量模型、如何校准模型符合实际情况更关键,否则预测的结果偏差过大导致没有太多的参考价值。

    另外,目前的商业工具或者开源工具都存一些不足,如何对工具做二次开发完善,也是一件很有挑战性的工作。
  • [论坛] 容量规划工具

    2008-06-14 23:45:51

    1 开源
      java model tool
      pdq

    2 借用定律

    A
      little's  law
                 N = X * R

    N = Number of requests in the system
    X = Throughput
    R = Response Time

    B  Utilization law

    U = X * S

    U = Utilization
    X = Throughput
    S = Service Time

    c Stretch Factor

    Stretch Factor=1/ (1-U) =response time/service time

    where U is the utilization of the server.
    The analytic formula for estimating stretch factor assumes the following:
    There are an infinite number of customers
    The arrival times are exponentially distributed
    The service times are exponentially distributed


    3 商业工具
    teamquest,国外SUN 公司、国内广东电信研究院用
    bmc performance assurance,上海电信研究院用
    原来Mercury工具也和一厂商有容量规划工具的合作的现在没有了

    其他的请各位朋友补充
1615/9<123456789>
Open Toolbar