Geant4 가이드

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

Multi-threading 에 관하여

Multi-threading은 프로그램을 하나 돌렸을 때 CPU 안에서 일을 분산하여 돌리는 작업을 의미한다. 여기서 프로그램 하나를 돌리는 것은 프로세스(process) 그리고 분산된 작업 하나의 단위를 스레드(thread) 라고 한다. 즉 프로세스는 하나인데 스레드를 여러개 만들어서 분산 작업을 한다.

일반적인 컴퓨터는 CPU 하나를 장착하고 있다. 그렇기 때문에 사용자가 하나의 CPU 성능을 최대한 이끌어내서 일을 하려고 할 때 multi-threading을 고려할 수 있다. 하지만 사용자가 여러개의 CPU를 가지고 있는 서버를 사용할 수 있다면 Multi-threading 보다는 여러 CPU에 일을 분산하는 방법을 강력하게 추천한다. 과학 내지 기타 분야에서 분석 목적으로 만들어진 서버에는 이러한 작업을 도와주는 (예를 들어서 HTCondor 와 같은) 프로그램이 반드시 설치되어 있다.

작동 원리

다음과 같은 조건을 들어보자.

  • 10개의 스레드 사용
  • 10000개의 이벤트 수행
  • (Run Action, Primary Generator Action, Stepping Action) 3개의 클래스 사용.
    간단하게 Action Class 묶음 이라고 하자.

위 조건에서 시뮬레이션을 초기화 할 경우 프로세스는 10개의 스레드를 생성하고 각 10개의 스레드는 개별적으로 Action Class 묶음 클래스를 생성한다. 즉, 10개의 Action Class 묶음이 만들어진다. 또 10개의 스레드를 관리하는 마스터 스레드를 추가로 생성하는데 마스터 스레드는 (사용자 설정이 가능하지만) 보통 Run Action 클래스만 생성하도록 한다. 굳이 Run Action 클래스를 생성하는 이유는 시뮬레이션이 시작하기 전, 혹은 모두 끝났을 때 종합적인 기능을 넣는 경우가 많기 때문이다. 런을 실행하게 되면 마스터는 스레드는 하위 스레드가 준비되는 대로 시뮬레이션을 수행하라는 명령을 내린다. 명령의 순서는 정할 수 없으며 하나의 스레드가 연속적으로 배정받을 수도 있다. 따라서 순서 의존적인 시뮬레이션을 할 수 없다. 이벤트를 수행 명령은 모든 스레드를 합쳐서 10000번이 된다.

주의 사항

Multi-threading을 고려한 시뮬레이션을 만들 때 가장 크게 고려해야 하는 것은 스레드 안정성(thread-safe)이다. 스레드가 완벽하게 독립할 수 있다면 가장 좋고 독립할 수 없다면 그 부분에 대한 안정성을 신경써야 한다. 스레드 안정성이란 모든 스레드가 공유된 기능을 사용하더라도 안정적으로 작동하는 것을 의미한다. 특히 Geant4는 입력과 출력이 이와 밀접한 관련이 있다.

입력의 경우 Primary Generator Action 에 쓰이는 이벤트 입력 파일이 있다면 매우 까다롭다. 이벤트 파일을 읽고 트랙 정보를 전달해 주는 클래스를 만들어야 하지만 그 클래스의 객체는 프로세스 안에서 유일해야하고 동시에 모든 스레드에서 접근해야 하기 때문에 스레드 안정성을 고려해야 한다. 또한 모든 스레드가 이 객체에 쉽게 접근할 수 있어야 한다. 이 부분은 위에서 언급한 마스터 스레드의 Run Action 클래스와 G4Mutex로 해결할 수 있다. 추후에 토픽에서 다루겠다.

출력을 위해서 스레드가 동시에 하나의 파일, 또는 하나의 데이터 구조에 접근하는 것은 매우 위험하다. 따라서 각 스레드에서 출력파일을 다른 이름으로 생성하고 각 파일에 데이터를 따로 쓰도록 하는 것이 바람직 하다. 다행이도 이 모든 기능이 구현된 툴이 바로 G4Tool 이다.

알아두자

  • Geant4는 multi-threading 기능을 사용할 때 기본 설정으로 2개의 스레드를 사용하도록 되어 있다. 사용자는 스레드 개수를 G4MTRunManager::SetNumberOfThreads(G4int n) 함수로 설정할 수 있다.
  • Geant4의 모든 example은 multi-thread를 염두해 둔 예제들이다.
  • Geant4 설치를 DGEANT4_BUILD_MULTITHREADED 옵션을 추가하여 할 경우, 즉 multi-threading을 지원할 경우 매크로 상수 G4MULTITHREADED 가 정의 된다. 이를 이용하여 multi-threading 지원 여부에 의존적인 프로그래밍을 할 수 있다. 실제로 Geant4의 example은 이를 적극 활용한다.
  • Sensitive Detector를 사용하는 경우 Detector Construction의 ConstructSDandField() 함수 안에서 선언하고 SetSensitiveDetector("이름",포인터) 함수를 사용하여 등록해야 한다.
  • G4Allocator를 사용하는 경우 스레드 로컬이어야 하고 반드시 스레드 안에서 메모리를 할당해야 한다.

유용한 함수들

Multi-threading을 사용할 때 유용한 함수들을 적어둔다. (G4Threading는 네임스페이스다)

  • G4Threading::G4GetNumberOfCores() : 사용할 수 있는 코어의 개수를 출력한다.
  • G4Threading::G4GetThreadedId() : 스레드 번호를 출력한다.
  • G4MTRunManager::GetMasterRunManager() : 마스터 런 메니저를 출력한다.
  • G4MTRunManager::SetNumberOfThreads(G4int n) : 사용할 스레드의 개수를 설정한다.
  • Action 클래스의 IsMaster() : 마스터 스레드의 Action 클래스인지 여부를 출력한다.

몇개의 스레드를 생성할 수 있을까?

최대로 생성할 수 있는 스레드 수는 컴퓨터에 따라서 다르다. 맥의 경우 터미널에서 다음 명령어로 알 수 있다.

 sysctl hw.logicalcpu 

얼마나 빠를까?

지금부터 만들어볼 프로그램으로 간단한 테스트를 해 본 결과 스레드 개수에 따른 프로그램의 경과 시간은 아래와 같다. 스레드의 개수와 정비례하지는 않는 것을 알 수 있다.

  • 스레드 1개 : 4760 ms
  • 스레드 2개 : 2502 ms (약 1.9 배 빠름)
  • 스레드 4개 : 2285 ms (약 2.1 배 빠름)

 

댓글

댓글 본문
작성자
비밀번호
  1. ejungwoo
    말씀하신 역할을 하는 것이 맞습니다. 저는 HTCondor를 단순 사용만 해본 입장이라서 크게 도와드릴 수는 없을 것 같습니다. 하지만 인터넷에 이에 대한 글이 많은 것 같으니 참고하시면 좋을 것 같습니다.
    대화보기
    • 그럼 HT Condor는 자동으로 job을 분배해주는 scheduler 같은 역할을 하는것인가요?
      혹시 이와관련된 글도 올려주실 수 있나요?
      대화보기
      • ejungwoo
        geant4는 MPI를 사용해서 얻을 수 있는 이점은 없다고 생각합니다.
        cpu가 여러개라면 cpu 개수 만큼 geant4 프로그램을 돌리면 될 것 같습니다.
        저희 분야에서는 여러 cpu에 일을 분배하는 프로그램으로 HTCondor를 사용하고 있습니다.
        대화보기
        • 안녕하세요 Multithread 는 1개의 cpu의 효율을 최대한 높이는 방법입니다.

          이 방법 외에 Multi process 즉 여러개의 Node들을 병렬화 하여 사용하는

          방법도 특별한 설정이 필요한지 궁금합니다

          open MPI와 같은 tool을 설치하면 자동으로 MP를 사용할 수 있는건지 아니면 Multi thread처럼 추가적인 설정을 더해야하는 건지 여쭤봅니다. 혹시 tool을 설치해야한다면 가장 적합한 MPI는 어떤건지도 궁금하네요항상 좋은 자료 올려주셔서 감사합니다.
        버전 관리
        ejungwoo
        현재 버전
        선택 버전
        graphittie 자세히 보기