DTrace 지원
DTrace 지원 (perldtrace)
Perl은 DTrace라는 추적 프레임워크를 지원해요. 이 문서는 Perl이 노출하는 DTrace 프로브(probe)들을 하나씩 설명하고, 어떤 용도로 쓸 수 있는지 예시와 함께 보여드려요.
DTrace는 시스템·애플리케이션 전반을 포괄하는 추적 프레임워크예요. Perl은 DTrace의 프로바이더(provider) 로 동작해서 계측(instrumentation)용 프로브(probe) 여러 개를 노출해요. 이를 커널 수준 프로브는 물론 MySQL 같은 다른 프로바이더의 프로브와 함께 쓰면 소프트웨어 결함은 물론 단순히 앱의 병목 지점까지 진단할 수 있어요.
본문
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-entry와 sub-return 프로브를 제공하는 Perl 최초의 DTrace 지원이 추가됐어요.
5.14.0
sub-entry와 sub-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} 변수의 변화를 추적한다고 이해하면 돼요. 특히 NEWPHASE와 OLDPHASE의 값이 바로 ${^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
이 CPAN 모듈로 Perl로 작성한 애플리케이션 수준 DTrace 프로브를 만들 수 있어요.
AUTHORS
Shawn M Moore [email protected]