[개발일지] 고해상도 타이머, ThreadPool, Stack Allocator 작업완료!
어셈블리어

Lv.1 어셈블리어 (180.♡.243.82)

2025년 12월 6일 PM 11:23 · 수정됨(12. 23. 22:49)

조회 815 공감 0


github.com/kidleon/MarkFramework2

- 게임 엔진의 심장이 될 고해상도 타이머를 추가 하였습니다. 일단은 Windows(MSVC)와 gcc, clang 모두 작동 하게 코딩 작업을 해놨습니다. 

- 원래는 C++11에도 chrono에 고해상도 타이머가 포함되어 있습니다. 하지만 저는 OS 각각의 시스템API를 직접 호출 하는 것을 선호하여 직접 호출해서 사용 하는 방향으로 했습니다.

- 어짜피 C++11도 chrono도 내부에서는 OS API를 호출 하는 방식이기에 별 차이는 없습니다. 다만 OS API를 직접 사용 할 경우 OS가 작성 되었을 때, 유도한 방향으로 개발이 가능 하다는 장점이 있습니다. 

- 리눅스나 BSD, MacOS의 경우 내부 OS API를 기본적으로 posix기반으로 빼놓은 경우가 많아서 posix api로만 작업해도 OS API를 직접 사용하는 것과 별 차이가 없습니다. 

- 아무튼 고해상도 타이머를 이용하여 초 당 몇 프레임으로 업데이트 할 지를 결정 할 수 있게 됩니다. 


============================

- 엔진에서 사용될 Thread Pool 역시 c기반으로 작업 하였습니다.

- Thread Pool의 목적은 요즘 같이 멀티코어 기반의 CPU에서 자원을 보다 효율적으로 사용 하기 위해서 반드시 필요합니다.  

- 게임 클라이언트에서는 주로 '비동기 리소스 IO(로딩) 작업', '파티클 시뮬레이션', '캐릭터 애니메이션', '소프트웨어 오클루전 처리' 등등에 쓰일 수 있습니다. 

- 작업들을 Thread Pool에 왕창 던져주면 구성된 여러 개의 작업 쓰레드가 Queue에서 하나씩 빼 가면서 각자 알아서 비동기로 처리 하게 됩니다.

- Windows의 Thread 생성 API는 CreateThread와 beginthread, beginthreadex를 제공합니다. CreateThread가 기능이 좀더 좋긴한데요.. 단점이 CRT C함수를 사용 할 경우 호환이 안되서 헬게이트가 발생합니다. 데이빗 커틀러가 처음 NT커널을 제작 할때 CRT C함수를 쓰진 않았을 테고 OS 커널 내부에서는 CreateThread만 써도 충분 했겠지만 유저모드에서 개발하는 저희 같은 프로그래머들에겐 CRT함수를 안쓴다는 것은 정말 미친 짓에 가깝죠 --; OS만들 것도 아닌데.. 그래서 윈도우용 ThreadPool은 beginthreadex를 이용해서 만들었습니다.


============================

- 스택 기반의 Memory pool allocator 역시 1차 구현 했습니다.

- 스택 기반의 메모리 테크닉에 대해서는 저는 처음 GPG1(Game Programming Gems 1) 책에서 접했습니다. 

- 아주 오래된 책이지만 일단 저는 1~7권 까지 모두 가지고 있어서 오랜만에 1권 펴서 참고 해가면서 만들었습니다. 

- 언리얼 엔진4, 5 의 경우에도 스택 할당자가 마커 기반으로 구현 되어있습니다. 저 역시 간단하지만 마커 기반으로 제작 하였습니다.

- C, C++은 스택 기반의 언어 인지라 제대로 적용 하면 아주 효율적으로 메모리 할당을 할 수 있습니다.

- 기본 힙 할당자인 malloc이나 new에 비해서는 거의 400~500배 까지 빠른 메모리 할당 속도를 보여줍니다.

- 다만 임시로만 사용 할 수 있지만 언어에서 제공하는 Stack 사용 용량이 아주 적다는 것을 생각하면 Heap메모리를 Stack메모리 처럼 펑펑 쓰면서도 속도 제한이 거의 없다는 점에서 어마어마 한 장점을 제공 합니다.

- 아시는 분은 아시겠지만.. 애초에 컴퓨터는 스택 기반으로 작동됩니다. 컴퓨터 CPU의 구조가 그렇게 생겨 먹었고.. CPU의 API나 다름없는 어셈블리어의 작동 자체가 Stack으로 돌아가게 되어있습니다. Stackless 언어들이 몇 개 있는데요.. 외부에서 프로그래밍 할때나 스택 상관없이 쓰라고 언어 형태를 그렇게 디자인 한것이지.. 실제로 그 언어로 작성한 명령어들은 CPU상에서 기계어로 변환 되어 스택 기반으로 작동 됩니다. 스택 만세..



============================

- BaseLib 디자인 

- BaseLib의 구현 목적은 OS별로 각기 다른 API들을 하나의 API로 엔진에 제공하기 위해서 디자인 되었습니다. 모든 OS API는 C 기반으로 제공하기 때문에 BaseLib역시 순수 C언어로 개발 하고 있습니다.

-리누스 토발즈 형님의 OS를 C언어로 만드는 철학에 아주 격렬히 지지하는 사람으로써, 컴파일 타임 늘어나고 메모리 효율성이 '비교적' 떨어지며 컴파일 되었을 때 난해한 어셈블리어로 디버깅 빡쎄게 만드는 모던C++의 방향성을 극혐 한다..

라는 마인드로 BaseLib를 제작 하고 있습니다.

- 물론 BaseLib제작 할 때 만이고 그 윗 레이어에 넘어가면 C++를 열심히 사용 합니다.  ㅎ 


댓글 (5)

  • 물고기침대21

    물고기침대21 Lv.1

    25.12.06 · 119.♡.9.55

    혹시 고해상도 타이머가 어느정도 정밀도일가요? 궁금해서 여쭤봅니다.
    윈도우같은 범용OS의 경우 정밀도가 10ms 이하로는 어려운걸로 알고 있습니다. 워낙에 많은 프로세스가 동작 중이고, 각종 인터럽트에 대한 지터도 빈번하기 때문에 1ms 단위의 정밀한 시간관리가 필요할 경우는 별도 Tick을 발생해주는 하드웨어가 필요하더군요.
    게임쪽은 잘 몰라서... 보통 어느정도가 되어야 게임엔진으로서 역할을 하는건가요?
  • 비쥬얼씨뿔뿔

    비쥬얼씨뿔뿔 Lv.1 → 물고기침대21 작성자

    25.12.06 · 180.♡.243.82

    윈도우 기준으로 설명 해드리자면 고해상도 타이머의 경우 CPU Clock기반으로 값을 얻어옵니다. 아마 10Mhz정도의 해상도로 카운트 하니까.. 대충 0.1 마이크로초 정도(0.0001ms) 되겠네요. 말씀 하신 10ms는 아득히 높은 저저저 해상도 입니다.

    옛날에 timeGetTime() OS API를 사용해서도 만들긴 했는데.. 이 API가 대충 10ms정도 되었을 겁니다. 그때는 2D 게임 만들때라서 3D 게임 처럼 보간이 필요 없을 때라 별 상관없었는데 3D에서는 사용이 불가능한 API죠..

    QueryPerformanceFrequency와 QueryPerformanceCounter .. 윈도우에서는 이 두 API를 이용해서 타이머를 만듭니다
    방금 AI에게 질문해보니 아주 자세히 설명 해주네요..
    제 코드(위 github)에서는 high_res_timer.h와 high_res_timer.c를 참고 하시면 될거 같아요. 물론 버그는 있을수 있습니다.ㅎ
  • 긴급휴무 Lv.1

    25.12.23 · 211.♡.71.91

    highrestimer_gettime 함수의 리턴값은 비윈도우일경우 [초] 단위가 아닌것 같은데요?
  • 비쥬얼씨뿔뿔

    비쥬얼씨뿔뿔 Lv.1 → 긴급휴무 작성자

    25.12.23 · 121.♡.94.55

    허허 리눅스의 경우 아직 코딩만 하고 테스튼 안하고 있습니다. 버그가 있을수 있어요.. 비 윈도우의 경우 과거 작성했던 경험에 일단 생각나는대로 작성한거라.. 맥의 경우에도 마찬가지 입니다. 현재 MacOS 기기가 없어서요 -_-)
    무엇보다 회사업무 다보고 집에 오면 밤 11시 12시라.. 시간이 많이 없네요 ㅠㅠ
  • 긴급휴무 Lv.1 → 비쥬얼씨뿔뿔

    25.12.23 · 211.♡.71.91

    건강 챙기면서 하세요ㅠㅠ

댓글을 작성하려면 이 필요합니다.