描述由Ruby程序调用的C共享库

时间:2010-01-12 06:47:09

标签: c ruby linux shared-libraries profiler

我有一个用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 个答案:

答案 0 :(得分:1)

在这种情况下,我发现oprofile比gprof更适合进行性能分析。 reports from oprofile更加全面。我使用#ifndef PROFILE从C扩展中编译出导致seg-faults(不是全部都是)的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;
 ...
 ...
 ...

答案 1 :(得分:1)

你可以做得比 gprof 更好。考虑stackshots。您可以使用 pstack lsstack (如果可以获得)或在调试器下手动暂停来执行此操作。 Here's a short intro to the technique.

答案 2 :(得分:0)

您可以通过分析器运行ruby解释器。如果这太多了,请编写一个小型C程序来加载共享库并调用其导出的函数。然后简介那个C程序。它使您无需维护两个版本的库。