2010-01-12 5 views
3

Ruby 및 C로 작성된 프로그램이 있습니다. C 부분은 공유 라이브러리이며 Ruby 프로그램의 확장입니다. gprof를 사용하여 작성한 C 공유 라이브러리를 프로파일 링하려고합니다. 나는이 같은 공유 라이브러리를 컴파일 :Ruby 프로그램에 의해 호출 된 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 

가 그럼 난이 공유 라이브러리를로드 루비 프로그램을 실행하고 나는 현재 디렉토리에 gmon.out 파일을 기대하지만, 어떤 이유로 파일의 gmon.out에 대한 생성되지 않습니다. 어떻게해야합니까?

나는 이것을 봤지만 만족스러운 답변을 찾을 수 없었다.

P. - 해결 방법으로, 프로필에 사용할 수있는 순수 C 프로그램 (공유 라이브러리로 생성되는 대신) 인 수정 된 버전을 사용할 수 있지만 동일한 C 확장의 두 버전을 유지 관리하는 것은 지루합니다. 둘 사이의 많은 차이).

공유 라이브러리를 직접 사용하는 C 프로그램을 작성해 보았습니다. 나는 즉시 공유 라이브러리를 초기화하는 동안 호출되는 루비 라이브러리 함수 중 하나에서 페이지 폴트를 얻는다. 나는 내부적으로 마술을 할 수있는 루비 프로그램에서로드 될 것으로 기대하고 있다고 생각합니다.

(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를 사용하여 Extension의 Ruby 부분을 컴파일하고 프로파일을 얻었습니다. 폐쇄.

+0

누군가가 답변을 찾고있는 경우; 나는 -pg가 링커 명령에도 전달되어야한다고 생각한다. 즉'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 -pg' – dashesy

+0

답을 찾았 기 때문에이 질문을 닫지 않았 으면합니다. 다른 사람들에게도 유용합니다. –

답변

1

프로파일 링을 위해 gprof보다 더 좋은 옵션 인 oprofile이 발견되었습니다. reports from oprofile은 훨씬 더 포괄적입니다. #ifndef PROFILE을 사용하여 C 확장자에서 seg-faults를 일으키는 루비 부분을 모두 컴파일하고 비 루비 코드로 대체했습니다. 확장 기능 내에서 함수를 호출하기 위해 확장 자체 내에 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; 
... 
... 
... 
0

프로파일 러를 통해 루비 인터프리터 자체를 실행할 수 있습니다. 너무 많으면 공유 라이브러리를로드하고 내 보낸 함수를 호출하는 작은 C 프로그램을 작성하십시오. 그런 다음 그 C 프로그램을 프로파일 링하십시오. 라이브러리의 두 버전을 유지 보수 할 필요가 없습니다.

+0

그래, 루비 인터프리터 자체를 프로파일 링 할 수있을 것 같아. 아마 내가 관심이없는 많은 난관을 헤쳐 나갈 필요는 없을 것이다. 내가봤을 때, 공유 라이브러리 자체를 프로파일 링하는 것이 가능하다고 생각한다. 그럴 수 있음을 시사합니다. 나는 정확한 방법을 알려주는 권위있는 링크를 얻지 못했다. – Sudhanshu

1

당신은 gprof은보다 나은 할 수 있습니다. stackshots을 고려하십시오. pstack, lsstack (얻을 수있는 경우) 또는 수동으로 디버거에서 일시 중지하여 수행 할 수 있습니다. Here's a short intro to the technique.

+0

마이크, opannotate 프로그램에서 제공 한 명령 수 + 시간이 아닌, 동일한 기법 (여기에 대한 내 자신의 대답 참조)이 거기에 설명되어 있습니다. – Sudhanshu

+0

@Sudhanshu : oprofile 문서를 살펴 봤는데 잘 모르겠지만 필요한 것 같아 보인다. 그것은 호출 스택을 샘플링하지만, 벽시계로 샘플링한다면 확실히 알 수는 없습니다. (일부 프로파일 러는 시스템 호출 중에 샘플링하지 않으므로 쓸모가 없습니다.) 그런 다음 호출 사이트 (또는 일반 명령어)에 표시된 숫자가 해당 호출 사이트를 포함하는 샘플의 일부일 경우 올바른 일을합니다. 이 작업을 수행하는 다른 프로파일 러는 RotateRight/Zoom입니다. –

+0

...해야 할 다른 일은 샘플을 처리 할 때와 제어하지 않을 때 (사용자 입력을 기다리는 경우와 같이) 제어 할 수있게하는 것입니다. –