하나를 위해 ECS 를 지불할 이유는 없다
Esc

    하나를 위해 ECS 를 지불할 이유는 없다

    –UnityDOTS최적화

    이 프로젝트는 전부 ECS 가 아닙니다. 경계가 이렇습니다.

    어디 무엇
    GameObject 플레이어 콤보, 타격감, 입력 버퍼, 카메라
    UI · VFX 킬 카운터, 사망 연출, 화면 흔들림
    ECS 적 1만 스폰, 이동, 이웃 회피, 타겟팅
    데미지, 사망, 넉백, 경직, 렌더

    플레이어는 왜 ECS 가 아닌가

    성능 때문이 아닙니다. 하나짜리를 ECS 로 옮겨도 얻는 게 없습니다.

    이터레이션 비용 때문입니다. 애니메이션 캔슬 타이밍, 입력 버퍼 길이, 타격 프레임, 카메라 추적 감도. 이런 것은 숫자를 바꾸고 플레이해 보고 다시 바꾸기를 수십 번 합니다.

    ECS 에서는 그 사이클이 비쌉니다. 값 하나를 인스펙터에 노출하려면 authoring 과 baker 를 거쳐야 하고, 로그 하나 찍으려면 잡을 Run 으로 바꿔야 하고, 그러면 Burst 도 병렬도 꺼져서 성능이 다른 코드가 됩니다.

    객체 하나를 위해 그 오버헤드를 낼 이유가 없습니다.

    무엇을 옮길지 고르는 기준

    네 가지를 봤습니다.

    질문 ECS 로 GameObject 로
    같은 일을 하는 것이 몇 개인가 수천 개 이상 한둘
    얼마나 자주 고칠 것인가 규칙이 굳었다 계속 만진다
    매 프레임 전부 도는가 그렇다 이벤트로 충분하다
    데이터가 독립적인가 서로 안 본다 여기저기 참조한다

    넷 다 같은 방향이면 쉽습니다. 갈리면 개수가 이깁니다. 1만 개짜리는 이터레이션이 불편해도 ECS 로 가야 하고, 하나짜리는 반대입니다.

    전투를 얹어도 기울기는 0이었다

    적 1만에 전투 시스템 다섯 개를 얹으면 무너지는지 재 봤습니다. 같은 세션 안에서 시스템을 런타임에 켜고 끄며 측정했습니다.

    적 수 전투 전부 끔 적 공격만 끔 전부 켬
    1,000 8.08 8.00 8.53
    10,000 7.76 8.16 9.37
    기울기 (1천에서 1만) -0.32 +0.16 +0.84

    세 조건 모두 평평합니다. 적이 열 배가 돼도 프레임타임이 안 늘어납니다. 1만 마리 거리 판정과 데미지 적용을 통째로 얹어도 그렇습니다.

    이 표에서 말할 수 없는 것

    같은 세션 안의 차이(전부 켬 빼기 전부 끔)는 1ms 안팎입니다. 그런데 그 숫자는 못 믿습니다.

    근거는 전투 전부 끔 의 기울기가 -0.32, 즉 음수 라는 점입니다. 적이 열 배인데 빨라졌다는 것은 물리적으로 불가능하니, 측정 노이즈가 최소 ±0.5ms 라는 뜻입니다. 1ms 신호가 그 안에 들어앉아 있습니다.

    신호가 노이즈보다 작으면 “작다” 는 것 말고는 할 수 있는 말이 없습니다.

    그리고 다른 세션과 비교하면 안 된다

    하마터면 이렇게 쓸 뻔했습니다.

    전투 있음 9.37 - 이전 측정의 6.26 = 전투 비용 3ms

    틀렸습니다. 전투를 전부 끈 조건도 7.76ms 가 나왔습니다. 이전 세션의 6.26이 재현되지 않습니다. 차이의 절반 이상이 코드와 무관한 세션 간 베이스라인 드리프트 였습니다. 에디터 상태, 도메인 리로드 누적 같은 것들입니다.

    유효한 비교는 같은 세션 안의 A/B 와 기울기 뿐입니다.

    안 쓰는 것도 설계다

    적이 플레이어를 때리는 판정에는 공간 해시를 안 썼습니다.

    쓰고 싶어집니다. 이미 만들어 뒀고, 이웃 탐색에 잘 듣는 것도 확인했으니까요. 그런데 필요가 없습니다.

    그리드가 푼 문제는 1만 × 1만 = 1억 이었습니다. 적이 플레이어를 때리는 것은 1만 × 1 입니다.

    적 1만이 각자 플레이어 하나와 거리를 재면 끝입니다. Burst 가 1억 번을 19ms 에 처리했으니 1만 번은 그 만분의 일입니다. 여기에 그리드를 끼우면 얻는 것 없이 JobHandle 얽힘만 늘어납니다.

    비쌀 이유가 없을 때 안 쓰는 것도 설계입니다.

    이 프로젝트에서 남은 것

    정직하게 적어 둡니다. 아직 못 한 것이 셋 있습니다.

    • 전수 검사 대비 시스템 마커 격리. 기준선 브랜치가 아트 에셋 이전의 옛 스냅샷이라 라이브 에디터를 그쪽으로 전환하면 대용량 리임포트가 일어납니다. git worktree 로 별도 인스턴스를 띄워서 같은 하니스를 돌려야 합니다
    • GPU 프레임 타임 실측. 에디터에서는 0으로 나오므로 빌드에서 따로 잡아야 합니다
    • 반경 스윕. 셀 스캔이 (2R+1)² 로 늘어나는데, 반경 25면 2,601칸이고 50이면 10,201칸입니다. 그런데 결과는 똑같이 1만 킬입니다. 그리드가 손해로 뒤집히는 지점이 어딘가에 있습니다

    정리

    • 데이터를 붙여 놓으면 캐시가 맞고, 그 결과로 SIMD 와 병렬이 열린다
    • 셀 크기를 질의 반경에 맞추면 검사 수가 상수가 되고, 기울기가 0이 된다
    • 배수는 잰 지점에서만 유효하다. 기울기가 구조에 대한 답이다
    • 최적화에는 손익분기점이 있다. 1,000 마리에서는 그리드가 손해였다
    • 브릿지는 방향과 건수가 모양을 정한다. 표면적은 좁을수록 좋다
    • 값이냐 참조냐가 반복해서 갈린다. 대상이 사라질 수 있으면 값을 복사한다
    • 구조 변경은 잡에서 못 한다. 그래서 비트 토글이 이긴다
    • 지표 설계와 표본 수가 결론을 만든다. 뺄셈으로 만든 지표는 노이즈가 더해진다
    • 격리하지 않은 관측은 증명이 아니다. 경쟁하는 시스템을 끄면 오차가 0이 된다
    • 개수가 적으면 ECS 를 지불할 이유가 없다