일반적으로 코드를 얼마나 자주 그리고 언제 최적화해야합니까?


13

'정상적인'비즈니스 프로그래밍 최적화 단계는 실제로 필요할 때까지 종종 남아 있습니다. 즉, 실제로 필요할 때까지 최적화하지 않아야합니다.

도널드 크 누스의 말을 기억하십시오. "우리는 작은 효율성을 잊어야하고, 시간의 약 97 %를 말합니다. 조기 최적화는 모든 악의 근원"

노력을 낭비하지 않도록 최적화 할 때가 언제입니까? 방법 수준을 수행해야합니까? 수업 레벨? 모듈 수준?

또한 최적화를 어떻게 측정해야합니까? 진드기? 프레임 속도? 총 시간?

답변:


18

내가 일한 곳에서는 항상 여러 수준의 프로파일 링을 사용합니다. 문제가 발생하면 상황을 파악할 때까지 목록을 조금 더 아래로 이동하십시오.

  • "인간 프로필러"는 일명 게임을합니다 . 가끔 느리거나 "히치"는 느낌이 들까 요? 육포 애니메이션을 눈치 채십니까? (개발자로서, 당신은 어떤 종류의 성능 문제에 더 민감하고 다른 것에 대해서는 망각 할 것입니다. 그에 따라 추가 테스트를 계획하십시오.)
  • 슬라이딩 윈도우 5 초 평균 FPS 인 FPS 디스플레이를 켭니다 . 계산 및 표시 할 오버 헤드가 거의 없습니다.
  • 각 코드 섹션 주위에 간단한 "스톱워치"타이머를 사용하여 프레임의 다른 부분 (예 : vblank, 프리 프레임, 업데이트, 충돌, 렌더링, 포스트 프레임)을 나타내는 일련의 쿼드 (ROYGBIV 색상) 인 프로파일 막대를 켭니다. . 원하는 것을 강조하기 위해 60Hz 대상 프레임을 대표 할 수 있도록 하나의 화면 너비에 해당하는 막대를 설정 했으므로 예산이 50 % 미만 (반 막대 만)인지 50 % 이상 ( 막대가 줄 바꿈되어 1.5 초가됩니다. 빨강 = 렌더, 노랑 = 업데이트 등 일반적으로 대부분의 프레임에서 무엇을 먹는지 쉽게 알 수 있습니다.
  • 각 함수 주위에 코드와 같은 "스톱워치"를 삽입 하는 특수 계측 빌드 를 빌드하십시오 . (이 작업을 수행 할 때 엄청난 성능, dcache 및 icache 적중이 발생할 수 있으므로 확실히 방해가 될 수 있습니다. 그러나 적절한 샘플링 프로파일 러 또는 CPU에 대한 적절한 지원이 부족한 경우 이는 허용 가능한 옵션입니다. 함수 입력 / 종료에 대한 최소 데이터를 기록하고 나중에 콜트 레이스를 다시 작성하는 방법에 대해 설명합니다.) 빌드 할 때 gprof 의 출력 형식을 대부분 모방했습니다 .
  • 무엇보다도 샘플링 프로파일 러를 실행하십시오 . VTune 및 CodeAnalyst는 x86 및 x64에 사용할 수 있으며 여기에 데이터를 제공 할 수있는 다양한 시뮬레이션 또는 에뮬레이션 환경이 있습니다.

(지난 해의 GDC의 그래픽 프로그래머에 대한 재미있는 이야기가 있습니다. 그래픽 프로그래머는 행복하고 무관심하고 성 가시고 화가 난 4 장의 사진을 찍었고 프레임 속도에 따라 내부 빌드의 모서리에 적절한 그림을 표시했습니다. 콘텐츠 제작자는 모든 객체와 환경 에 복잡한 셰이더를 설정하지 않는 방법을 빠르게 배웠습니다 . 프로그래머가 화를 내고 피드백의 힘을 봅니다.)

"프로파일 바"를 계속 그래프로 표시하는 것과 같은 재미있는 작업을 수행 할 수 있으므로 스파이크 패턴 ( "7 프레임마다 프레임이 손실 됨") 등을 볼 수 있습니다.

그래도 귀하의 질문에 직접 대답하기 위해 : 내 경험상, 단일 명령 / icache 또는 dcache 성능을 최적화하기 위해 단일 함수 / 모듈을 다시 작성하고 싶은 유혹을 느끼고 (보통 보람이있는 경우가 많습니다) 실제로 실제로 해야 합니다. 때때로 우리가 특히 눈에 띄지 않는 성능 문제를 겪을 때, 우리가 정기적으로 처리하는 대부분의 성능 문제는 설계귀결 됩니다. 예를 들면 다음과 같습니다.

  • 플레이어를 위해 "공격"상태 애니메이션 프레임을 RAM에 캐시하거나 디스크에서 다시로드해야합니까? 각 적에게는 어떻습니까? 모든 작업을 수행 할 수있는 RAM은 없지만 디스크로드는 비쌉니다! 5 명 또는 6 명의 다른 적들이 한 번에 튀어 나오는 경우 타격을 볼 수 있습니다! (좋아요, 산란은 어떻습니까?)
  • 모든 입자에서 단일 유형의 작업을 수행합니까, 단일 입자에서 모든 작업을 수행합니까? (이것은 icache / dcache 트레이드 오프이며 그 대답이 항상 명확하지는 않습니다.) 모든 파티클을 분리하고 위치를 함께 저장하는 것 (유명한 "배열의 구조체") 대 모든 파티클 데이터를 한 곳에 보관하는 방법 ( " 구조체 배열 ").

대학 수준의 컴퓨터 과학 과정에서 불쾌해질 때까지 들리지만 실제로는 데이터 구조와 알고리즘에 관한 것입니다. 알고리즘 및 데이터 흐름 설계에 시간을 투자하면 일반적으로 비용을 더 많이 벌 수 있습니다. ( 소니 개발자 서비스 직원이 제공 하는 뛰어난 객체 지향 프로그래밍 슬라이드의 함정 을 여기에서 읽어보십시오 .) 최적화와 같은 느낌이 들지 않습니다. 현재 코드를 더 빨리 실행하지 않고 화이트 보드 또는 UML 도구를 사용하거나 많은 프로토 타입을 만드는 데 대부분의 시간이 걸립니다. 그러나 일반적으로 훨씬 가치가 있습니다.

또 다른 유용한 휴리스틱 : 엔진의 "핵심"에 가까우면 최적화 (예 : 행렬 곱셈을 벡터화)하는 데 추가 노력과 실험이 필요합니다. 코어에서 멀어 질수록 프로파일 링 도구 중 하나가 달리 지시하지 않는 한 걱정할 필요가 없습니다.


6
  1. 올바른 데이터 구조와 알고리즘을 미리 사용하십시오.
  2. 핫스팟의 위치를 ​​정확히 파악하고 파악할 때까지 미세 최적화하지 마십시오.
  3. 영리한 것에 대해 걱정하지 마십시오. 컴파일러는 이미 여러분이 생각하고있는 모든 작은 트릭을 수행합니다 ( "오! 4를 곱해야합니다! 왼쪽으로 2를 옮길 것입니다!")
  4. 캐시 누락에주의하십시오.

1
컴파일러에 의존하는 것은 특정 시점에만 현명합니다. 그렇습니다. 생각하지 못하고 조립하지 않고 틈새 최적화를 수행하지만 알고리즘이 수행 해야하는 것에 대한 단서가 없으므로 지능형 최적화를 수행 할 수 없습니다. 또한 어셈블리 또는 내장 함수에 중요한 코드를 구현하여 얼마나 많은 사이클을 이길 수 있는지에 놀랄 것입니다. 컴파일러는 생각만큼 똑똑하지 않으며, 종교적으로 '제한'을 사용하는 등 명시 적으로 어디에서나 말하지 않으면 수행하는 일을 알지 못합니다.
Kaj

1
다시 한 번 핫스팟 만 찾으면 보드 전체에서 꼬인 사이클을 찾을 수 없기 때문에 많은 사이클에서 놓칠 수 있다고 언급해야합니다 (예 : smartpointers .... 효과적으로 전체 프로그램이 핫스팟이기 때문에 핫스팟으로).
Kaj

1
나는 당신의 두 가지 점에 동의하지만, "올바른 데이터 구조와 알고리즘을 사용하십시오"에서 그 중 대부분을 집중시킵니다. 참조 횟수가 매겨진 스마트 포인터를 어디에서나 통과하고 계산을 통해 출혈이 발생하는 경우 잘못된 데이터 구조를 선택했습니다.
munificent

5

그러나 "조기 비관 화"도 기억하십시오. 모든 코드 라인에서 하드 코어를 수행 할 필요는 없지만, 실제로 게임에서 작업하고 있다는 사실에 대한 정당성이 있습니다. 실시간 성능에 영향을 미칩니다.
모든 사람이 핫스팟을 측정하고 최적화하라고 지시하지만,이 기술은 숨겨진 장소에서 손실되는 성능을 보여주지는 않습니다. 예를 들어 코드의 모든 '+'작업이 필요한 시간보다 두 배 오래 걸리는 경우 핫스팟으로 표시되지 않으므로이를 최적화하거나 인식하지 못합니다. 많은 성능이 필요할 수 있습니다. 당신은 그 사이클들 중 몇 개가 감지되지 않고 흘러 내리는 지 놀랄 것입니다. 그러므로 당신이하는 일에주의하십시오.
그 외에도, 나는 거기에 무엇이 있는지, 프레임 당 얼마나 많은 시간이 남아 있는지 알기 위해 정기적으로 프로파일 링하는 경향이 있습니다. 나에게 프레임 당 시간은 프레임 속도 목표를 가진 위치를 직접 알려주기 때문에 가장 논리적입니다. 또한 피크의 위치와 그 원인을 찾아보십시오. 나는 스파이크가있는 높은 프레임 속도보다 안정적인 프레임 속도를 선호합니다.


이것은 나에게 너무 잘못 보인다. 물론, 내 '+'는 호출 될 때마다 두 배 더 오래 걸릴 수 있지만, 이것은 꼭 긴밀한 루프에서만 중요합니다. 타이트한 루프 안에서 단일 '+'를 변경하면 루프 외부에서 '+'를 변경하는 것보다 훨씬 더 많은 작업을 수행 할 수 있습니다. 밀리 초를 절약 할 수있는 10 분의 1 초를 생각하는 이유는 무엇입니까?
Wilduck

1
그렇다면 당신은 세류 손실의 개념을 이해하지 못합니다. 예를 들어 '+'는 타이트한 루프뿐만 아니라 프레임 당 수십만 번 호출됩니다. 보드 전체에서 많은 사이클을 잃을 때마다 몇 번의 사이클이 손실되면 코드베이스 / 실행 경로에 고르게 분산되어 있기 때문에 핫스팟으로 표시되지 않습니다. 따라서 여러분은 10 분의 1 마이크로 초가 아니라 실제로는 10 분의 1 마이크로 초의 수천 배에 이르므로 수 밀리 초가됩니다. 낮은 교수형 과일 (꽉 루프)을 한 후이 방법으로 밀리 초를 두 번 이상 얻었습니다.
Kaj

물이 뚝뚝 떨어지는 수도꼭지와 같습니다. 작은 방울을 저장하는 것에 대해 왜 걱정합니까? - "수도꼭지가 초당 1 방울의 속도로 떨어지는 경우 연간 2700 갤런을 낭비 할 수 있습니다."
Kaj

오, 나는 operator +가 오버로드되었을 때를 의미한다는 것이 확실하지 않다고 생각하므로 코드의 모든 '+'에 영향을 미칩니다. 실제로 코드의 모든 '+'를 최적화하고 싶지는 않습니다. 나쁜 예라고 생각합니다. ... '특히 연산자 오버로드 또는 다른 난독 화 C ++ 구성에 의해 숨겨진 경우 구현이 예상보다 느릴 수있는 곳에서 호출되는 핵심 기능의 예라고 생각했습니다.
Kaj

3

게임이 출시 (최종 또는 베타) 될 준비가되었거나 눈에 띄게 느리면 앱 을 프로파일 링 하기에 가장 좋은 시간 일 것입니다 . 물론 언제든지 프로파일 러를 실행할 수 있습니다. 그러나 그렇습니다. 조기 최적화는 모든 악의 근원입니다. 근거없는 최적화; "최적화"를 시도하기 전에 일부 코드가 느리다는 것을 보여주기 위해 실제 데이터가 필요합니다. 프로파일 러가이를 수행합니다.

프로파일 러에 대해 모른다면 배우십시오! 다음 은 프로파일 러의 유용성을 보여주는 좋은 블로그 게시물 입니다.

대부분의 게임 코드 최적화는 각 프레임에 필요한 CPU주기를 줄입니다. 이를 수행하는 한 가지 방법은 모든 루틴을 작성할 때이를 최적화하고 가능한 빨리 작성하는 것입니다. 그러나 CPU 사이클의 90 %가 코드의 10 %에 소비된다는 일반적인 말이 있습니다. 즉, 모든 병목 현상 루틴에 모든 최적화 작업을 지시하면 모든 것을 균일하게 최적화하는 효과가 10 배가됩니다. 그렇다면 이러한 루틴을 어떻게 식별합니까? 프로파일 링이 쉬워집니다.

그렇지 않으면 작은 게임에 비효율적 인 알고리즘이 있어도 200 FPS에서 실행되는 경우 실제로 최적화해야 할 이유가 있습니까? 대상 머신의 사양을 잘 알고 있어야하며 게임이 해당 머신에서 제대로 실행되는지 확인해야하지만 그 이외의 모든 것은 게임 코딩 또는 연마에 더 나은 시간을 낭비 할 수 있습니다.


낮은 매달린 과일은 실제로 코드의 10 %에 속하며 결국 프로파일 링으로 쉽게 잡히지 만, 프로파일 링을 통해 순수하게 작업하면 많이 호출되지만 약간만있는 루틴을 놓칠 수 있습니다. 각각의 잘못된 코드-프로필에는 표시되지 않지만 통화 당 많은 사이클이 번집니다. 정말 더해집니다.
Kaj

@Kaj, Good 프로파일 러는 나쁜 알고리즘의 수백 건의 개별 실행을 모두 합산하여 총계를 보여줍니다. 다음으로 "하지만 10 개의 잘못된 방법이 있고 모두 주파수의 1/10에서 호출하면 어떻게됩니까?" 이 10 가지 방법에 모든 시간을 소비한다면, 매달린 과일을 모두 잃어 버릴 수 있습니다.
John McDonald

2

프로파일 링을 작성하는 것이 유용하다는 것을 알게되었습니다. 적극적으로 최적화하지 않더라도 주어진 시간에 성능을 제한하는 요소에 대한 아이디어를 얻는 것이 좋습니다. 많은 게임에는 일종의 오버레이 가능한 HUD가 있으며, 이는 게임 루프의 다양한 부분이 각 프레임을 얼마나 오래 걸리는지 보여주는 간단한 그래픽 차트 (일반적으로 컬러 막대)를 표시합니다.

성능 분석 및 최적화를 너무 늦게 늦은 상태로 두는 것은 나쁜 생각입니다. 이미 게임을 빌드했는데 CPU 예산보다 200 % 이상이고 최적화를 통해 찾을 수 없다면 문제가 생길 수 있습니다.

글을 쓸 때 그래픽, 물리 등의 예산이 무엇인지 알아야합니다. 자신의 공연이 무엇인지 모를 경우, 그 공연이 무엇인지, 얼마나 느슨해 질지 모른 채 추측 할 수 없습니다.

따라서 첫날부터 일부 성능 통계를 작성하십시오.

물건을 다룰 때-엔진을 반 리팩토링하지 않도록 너무 늦게 두지 않는 것이 가장 좋습니다. 반면, 내일 알고리즘을 완전히 바꾸거나 실제 게임 데이터를 넣지 않은 경우 모든 사이클을 짜기 위해 물건을 최적화하는 데 너무 신경 쓰지 마십시오.

당신이 따라갈 때 낮은 매달린 과일을 골라 내고 큰 물건을 주기적으로 다루십시오. 그러면 괜찮을 것입니다.


게임 내 프로파일 러에 추가하려면 (내가 동의 한) 게임 내 프로파일 러를 확장하여 여러 막대 (여러 프레임에 대해)를 표시하면 게임 동작을 스파이크와 연관시키고 평균 캡처에 표시되지 않는 병목 현상을 찾는 데 도움이 될 수 있습니다 프로파일 러와 함께.
Kaj

2

Knuth의 맥락에서 Knuth의 인용문을 살펴보면 프로파일 러와 같은 도구를 사용하여 최적화 해야한다고 설명 합니다 .

기본 아키텍처가 완성 된 후에는 응용 프로그램을 지속적으로 프로파일 링하고 메모리 프로파일 링해야합니다.

프로파일 링은 속도를 높이는 데 도움이 될뿐만 아니라 버그를 찾는 데 도움이됩니다. 프로그램이 갑자기 속도를 크게 바꾸면 대개 버그 때문입니다. 프로파일 링하지 않으면 눈에 띄지 않을 수 있습니다.

최적화의 요령은 의도적으로 수행하는 것입니다. 마지막 순간까지 기다리지 마십시오. 프로그램의 디자인이 실제로 내부 루프 트릭을 사용하지 않고도 필요한 성능을 제공하는지 확인하십시오.


1

내 프로젝트의 경우 일반적으로 기본 엔진에 매우 필요한 최적화를 적용합니다. 예를 들어 나는 항상 SSE2와 3DNow! 이것은 내 부동 소수점 수학이 내가 원하는 곳에 큐에 있는지 확인합니다. 또 다른 좋은 방법은 코드를 다시 작성하지 않고 최적화 할 때 습관을 없애는 것입니다. 대부분의 경우,이 작은 관행은 코딩하는 것과 마찬가지로 시간이 많이 걸립니다. 기능을 코딩하기 전에 가장 효율적인 방법을 연구하십시오.

결론적으로, HARDER는 코드를 이미 빨아 들인 후에 더 효율적으로 만드는 HARDER입니다.


0

가장 쉬운 방법은 상식을 사용하는 것이라고 말하고 싶습니다. 무언가가 느리게 실행되는 경우 살펴보십시오. 병목 현상인지 확인하십시오.
프로파일 러를 사용하여 속도 함수가 수행하는 속도와 호출 빈도를 살펴보십시오.
필요하지 않은 것을 최적화하기 위해 시간을 최적화하거나 시간을 소비하는 것은 절대로 없습니다.


0

코드가 느리게 실행되면 프로파일 러를 실행하고 정확히 무엇이 더 느리게 실행되는지 확인하십시오. 또는 성능 문제를 발견 하기 전에 사전 예방 적이며 이미 프로파일 러를 실행 하고있을 수 있습니다.

프레임 속도가 게임이 시작되는 지점으로 떨어질 때 최적화하는 것이 좋습니다. 가장 많은 범인은 CPU를 너무 많이 사용하는 것입니다 (100 %).


GPU가 CPU만큼이나 좋다고 말하고 싶습니다. 실제로 얼마나 밀접하게 연결되어 있는지에 따라 프레임의 절반에 CPU를 많이 묶고 나머지 절반을 GPU에 완전히 묶을 수 있습니다. 벙어리 프로파일 링은 100 % 미만의 활용도를 보여줄 수 있습니다. 확인 당신의 프로파일 링은 잘은이 보여 정도로 그레인한다 (그러나 너무 잘 방해가하는대로 그레인하지!)
JasonD

0

필요한 횟수만큼 코드를 최적화해야합니다.

내가 과거에 한 일은 프로파일 링을 켜고 (항상 화면의 프레임 속도 카운터에서) 게임을 계속 실행하는 것입니다. 게임이 느려지는 경우 (예를 들어 최소 사양 머신의 대상 프레임 속도 미만) 프로파일 러를 켜고 핫스팟이 표시되는지 확인하십시오.

때로는 코드가 아닙니다. 내가 과거에 겪었던 많은 문제는 GPU 지향적이었습니다 (허여 된 것은 iPhone에 있습니다). 채우기 속도 문제, 너무 많은 그리기 호출, 충분한 지오메트리 배치, 비효율적 인 셰이더 ...

어려운 문제 (예 : 길 찾기, 물리)에 대한 비효율적 인 알고리즘 외에, 코드 자체가 범인이었던 문제는 거의 발생하지 않습니다. 그리고 이러한 어려운 문제는 알고리즘을 올바르게 작성하고 더 작은 것을 걱정하지 않기 위해 많은 노력을 기울여야합니다.


0

나를 위해 잘 준비된 데이터 모델을 따르는 것이 가장 좋습니다. 그리고 주요 단계 전의 최적화. 큰 새로운 것을 구현하기 전에 의미합니다. 최적화에 대한 다른 이유는 리소스에 대한 제어를 잃어 버릴 때, 앱에 많은 CPU로드 / GPU로드 또는 메모리가 필요하며 이유가 무엇인지 모르겠습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.