DTrace 지원

DTrace 지원 (perldtrace)

Perl은 DTrace라는 추적 프레임워크를 지원해요. 이 문서는 Perl이 노출하는 DTrace 프로브(probe)들을 하나씩 설명하고, 어떤 용도로 쓸 수 있는지 예시와 함께 보여드려요.

DTrace는 시스템·애플리케이션 전반을 포괄하는 추적 프레임워크예요. Perl은 DTrace의 프로바이더(provider) 로 동작해서 계측(instrumentation)용 프로브(probe) 여러 개를 노출해요. 이를 커널 수준 프로브는 물론 MySQL 같은 다른 프로바이더의 프로브와 함께 쓰면 소프트웨어 결함은 물론 단순히 앱의 병목 지점까지 진단할 수 있어요.

출처: perldtrace - Perl's support for DTrace

본문

SYNOPSIS

# dtrace -Zn 'perl::sub-entry, perl::sub-return { trace(copyinstr(arg0)) }'
dtrace: description 'perl::sub-entry, perl::sub-return ' matched 10 probes

# perl -E 'sub outer { inner(@_) } sub inner { say shift } outer("hello")'
hello

(dtrace output)
CPU     ID                    FUNCTION:NAME
  0  75915       Perl_pp_entersub:sub-entry   BEGIN
  0  75915       Perl_pp_entersub:sub-entry   import
  0  75922      Perl_pp_leavesub:sub-return   import
  0  75922      Perl_pp_leavesub:sub-return   BEGIN
  0  75915       Perl_pp_entersub:sub-entry   outer
  0  75915       Perl_pp_entersub:sub-entry   inner
  0  75922      Perl_pp_leavesub:sub-return   inner
  0  75922      Perl_pp_leavesub:sub-return   outer

DESCRIPTION

앞서 말했듯 DTrace는 포괄적인 시스템·애플리케이션 수준 추적을 위한 프레임워크예요. Perl은 DTrace 프로바이더로 동작해서 계측용 프로브 여러 개를 노출해요. 커널 수준 프로브와 함께, 그리고 MySQL 같은 다른 프로바이더의 프로브와도 함께 사용하면 소프트웨어 결함이나 애플리케이션의 병목을 진단할 수 있어요.

제공되는 프로브를 사용하려면 Perl을 -Dusedtrace 옵션으로 컴파일해야 해요. DTrace 자체는 계측이 활성화되지 않을 때 오버헤드가 없도록 설계되지만, Perl 쪽 지원은 그 보장을 유지할 수 없어서 대부분의 시스템에서 Perl은 DTrace 프로브 없이 빌드돼요. 주목할 만한 예외는 Mac OS X로, DTrace 지원이 켜진 /usr/bin/perl을 포함해 배포돼요.

HISTORY

5.10.1

sub-entrysub-return 프로브를 제공하는 Perl 최초의 DTrace 지원이 추가됐어요.

5.14.0

sub-entrysub-return 프로브에 네 번째 인자(함수의 패키지 이름)가 추가됐어요.

5.16.0

phase-change 프로브가 추가됐어요.

5.18.0

op-entry, loading-file, loaded-file 프로브가 추가됐어요.

PROBES

sub-entry(SUBNAME, FILE, LINE, PACKAGE)

어떤 서브루틴이든 진입점을 추적해요. 모든 변수는 호출되는(진입하는) 서브루틴을 가리킨다는 점을 기억하세요. 현재 DTrace 액션에서 서브루틴의 *호출자(caller)*에 대한 정보를 얻을 방법은 없어요.

:*perl*::sub-entry {
    printf("%s::%s entered at %s line %d\n",
          copyinstr(arg3), copyinstr(arg0), copyinstr(arg1), arg2);
}

sub-return(SUBNAME, FILE, LINE, PACKAGE)

어떤 서브루틴이든 종료(리턴) 지점을 추적해요. 모든 변수는 리턴하는 서브루틴을 가리킨다는 점을 기억하세요. 현재 DTrace 액션에서 서브루틴의 *호출자(caller)*에 대한 정보를 얻을 방법은 없어요.

:*perl*::sub-return {
    printf("%s::%s returned at %s line %d\n",
          copyinstr(arg3), copyinstr(arg0), copyinstr(arg1), arg2);
}

phase-change(NEWPHASE, OLDPHASE)

Perl 인터프리터 상태의 변화를 추적해요. 이를 Perl의 ${^GLOBAL_PHASE} 변수의 변화를 추적한다고 이해하면 돼요. 특히 NEWPHASEOLDPHASE의 값이 바로 ${^GLOBAL_PHASE}가 보고하는 문자열이니까요.

:*perl*::phase-change {
    printf("Phase changed from %s to %s\n",
        copyinstr(arg1), copyinstr(arg0));
}

op-entry(OPNAME)

Perl 실행 루프에서 각 opcode가 실행되는 것을 추적해요. 이 프로브는 opcode가 실행되기 전에 발화돼요. Perl 디버거가 활성화된 경우에는 DTrace 프로브가 디버거 훅 이후에(그래도 opcode 자체가 실행되기 전에는) 발화돼요.

:*perl*::op-entry {
    printf("About to execute opcode %s\n", copyinstr(arg0));
}

loading-file(FILENAME)

Perl이 개별 파일을 로드하려 할 때(use, require, do 중 어느 것으로든) 발화해요. 이 프로브는 파일이 디스크에서 읽히기 전에 발화돼요. 파일명 인자는 Module::Name 스타일 이름 대신 로컬 파일시스템 경로로 변환돼요.

:*perl*:loading-file {
    printf("About to load %s\n", copyinstr(arg0));
}

loaded-file(FILENAME)

Perl이 개별 파일을 성공적으로 로드했을 때(use, require, do 중 어느 것으로든) 발화해요. 이 프로브는 파일이 디스크에서 읽히고 그 내용이 평가된 후에 발화돼요. 파일명 인자는 Module::Name 스타일 이름 대신 로컬 파일시스템 경로로 변환돼요.

:*perl*:loaded-file {
    printf("Successfully loaded %s\n", copyinstr(arg0));
}

EXAMPLES

가장 자주 호출된 함수

# dtrace -qZn 'sub-entry { @[strjoin(strjoin(copyinstr(arg3),"::"),copyinstr(arg0))] = count() } END {trunc(@, 10)}'

Class::MOP::Attribute::slots                                    400
Try::Tiny::catch                                                411
Try::Tiny::try                                                  411
Class::MOP::Instance::inline_slot_access                        451
Class::MOP::Class::Immutable::Trait:::around                    472
Class::MOP::Mixin::AttributeCore::has_initializer               496
Class::MOP::Method::Wrapped::__ANON__                           544
Class::MOP::Package::_package_stash                             737
Class::MOP::Class::initialize                                  1128
Class::MOP::get_metaclass_by_name                              1204

함수 호출 추적하기

# dtrace -qFZn 'sub-entry, sub-return { trace(copyinstr(arg0)) }'

0  -> Perl_pp_entersub                        BEGIN
0  <- Perl_pp_leavesub                        BEGIN
0  -> Perl_pp_entersub                        BEGIN
0    -> Perl_pp_entersub                      import
0    <- Perl_pp_leavesub                      import
0  <- Perl_pp_leavesub                        BEGIN
0  -> Perl_pp_entersub                        BEGIN
0    -> Perl_pp_entersub                      dress
0    <- Perl_pp_leavesub                      dress
0    -> Perl_pp_entersub                      dirty
0    <- Perl_pp_leavesub                      dirty
0    -> Perl_pp_entersub                      whiten
0    <- Perl_pp_leavesub                      whiten
0  <- Perl_dounwind                           BEGIN

인터프리터 정리 중 함수 호출

# dtrace -Zn 'phase-change /copyinstr(arg0) == "END"/ { self->ending = 1 } sub-entry /self->ending/ { trace(copyinstr(arg0)) }'

CPU     ID                    FUNCTION:NAME
  1  77214       Perl_pp_entersub:sub-entry   END
  1  77214       Perl_pp_entersub:sub-entry   END
  1  77214       Perl_pp_entersub:sub-entry   cleanup
  1  77214       Perl_pp_entersub:sub-entry   _force_writable
  1  77214       Perl_pp_entersub:sub-entry   _force_writable

컴파일 시점의 시스템 호출

# dtrace -qZn 'phase-change /copyinstr(arg0) == "START"/ { self->interesting = 1 } phase-change /copyinstr(arg0) == "RUN"/ { self->interesting = 0 } syscall::: /self->interesting/ { @[probefunc] = count() } END { trunc(@, 3) }'

lseek                                                           310
read                                                            374
stat64                                                         1056

가장 많은 opcode를 실행하는 Perl 함수

# dtrace -qZn 'sub-entry { self->fqn = strjoin(copyinstr(arg3), strjoin("::", copyinstr(arg0))) } op-entry /self->fqn != ""/ { @[self->fqn] = count() } END { trunc(@, 3) }'

warnings::unimport                                             4589
Exporter::Heavy::_rebuild_cache                                5039
Exporter::import                                              14578

REFERENCES

DTrace Dynamic Tracing Guide

https://illumos.org/books/dtrace/preface.html

DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD

https://www.amazon.com/DTrace-Dynamic-Tracing-Solaris-FreeBSD/dp/0132091518/

SEE ALSO

Devel::DTrace::Provider

이 CPAN 모듈로 Perl로 작성한 애플리케이션 수준 DTrace 프로브를 만들 수 있어요.

AUTHORS

Shawn M Moore [email protected]

더 알아보기 (Learn more)