debugging - Erlang에서 trace와 dbg 사용하기




(5)

나는 erlang : trace / 3과 dbg 모듈을 사용하여 서버를 다운시키지 않고 라이브 프로덕션 시스템의 동작을 추적하려고합니다.

documentationdocumentation (온화하게 넣기 위해) 온라인에서 유용한 자습서가없는 것 같습니다.

내가 하루 종일 겪었던 일은 특정 기능에서 모듈에 추적을 적용하여 발생하는 것을 캡처하는 것이 었습니다. dbg : c 및 dbg : p를 사용하는 기능 이었지만 전혀 성공하지 못했습니다 ...

누구든지 라이브 얼랑 시스템에서 트레이스를 사용하는 방법에 대한 간결한 설명을 가지고 있습니까?


Answers

당신이 그래픽 트레이서를 선호한다면 erlyberly 를 시도 erlyberly . 추적 기능 (현재 모든 프로세스에서)을 선택하고 dbg API를 처리 할 수 ​​있습니다.

그러나 과부하로부터 보호하지 못하므로 프로덕션 시스템에 적합하지 않습니다.


'dbg'모듈은 상당히 낮은 수준의 항목입니다. 내가 자주 필요로하는 작업을 위해 자주 사용하는 두 가지 해킹이 있습니다.

  1. http://www.snookles.com/erlang/user_default.erl 에서 Erlang CLI / 쉘 확장 코드를 사용 http://www.snookles.com/erlang/user_default.erl . 그것은 원래 Serge Aleynikov에 의해 (필자가 아는 한) 쓰여졌 고 유용한 "그래서 쉘에 사용자 정의 함수를 추가하는 방법"이었습니다. 모듈을 컴파일하고 ~ / .erlang 파일이 경로를 가리 키도록 편집하십시오 (파일 상단의 주석 참조).

  2. EPER 유틸리티 모음에 번들로 제공되는 " redbug "유틸리티를 사용하십시오. 'dbg'를 사용하여 몇 초 만에 수백만 가지의 추적 이벤트를 생성하는 것은 매우 쉽습니다. 프로덕션 환경에서 그렇게하면 재앙이 될 수 있습니다. 개발 또는 프로덕션 사용을 위해 redbug는 추적으로 인한 과부하로 실행중인 시스템을 종료하는 것을 거의 불가능하게 만듭니다.


함수 호출에 대한 추적의 기본 단계는 비보안 노드에 있습니다.

> dbg:start().   % start dbg
> dbg:tracer().  % start a simple tracer process
> dbg:tp(Module, Function, Arity, []).   % specify MFA you are interested in
> dbg:p(all, c).   % trace calls (c) of that MFA for all processes.

... trace here

> dbg:stop_clear().   % stop tracer and clear effect of tp and p calls.

동시에 여러 기능을 추적 할 수 있습니다. 각 함수에 대해 tp 를 호출하여 함수를 추가하십시오. 수출되지 않은 기능을 추적하려면 tpl 을 호출해야합니다. 함수를 제거하려면 비슷한 방법으로 ctp 또는 ctpl 을 호출하십시오. 일반적인 tp 호출은 다음과 같습니다.

> dbg:tpl(Module, '_', []).  % all calls in Module
> dbg:tpl(Module, Function, '_', []).   % all calls to Module:Function with any arity.
> dbg:tpl(Module, Function, Arity, []). % all calls to Module:Function/Arity.
> dbg:tpl(M, F, A, [{'_', [], [{return_trace}]}]).   % same as before, but also show return value.

마지막 인수는 일치 스펙입니다. dbg:fun2ms 를 사용하면 dbg:fun2ms 가지고 놀 수 있습니다.

p ()를 호출하여 추적 할 프로세스를 선택할 수 있습니다. 항목은 erlang : trace에 설명되어 있습니다. 일부 전화는 다음과 같습니다.

> dbg:p(all, c).   % trace calls to selected functions by all functions
> dbg:p(new, c).   % trace calls by processes spawned from now on
> dbg:p(Pid, c).   % trace calls by given process
> dbg:p(Pid, [c, m]).  % trace calls and messages of a given process

나는 dbg 이 당신을 위해 거의 모든 일을하기 때문에 erlang:trace 를 직접 호출 할 필요가 없다고 생각한다.

라이브 노드에 대한 황금률은 쉘에 추적 출력량 만 생성하여 dbg:stop_clear(). 에 입력 할 수있게합니다 dbg:stop_clear(). . :)

나는 종종 많은 사건 후에 자동으로 멈추는 추적자를 사용한다. 예 :

dbg:tracer(process, {fun (_,100) -> dbg:stop_clear();
                        (Msg, N) -> io:format("~p~n", [Msg]), N+1 end, 0
                    }).

원격 노드 (또는 여러 노드)에서 디버깅을 찾고 있다면 pan , eper , inviso 또는 onviso .


실제 시스템에서는 거의 셸을 추적하지 않습니다. 시스템이 잘 구성되어 있다면 쉘에 인쇄 된 Erlang 로그를 이미 수집하고 있습니다. 이것이 어떤 라이브 노드에서 왜 중요한지 강조 할 필요가 없습니다 ...

파일 추적에 대해 자세히 설명하겠습니다.

파일로 추적 할 수 있으며 나중에 변환 및 파싱 할 수있는 이진 출력을 생성합니다. (추가 분석 또는 자동화 된 제어 시스템 등)

예를 들면 다음과 같습니다.

  • 랩핑 된 여러 파일 추적 (12x50 Mbytes). 큰 트레이스를 사용하기 전에 항상 사용 가능한 디스크 공간을 확인하십시오!

    dbg:tracer(port,dbg:trace_port(file,{"/log/trace",wrap,atom_to_list(node()),50000000,12})).
    

    dbg:p(all,[call,timestamp,return_to]).

    • 실제 노드의 쉘에 무엇인가를 입력하기 전에 항상 테스트 노드에서 테스트하십시오!
    • 가장 먼저 테스트 노드 또는 복제본 노드를 사용하여 스크립트를 먼저 시도하는 것이 좋습니다.

즉, 기본적인 추적 명령 시퀀스를 살펴 보겠습니다.

<1> dbg:stop_clear().

  • 항상 추적 포트를 비우고 이전 추적이 현재 추적을 방해하지 않는지 확인하십시오.

<2> dbg:tracer().

  • 추적 프로그램 프로세스를 시작하십시오.

<3> dbg:p(all,[call, timestamp]).

  • 이 경우 모든 프로세스와 함수 호출을 추적합니다.

<4> dbg:tp( ... ).

  • Zed의 답변 에서처럼

<5> dbg:tpl( ... ).

  • Zed의 답변 에서처럼

<42> dbg:stop_clear().

  • 다시 말하지만 모든 흔적이 결과물에 쓰여지고 나중에 불편 함을 피하는 것입니다.

할 수있는 일 :

  • 쉘에 fun () - s를 정의하여 트리거를 추가하여 주어진 시간이나 이벤트에서 추적을 중지하십시오. 재귀 fun () - s는 이것을 달성하는 것이 가장 좋지만 적용 할 때 매우주의해야합니다.

  • 특정 유형의 인수를 사용하여 특정 함수 호출로 특정 프로세스에 대해서만 추적 할 수 있도록 방대한 패턴 일치를 적용하십시오.

나는 ETS 테이블의 내용을 점검해야만했던 문제와 몇 가지 항목의 출현으로 2-3 분 내에 추적을 중단해야하는 문제가있었습니다.

나는 또한 Francesco Cesarini가 쓴 얼랭 프로그래밍 (Erlang Programming)을 제안한다. ( 얼랭 프로그래밍 @ 아마존 )


GHC 7.0.3 , gcc 4.4.6 , Linux 2.6.29 를 x86_64 Core2 Duo (2.5GHz) 컴퓨터에서 사용하고 ghc -O2 -fllvm -fforce-recomp 를 사용하여 Haskell을 컴파일하고 gcc -O3 -lm 하여 C를 컴파일합니다.

  • 귀하의 C 루틴은 8.4 초 (아마도 -O3 때문에 실행보다 빠릅니다)
  • Haskell 솔루션은 36 초 만에 실행됩니다 ( -O2 플래그로 인해).
  • 귀하의 factorCount' 코드는 명시 적으로 입력되지 않고 Integer 기본값입니다 (Daniel이 내 오진을 바로 factorCount' 감사합니다!). Int 사용하고 11.1 초로 시간을 변경하는 명시적인 형식 서명 (어쨌든 표준 연습 임) 제공
  • factorCount' 당신은 불필요하게 통합을 호출 fromIntegral . 수정 사항은 변경되지 않지만 (컴파일러는 현명하고 운이 좋다).
  • rem 이 더 빠르고 충분하면 mod 사용했습니다. 시간이 8.5 초로 변경됩니다.
  • factorCount' 는 변경되지 않는 두 개의 추가 인수 ( number , sqrt )를 지속적으로 적용합니다. 작업자 / 래퍼 변환은 다음을 제공합니다.
 $ time ./so
 842161320  

 real    0m7.954s  
 user    0m7.944s  
 sys     0m0.004s  

맞아. 7.95 초 . 지속적으로 C 솔루션보다 0.5 초 빠릅니다 . -fllvm 플래그가 없으면 여전히 8.182 seconds NCG 백엔드도이 경우에도 잘 수행됩니다.

결론 : 하스켈은 굉장합니다.

결과 코드

factorCount number = factorCount' number isquare 1 0 - (fromEnum $ square == fromIntegral isquare)
    where square = sqrt $ fromIntegral number
          isquare = floor square

factorCount' :: Int -> Int -> Int -> Int -> Int
factorCount' number sqrt candidate0 count0 = go candidate0 count0
  where
  go candidate count
    | candidate > sqrt = count
    | number `rem` candidate == 0 = go (candidate + 1) (count + 2)
    | otherwise = go (candidate + 1) count

nextTriangle index triangle
    | factorCount triangle > 1000 = triangle
    | otherwise = nextTriangle (index + 1) (triangle + index + 1)

main = print $ nextTriangle 1 1

편집 : 이제 우리는 그것을 탐구 해 보았습니다.

질문 1 : erlang, python 및 haskell은 임의의 길이의 정수를 사용하기 때문에 속도가 느려지 나 값이 MAXINT보다 작 으면 속도가 떨어 집니까?

Haskell에서 Integer 사용하는 것은 Int 보다 느리지 만, 수행 된 계산에 따라 느리게 계산됩니다. 다행히도 (64 비트 컴퓨터의 경우) Int 이면 충분합니다. 이식성을 위해 Int64 또는 Word64 를 사용하도록 코드를 다시 작성해야합니다 (C는 longlong 유일한 언어는 아닙니다).

질문 2 : 왜 haskell이 그렇게 느린가요? 거기에 브레이크를 해제하거나 내 구현은 컴파일러 플래그가 있나요? (후자는 haskell이 나에게 7 개의 물개가있는 책이기 때문에 꽤 가능할 것입니다.)

질문 3 : 요소를 결정하는 방식을 변경하지 않고 이러한 구현을 최적화하는 방법에 대한 힌트를 제공 할 수 있습니까? 어떤 식 으로든 최적화 : 더 멋지고 빠르며 더 많은 언어로 "고유"합니다.

그것이 내가 위에 답한 것입니다. 대답은

  • 0) -O2 를 통한 최적화 사용
  • 1) 가능한 경우 빠른 (특히 : 박스에서 제외 가능) 유형 사용
  • 2) mod 안함 (자주 잊어 버리는 최적화)
  • 3) 작업자 / 래퍼 변환 (아마도 가장 일반적인 최적화).

질문 4 : 함수 구현이 LCO를 허용하므로 호출 스택에 불필요한 프레임을 추가하지 않아도됩니까?

네, 그게 문제가 아니 었습니다. 좋은 일을하고 기뻤습니다.





debugging erlang trace