2016-12-19 9 views
0

불꽃을 사용하지 마십시오.하지만 정품입니다. 필자는 매우 오랜 시간 동안 실행되는 멀티 스레드 파이썬 응용 프로그램을 작성하는데, 일반적으로 10 개의 프로세스가 2-3 시간 동안 실행됩니다. 이 기계는 천천히 계산되지 않습니다.메모리, .so 파일 이름 및 16 진수 오프셋을 어떻게 처리합니까?

외부 도구로 인해 응용 프로그램이 약 85-90 % 지연되는 경우가 종종 있습니다.

이 테스트를 더 작은 조각으로 나눠서 성공적으로 실행할 수 있지만 장시간 실행되는 프로그램이 중단됩니다.

예를 들어 100,000,000 개의 항목이있는 목록의 일부 데이터를 분석해야한다고 가정 해 봅시다.

20,000,000 개의 목록으로 나누면 모든 작은 부분이 완료되어 실행됩니다.

100,000,000 개의 프로젝트를 수행하려고하면 끝까지 중단됩니다. 내가 변경할 수없는 몇 가지 외부 도구를 사용하여 지금 진행중인 작업을 확인하려고합니다.

I 설정 Dtrace와 그것이 응답 나는 아래의 코드 샘플과 같은 출력을 얻을 때 내 프로그램의 오른쪽

sudo dtrace -n 'syscall:::entry/execname == "python2.7"/{ @[ustack()] = count() }' 

를 실행합니다.

  libc.so.7`__sys_recvfrom+0xa 
      _socket.so`0x804086ecd 
      _socket.so`0x8040854ac 
      libpython2.7.so.1`PyEval_EvalFrameEx+0x52d7 
      libpython2.7.so.1`PyEval_EvalCodeEx+0x665 
      libpython2.7.so.1`0x800b3317d 
      libpython2.7.so.1`PyEval_EvalFrameEx+0x4e2f 
      libpython2.7.so.1`0x800b33250 
      libpython2.7.so.1`PyEval_EvalFrameEx+0x4e2f 
      libpython2.7.so.1`PyEval_EvalCodeEx+0x665 
      libpython2.7.so.1`0x800abb5a1 
      libpython2.7.so.1`PyObject_Call+0x64 
      libpython2.7.so.1`0x800aa3855 
      libpython2.7.so.1`PyObject_Call+0x64 
      libpython2.7.so.1`PyEval_EvalFrameEx+0x4de2 
      libpython2.7.so.1`PyEval_EvalCodeEx+0x665 
      libpython2.7.so.1`0x800abb5a1 
      libpython2.7.so.1`PyObject_Call+0x64 
      libpython2.7.so.1`0x800aa3855 
      libpython2.7.so.1`PyObject_Call+0x64 

코드가 반복해서 반복됩니다. Dtrace 파이썬 프로브를 조사해 보았습니다. 그러나 화요일부터 양측이 파손 된 것으로 보입니다. 그래서 이것이 내가 얻을 수있는 가장 가까운 것일 수 있습니다.

내 질문에, 내가 libpython2.7.so.1가 진수의 기능 pyObject_Call을 보유하고있는 공유 라이브러리가 0x64

의 오프셋되는 퍼지 생각을 가지고는 그 거 맞아?

어떻게 해독 할 수 있습니까? 나는 이것을 답변 이라든가 가이드로 쓸 수 있도록 무엇을 부를지 모릅니다.

답변

2

아마도 Showing the stack trace from a running Python application으로 시작해야합니다.

귀하의 구체적 질문은 DTrace의 ustack() 조치 및 의 해석에 관한 것이므로이 회신은 귀하가 필요로하는 것 이상일 수 있습니다. DTrace의 디자인 원칙 중 하나 인 중 하나가 시스템의 정확한 상태를 보여주기 때문입니다. 따라서 프로그램의 Python 측면에 관심이 있더라도 DTrace는 기본 구현을 보여줍니다.

출력은 실행의 특정 지점에서 스레드의 상태를 설명하는 의 방식 인 스택입니다. 당신은 코드

void c(void) { pause(); } 
void b(void) { c(); } 
void a(void) { b(); } 

했다 당신이 실행하는 동안 스택을 요청하는 경우 예를 들어, 당신은 발견 할 것이다 사용간에 도구

pause() 
c() 
b() 
a() 

같은 것을 볼 수 있습니다 다음) (일시 정지 이내 현재 명령 및 그것의 둘러싸는 기능 "반환 주소"를 찾아 내기 전에, ie그 함수가 결국 리턴 할 포인트는 입니다. 이 프로 시저를 반복하면 스택이 생성됩니다. 따라서 스택은 일련의 리턴 주소로 위에서 아래로 으로 읽어야하지만 일반적으로 은 일련의 호출자로 읽습니다. 프로그램의 해당 명령어가 어셈블되는 방식에서 의 미묘한 차이는이 두 번째 해석 이 때때로 오도 된 수 있음을 의미합니다.

위의 예제를 확장하려면 a(), b() 및 c()가 모두 동일한 라이브러리에 존재하고 다른 라이브러리에 동일한 이름을 가진 함수가있을 수 있습니다. 따라서 이 속한 객체를 각 함수에 대해 표시하는 것이 유용한 입니다.) (일시 정지를 호출 한 함수 C()를 libfoo 에서 : 따라서 위의 스택이 개발자가 특정 상태에서 프로그램이 결국 어떻게 식별 할 수 있도록으로 어떤 길을 간다

libc.so`pause() 
libfoo.so`c() 
libfoo.so`b() 
libfoo.so`a() 

될 수 있습니다. 그러나, 할 더가있다 : C() 이

void c() { 
    pause(); 
    pause(); 
} 

처럼 보였다 경우 다음 프로그램이 기다리고있는 (일시 정지) 호출에?

함수 a(), b() 및 c()는 일반적으로 메모리의 연속 영역을 차지하는 명령어 시퀀스입니다. 함수 중 하나를 호출하면 이상의 정보가 포함되어 작업이 완료되면 반환 할 위치 (예 : 주소)를 기록한 다음 함수 시작 부분에 에 해당하는 메모리 주소로 점프합니다. 함수의 시작 주소 및 크기는 객체에 포함 된 "기호 테이블"에 기록 된 입니다. 이 테이블을 읽으면 디버거가 반환 주소와 같은 주어진 위치를 포함하는 함수를 찾을 수 있음을 알면 입니다. 따라서 특정 지점 내에서 함수는 시작 부분부터 일반적으로 16 진수로 표시된 오프셋으로 설명 될 수 있습니다. 따라서 스택의 더 나은 버전 이상, C 내에서 지침을 표시하는 libfoo.so 에 "디스어셈블러"을 사용할 수있는 개발자()이 시점에서

libc.so`pause()+0x12 
libfoo.so`c()+0x42 
libfoo.so`b()+0x12 
libfoo.so`a()+0x12 

이 될 수 있습니다; c()의 소스 코드와 비교하면 pause()에 대한 호출이 만들어진 특정 줄이 밝혀 질 수 있습니다.

스택에 대한이 설명을 결론지기 전에 을 한 번 더 살펴볼 필요가 있습니다. libfoo와 같은 라이브러리에 충분한 "디버그 데이터"가 있으면 더 나은 디버거가 추가 마일을 이동하여 각 "프레임의 16 진수 오프셋 대신 소스 코드 파일 이름과 줄 번호를 표시 할 수 있습니다 "스택에서 입니다.

질문에 스택으로 돌아 가려는 경우 libpython (2.7.so.1)은 함수가 인 Python 스크립트를 실행하는 라이브러리 인 라이브러리입니다.파이썬 스크립트의 기능 그래서 내 생각은 단편

libpython2.7.so.1`0x800b33250 
libpython2.7.so.1`PyEval_EvalFrameEx+0x4e2f 
libpython2.7.so.1`PyEval_EvalCodeEx+0x665 

이 PyEval_EvalFrameEx()를 작성 (즉, 뭔가 파이썬 함수를 호출하는 자체 libpython 내에서 기능이 있음을 의미 이며, 즉시 실행 가능한 명령어로 변환 된다 in Python) 주소 0x800b33250 근처의 메모리에 상주합니다. A 간단한 디버거는이 주소가 libpython에 속해 있지만 이 라이브러리의 기호 테이블에서 해당 항목을 찾지 못한다는 것을 알 수 있습니다. 을 선택하지 않으면 단순히 "원시"주소 만 인쇄됩니다.

그래서, 당신은 스택의 파이썬 구성 요소의 함수의 이름의 징후가 없다, 그래서 불행하게도, 일을 입니다하지만 볼 파이썬 스크립트 볼 필요가있다.

진행 방법은 몇 가지가 있습니다. 첫 번째는 과 함께 libpython의 버전을 찾습니다 (있는 경우). 이 은 구현 외에도 Python 프로그램 자체의 상태를 DTrace에서 볼 수있게 해주는 몇 가지 추가 기능입니다. 결과적으로 각 파이썬 프레임은 이되어 파이썬 소스 코드의 해당 지점으로 주석 처리됩니다.

Solaris의 경우 pstack (1)을 사용하십시오. 파이썬에 대한 기본 지원은 입니다.

마지막으로 특정 Python 디버거를 사용해보십시오.

프로그램 "python2.7"이 시스템 호출을 할 때마다 dtrace 호출이 보았을 때 모든 스택을 보았을 때 이 표시된다는 점도 지적 할 가치가 있습니다. 귀하의 설명에서 아마도 이것은 당신이 원하는 것이 아닙니다. 중단의 동작을 이해하려는 경우 정지시에 프로세스의 단일 스냅 샷으로 시작하려고합니다.

+0

이것은 훌륭한 대답이었으며 문제를 완전히 디버그하는 데 사용할 수있었습니다. 이전에 파이썬 디버거를 사용해 보았지만 스크립트를 실행하지 않았을 가능성이 높습니다. 일부 멀티 프로세싱이 있었기 때문에 스크립트를 실행하지 않았을 것입니다. 프로세스, DTrace를 살펴 보았지만 파이썬 도우미는 모두 구식 인 것처럼 보였습니다. 위의 대답으로 나는 그것을 모두 소트 할 수 있었다. – user1610950