记录阿里巴巴QA架构组成长点滴。2008年关键词为效率,技术,影响力!QA/测试架构师定义:开发和设计测试框架测试库;纵横全局的考虑产品的功能,设计复杂的测试系统;负责研发某一项特定的测试技术;为公司考虑如何提高测试效率。领导公司测试技术的发展和测试策略上的方向,关注整个公司的测试部门的问题,前瞻性的考虑未来的版本的测试策略和技术。测试架构师计划/设计测试平台,关注着产品的测试过程,提供咨询服务,影响到公司内的测试机构测试社区,以及开发机构等,对产品各个方面施加深远而正确的影响,最终提高整体软件质量。

发布新日志

  • Valgrind 检测linux上c++内存泄露

    2008-07-15 21:51:19

    Linux c++上常用内存泄露检测工具有valgrind, Rational purifyValgrind免费。Valgrind 可以在 32 位或 64 PowerPC/Linux 内核上工作。

    Valgrind工具包包含多个工具,如Memcheck,Cachegrind,Helgrind, CallgrindMassif。下面分别介绍个工具的作用:

    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 [])
    • srcdst的重叠(Overlapping src and dst pointers in memcpy() and related functions)

    Valgrind不检查静态分配数组的使用情况。

    Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试

    1.1.      下载安装

     http://www.valgrind.org

    安装

    ./configure;make;make install

    1.2.      编译程序

    被检测程序加入 –g  -fno-inline 编译选项保留调试信息。

     

    1.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

     

    1.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/

     

    1.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%  )

     

    上面的是指令缓存,I1L2i缓存,的访问信息,包括总的访问次数,丢失次数,丢失率。

    中间的是数据缓存,D1L2d缓存,的访问的相关信息,下面的L2缓存单独的信息。Cachegrind也生成一个文件,名为cachegrind.out.pid可以通过cg_annotate来读取。输出是一个更详细的列表。Massif的使用和cachegrind类似,不过它也会生成一个名为massif.pid.psPostscrīpt文件,里面只有一幅描述堆栈使用状况的彩图。

     

    [search@alitest146 /home/search/Isearchv3_scrīpt_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

    查看(938) 评论(0) 收藏 分享 管理

  • gcov和lcov对linux c++分析代码覆盖率

    2008-07-09 16:19:17

    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 展现。

    安装lcovsu  - 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 打包szwindows,打开

    总体报告:

     

    单个cpp文件的覆盖率:

     

     

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

     

     

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

     

  • 测试中经常遇到的文件句柄打开过多的解决_by_WXC

    2008-04-29 17:23:54

    特别是在搜索性能测试的时候遇到比较多的类似问题:

    有一些概念性的东西还是需要分下类,写一下吧,好记性不如烂笔头。呵呵~

     

    /proc/sys/fs/file-max整个系统可以打开的文件数的限制。
    ulimit -n
    修改的是当前shell和它的子进程可以打开的文件数的限制。

     

    echo 200000 > /pro/sys/fs/file-max 改变当前的系统句柄数目,仅适用于运行中的系统。

    /etc/sysctl.conf文件中加入一行 fs.file-max = 200000 ,然后在命令行中输入 sysctl –p

    永久生效。

     

    ulimit –n 65535 :仅改变当前用户,当前shell及其子shell的句柄数。

    /etc/security/limits.conf: 文件,插入一行:user * nofile  65535:永久改变所有登录用户的句柄数目。

     

    在大并发量的测试时候,遇到too many files open,用一下以上的设置,相信问题会迎刃而解。

  • inet_ntoa(remote_addr.sin_addr) 在64位linux下core dump

    2008-04-15 21:18:52

    在编写一个网络应用程序,在32位Linux下已经运行了相当长时间,无core dump,移植到64

    我都是单进程执行的。

     

     

    Program terminated with signal 11, Segmentation fault.

    #0  0x0000003a53c75350 in strlen () from /lib64/libc.so.6

    (gdb) bt

    #0  0x0000003a53c75350 in strlen () from /lib64/libc.so.6

    #1  0x0000003a53c45b88 in vfprintf () from /lib64/libc.so.6

    #2  0x0000003a53c60e09 in vsprintf () from /lib64/libc.so.6

    #3  0x0000003a53c4b958 in sprintf () from /lib64/libc.so.6

    #4  0x000000000040156b in socket_server () at getlinuxstat.c:183

    #5  0x0000000000401c90 in main (argc=1, argv=0x7fff4b872328) at getlinuxstat.c:349

    (gdb) f 4

    #4  0x000000000040156b in socket_server () at getlinuxstat.c:183

    183                                                                                                             sprintf(buf_log,"received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

     

      咨询开发用线程安全的inet_ntop函数,但是这样的话,就会用到两个额外的数组。总要有些牺牲的。
    使用inet_ntoa的话,就不能够在同一个函数的几个参数里面出席那两次inet_ntoa,或者是第一个inet_ntoa未使用结束之前,不要使用第二个。

    更改实现为:

     if ( NULL== (char*) (inet_ntop(AF_INET,&remote_addr.sin_addr.s_addr,str,31)) )

     

    详细的代码如下:

    int socket_server()

    {

        int sockfd,client_fd; /*sock_fd:监听socketclient_fd:数据传输socket */

        struct sockaddr_in my_addr; /* 本机地址信息 */

        struct sockaddr_in remote_addr; /* 客户端地址信息 */

        int sin_size;

        char  recv_buf[MAX_BUF_SIZE]={0};

        int   recv_size=0;

        char  send_buf[MAX_BUF_SIZE]={0};

        int    send_size=0;

        int  pid;

        int  status;

        struct timeval tv;

        struct in_addr clientaddr ;

        char  str[32]={0};

        char  buf_log[MAX_BUF_SIZE]={0};

     

        enum  stat_action  action;

        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

            sprintf(buf_log,"socke errno=%d,desc=%s\r\n",errno,strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

            return 1;

        }

     

       my_addr.sin_family=AF_INET;

       my_addr.sin_port=htons(SERVPORT);

       my_addr.sin_addr.s_addr = INADDR_ANY;

       bzero(&(my_addr.sin_zero),8);

       if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))  == -1) {

          sprintf(buf_log,"bind errno=%d,desc=%s\r\n",errno,strerror(errno));

          buf_log[strlen(buf_log)]=0;

          writelog(g_logfile,buf_log);

          return 1;

       }

       if (listen(sockfd, BACKLOG) == -1) {

         sprintf(buf_log,"bind errno=%d,desc=%s\r\n",errno,strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

         return 1;

        }

        tv.tv_sec= SOCKET_TIMEOUT_SECOND;

        tv.tv_usec=0;

     

        while(1) {

             memset(&remote_addr, 0, sizeof(struct sockaddr));

            sin_size = sizeof(remote_addr);

            if ((client_fd = accept(sockfd, (struct sockaddr *)(&remote_addr), &sin_size)) == -1) {

               sprintf(buf_log,"accept errno=%d,desc=%s\r\n",errno,strerror(errno));

               buf_log[strlen(buf_log)]=0;

               writelog(g_logfile,buf_log);

               continue;

              }

     

            //sprintf(buf_log,"received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

     

            if ( NULL== (char*) (inet_ntop(AF_INET,&remote_addr.sin_addr.s_addr,str,31)) )

            {

               printf("inet_ntop error,errno=%d,desc=%s\r\n",errno,strerror(errno) );

            }

            sprintf(buf_log,"received a connection from %s\n", str);

     

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

     

           if (setsockopt(client_fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1)

           {

              sprintf(buf_log,"warning!setsockopt  errno=%d,desc=%s\r\n",errno,strerror(errno));

             buf_log[strlen(buf_log)]=0;

             writelog(g_logfile,buf_log);

           }

     

           if ( (pid=fork()) == 0) { /* 子进程代码段 */

               while(1)

               {

                 memset(recv_buf,0,MAX_BUF_SIZE);

                 recv_size=recv(client_fd,recv_buf,MAX_BUF_SIZE -1 ,0);

                 if(recv_size ==-1)

                 {

                    sprintf(buf_log,"recv errno=%d,desc=%s\r\n",errno,strerror(errno));

                     buf_log[strlen(buf_log)]=0;

                    writelog(g_logfile,buf_log);

                    close(client_fd);

                    exit(1);

                 }

                 else if( 0== recv_size)

                {

                   sprintf(buf_log,"connection reset by peer!\r\n");

                    buf_log[strlen(buf_log)]=0;

                    writelog(g_logfile,buf_log);

                   exit(1);

                }

                 else     //if (1 == recv_size)

                 {

     

                   action=atoi(recv_buf);

                   sprintf(buf_log,"recv_buf=%s,recv_size=%d,action=%d\r\n",recv_buf,recv_size,action);

                   buf_log[strlen(buf_log)]=0;

                   writelog(g_logfile,buf_log);

                   memset(send_buf,0,MAX_BUF_SIZE);

     

                   if (exec_command(2,action,send_buf) ==-1 )

                    {

                         continue;

                    }

     

                   send_buf[ strlen(send_buf)] = 0;

                   sprintf(buf_log,"begin send...,send_buf=%s\r\n",send_buf);

                   buf_log[strlen(buf_log)]=0;

                   writelog(g_logfile,buf_log);

                   if (send(client_fd, send_buf,strlen(send_buf), 0) == -1) {

                      sprintf(buf_log,"send errno=%d,desc=%s\r\n",errno,strerror(errno));

                       buf_log[strlen(buf_log)]=0;

                       writelog(g_logfile,buf_log);

                      close(client_fd);

                      exit(1);

                   }

     

                 }

              }

          }

          else if(pid <0)

          {

            sprintf(buf_log,"socket_server fork errno=%s\n",strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

          }

          else

          {

            //parent;

            close(client_fd);

            waitpid(pid,&status,0);

     

           }

     

       }

      return 0;

    }

     

     

     

     

     

     

  • google测试初探

    2008-03-11 12:43:41

    偶今晚来京和一 google哥们(前同事,哈哈,沾光了) 聊聊google情况。

    1)google 中国人数 6/7 百人
    2) 测试人数很少 ,测试和开发都统称工程师。地位很高
    3) 搜索引擎测试不在中国
    4) 黑盒,白盒 ,安全,性能测试,接口测试都做。
       测试工具多为自主研发。类似LOADRUNNER\QTP 等看不到的
       呵呵 这点非常强 。

      我们的奋斗目标啊 。

      而且测试人员很少的情况下,这点看来生产率很高啊

    5)工程师多为刚走出校门的新人,但经过GOOGLE的 7轮面试折磨,能力相比很强。
      偶很羡慕啊。呵呵
    6) 1年有2-3次回美国总部培训机会

    7) 具体的技术级别有: 工程师,leader,高级工程师,资深工程师,杰出工程师 

      高级工程师就需要美国总部面试.要求很高

      据说国内仅仅有几个杰出工程师 

    8) 服务器平台

       OS 在linux上改造.

       用的平台\语言很多,以JAVA/C++为主 .

     

       

  • 搜索引擎测试的难点

    2008-02-26 23:56:08

    衡量搜索引擎系统功能质量方面有2大指标,查询率、查准率。

    性能方面从吞吐率、响应时间、系统资源消耗等多方面综合考虑。

    搜索引擎应用参与运作的角色划分:分发请求/合并查询结果的merger,以及查询服务的searcher.

     

    搜索引擎系统部署可以划分为:

    1)      1 Merger Nsearcher searcher上数据一样  (分布式单个集群多台机器)  N>=1且为整数

    2)      1个机器 同时充当Merger以及searcher (单机版)

    3)      为避免2)单点故障,几台机器同时为merger/searcher,机器的数据一样。

    4)      M 个分布式单个集群多台机器组成 1个大型的分布式多集群多机器的复杂环境

     

    实践中3)4)  2种部署模式都是存在的。

     

    大数据量、高吞吐率的都采用4),避免单点故障

    小型的数据采用3) ,节约成本。

     

    单机上搜索引擎的模块划分一般有:

    Ø        索引模块:为海量数据(数据库导出的文件数据) 建立索引文件 (依照一定数据结构格式保存为二进制文件)

    Ø        查询模块:接收http请求,查询本机硬盘上的索引文件,返回文档ID以及第二次查询时返回具体的内容

    Ø        即时更新模块:加入新的数据,可以从0开始重新建索引,也可以在原有基础上增加索引。

    Ø        分布式模块:merger/searcher 多台机器的网络通信。

    Ø        CACHE模块:这里可以做查询请求的缓存,也可以做查询结果的缓存,但缓存后者的话,将极大消耗系统内存。

    Ø        其他管理模块

    Ø        外部接口

     

     

    基于如上复杂的系统架构,尤其是4)模式,我们在测试当中也碰到相当多棘手的技术问题

    1)      海量数据是否都按预期的分词算法建立索引了呢?

    2)      机器分词的效果与手工分词相差有多大呢?

    3)      海量查询的返回结果是否多查了

    4)      海量查询的返回结果是否漏查了

    5)      海量查询的返回结果的加亮、标注如期加了?

    6)      海量查询的返回结果中相关性分数计算是否正确?

    7)      海量查询的返回结果积分计算是否正确了呢

    8)      海量查询的返回结果积分相同时,排序的先后依据唯一么?

    9)      加入即时更新模块后,每次查询结果都不同,新建的索引内容是否都反馈到查询结果里面了呢

    10)  海量数据时CACHE是否预期CACHEcache的内容?

    11)  海量数据时CACHE是否依照一定的过时算法令cache的内容失效呢?

    12)  应用程序在32LINUX 操作系统和64位的LINUX的索引、查询结果是否依然一样?

    13)  应用程序在不同的OS 上索引、查询结果是否依然一样?

     

     

    我们在实践中,针对查询结果正确性有3类方法处理以上问题

    第一类基于人工肉眼对比,极度耗费脑细胞

    1)      少量数据单机测试准确性

    2)      少量数据1个集群,搭建1merger 1searcher 测试准确性

    3)      少量数据1个集群,搭建1merger searcher 测试准确性

    4)      少量数据多个集群,搭建1merger searcher 测试准确性

     

    第二类,经过人工对比确认基本功能无大问题后,开发linux shell脚本或者loadrunner脚本比较部署方式不同但测试返回结果理当相同的。这个方法也帮我们发现了一些BUG

     

    第三类方法,

    直接测试大量数据多个集群,搭建1merger searcher 测试准确性。

    这个时候采用loadrunner施加高峰压力,抽样检查查询请求的正确性。

     

    对于分词结果、相关性的结果,有人可能建立另外按照同样的算法以及输出格式,由2个不同的开发工程师实现,再对比同样的数据分词、相关性是否相同。在项目开发时间从容的情况下,可以考虑这么做的,但现实中有几个项目时间从裕?呵呵,我没有这么好运气遇上。

     

    针对搜索引擎测试的困难,欢迎各位各抒己见。