代码之家  ›  专栏  ›  技术社区  ›  Sudhanshu

分析Ruby程序调用的C共享库

  •  3
  • Sudhanshu  · 技术社区  · 14 年前

    我有一个用Ruby和C编写的程序。C部分是一个共享库,它是Ruby程序的扩展。我想使用gprof分析我编写的C共享库。我这样编译共享库:

    gcc -I. -I/usr/lib/ruby/1.8/i486-linux -I/usr/lib/ruby/1.8/i486-linux -I. -D_FILE_OFFSET_BITS=64  -fPIC -fno-strict-aliasing -g -march=i686 -O2 -ggdb -pg -fPIC -c extension.c
    gcc -shared -o extension.so extension.o -L. -L/usr/lib -L. -Wl,-Bsymbolic-functions -rdynamic -Wl,-export-dynamic  -lruby1.8  -lpthread -lrt -ldl -lcrypt -lm -lc
    

    然后我执行Ruby程序,它加载这个共享库,我期望在当前目录中有一个gmon.out文件,但是由于某种原因,这个文件gmon.out不会被创建。我该怎么做?

    我在谷歌上搜索了一下,但找不到满意的答案。

    P.S.-作为一个解决方法,我可以有一个修改过的扩展版本,它是一个纯C程序(而不是作为共享库创建),我可以使用它来进行分析,但是维护同一个C扩展的两个版本(两者之间的大量差异)会变得单调乏味。

    我试着写一个直接使用共享库的C程序。我马上会在Ruby库函数中发现一个页面错误,这个函数在共享库的初始化过程中被调用。我认为它确实期望从Ruby程序中加载,这可能在内部起到了一些神奇的作用。

    (gdb) bt
    #0  0x0091556e in st_lookup () from /usr/lib/libruby1.8.so.1.8
    #1  0x008e87c2 in rb_intern () from /usr/lib/libruby1.8.so.1.8
    #2  0x008984a5 in rb_define_module () from /usr/lib/libruby1.8.so.1.8
    #3  0x08048dd0 in Init_SimilarStr () at extension.c:542
    #4  0x0804933e in main (argc=2, argv=0xbffff454) at extension.c:564
    

    更新: 不要介意。我用ifdef编译了扩展的Ruby部分并得到了一个概要文件。关闭。

    3 回复  |  直到 14 年前
        1
  •  1
  •   Sudhanshu    14 年前

    我发现 oprofile 在这种情况下,要比gprof更好地进行分析。这个 reports from oprofile 更全面。我用ifndef配置文件从C扩展编译了导致SEG错误的Ruby部分(并非所有部分都是),并用非Ruby代码替换了它们。我在扩展本身中编写了一个main()例程来调用扩展中的函数。然后我设置了一个makefile,将扩展编译为一个定义了profile的C程序。然后我 installed oprofile on Ubuntu . 写了这个剧本。

    #!/bin/bash
    sudo opcontrol --reset
    sudo opcontrol --start
    ./a.out Rome Damascus NewYork Delhi Bangalore
    sudo opcontrol --shutdown
    opreport -lt1
    

    编译了我的程序,并执行了上面的脚本,该脚本通过“opreport”命令提供如下输出:

    ...
    ...
    Killing daemon.
    warning: /no-vmlinux could not be found.
    warning: [vdso] (tgid:10675 range:0x920000-0x921000) could not be found.
    warning: [vdso] (tgid:1270 range:0xba1000-0xba2000) could not be found.
    warning: [vdso] (tgid:1675 range:0x973000-0x974000) could not be found.
    warning: [vdso] (tgid:1711 range:0x264000-0x265000) could not be found.
    warning: [vdso] (tgid:1737 range:0x990000-0x991000) could not be found.
    warning: [vdso] (tgid:2477 range:0xa53000-0xa54000) could not be found.
    warning: [vdso] (tgid:5658 range:0x7ae000-0x7af000) could not be found.
    CPU: Core Solo / Duo, speed 1000 MHz (estimated)
    Counted CPU_CLK_UNHALTED events (Unhalted clock cycles) with a unit mask of 0x00 (Unhalted core cycles) count 100000
    samples  %        app name                 symbol name
    12731    32.8949  a.out                    levenshtein
    11958    30.8976  a.out                    corpora_pass2
    5231     13.5161  no-vmlinux               /no-vmlinux
    4021     10.3896  a.out                    corpora_pass1
    1733      4.4778  libc-2.10.1.so           /lib/tls/i686/cmov/libc-2.10.1.so
    542       1.4004  ld-2.10.1.so             /lib/ld-2.10.1.so
    398       1.0284  a.out                    method_top_matches
    

    这里是:最大的使用者是函数levenshtein()。接下来是另一个命令,生成用源代码和每行的执行计数/时间注释的反汇编输出。如下所示(计数/次数在每行执行的左侧):

    > opannotate --source --assembly ./a.out > report.as.handcoded.1
    > cat report.as.handcoded.1
    
    ...
    ...
    ...
               :         __asm__ (
     2  0.0069 : 804918a:       mov    -0x50(%ebp),%ecx
     4  0.0137 : 804918d:       mov    -0x54(%ebp),%ebx
               : 8049190:       mov    -0x4c(%ebp),%eax
    12  0.0412 : 8049193:       cmp    %eax,%ecx
    10  0.0344 : 8049195:       cmovbe %ecx,%eax
     8  0.0275 : 8049198:       cmp    %eax,%ebx
    11  0.0378 : 804919a:       cmovbe %ebx,%eax
    16  0.0550 : 804919d:       mov    %eax,-0x4c(%ebp)
               :                   "cmp     %0, %2\n\t"
               :                   "cmovbe  %2, %0\n\t"
               :                  : "+r"(a) :
               :                    "%r"(b), "r"(c)
               :                  );
               :          return a;
     ...
     ...
     ...
    
        2
  •  1
  •   Community skywinder    7 年前

    你可以做得比 GPROF . 考虑 stackshots . 你可以用 堆栈 , LSStad (如果可以),或者在调试器下手动暂停。 Here's a short intro to the technique.

        3
  •  0
  •   Vijay Mathew Chor-ming Lung    14 年前

    您可以通过分析器运行Ruby解释器本身。如果这太多,编写一个小的C程序,加载共享库并调用其导出的函数。然后分析那个C程序。它可以避免维护库的两个版本。