조기에 최적화하고 있습니까?


9

저는 현재 C ++에서 구성 요소 기반 아키텍처의 디자인 단계에 있습니다.

현재 디자인에는 다음과 같은 기능 사용이 포함됩니다.

  • std::vectorstd::shared_ptr구성 요소를 보유
  • std::dynamic_pointer_cast
  • std::unordered_map<std::string,[yada]>

컴포넌트는 그래픽, 물리, AI, 오디오 등과 같은 게임과 같은 소프트웨어에 필요한 다양한 아이템의 데이터와 로직을 나타냅니다.

캐시 미스가 성능에 어려움을 겪는 곳을 모두 읽었으므로 몇 가지 테스트를 실행하여 실제로 응용 프로그램 속도가 느려질 수 있다고 생각했습니다.

위에서 언급 한 언어 기능을 테스트 할 수는 없었지만 많은 곳에서 비용이 많이 들고 가능한 경우 피해야한다고합니다.

아키텍처의 디자인 단계에 있기 때문에 이것이 디자인의 핵심에 포함될 것이므로, 성능이 떨어지면 나중에 변경하기가 매우 어려워 지금 피할 수있는 방법을 찾아야합니다. 문제?

아니면 방금 조기 최적화를하고 있습니까?


3
성능 문제에 관계없이 나중에 변경하기가 매우 어려운 디자인에 정착하기를 꺼려했습니다. 가능하다면 피하십시오. 유연하고 빠른 디자인이 많이 있습니다.
candied_orange

1
세부 사항을 알지 못하더라도이 질문에 대한 대답은 거의 항상 "YES !!"입니다.
Mawg는 모니카

2
@Mawg "... 그렇지만 중요한 3 %의 기회를 넘겨서는 안됩니다." 이것이 디자인의 핵심이므로이 3 %로 작업하고 있는지 어떻게 알 수 있습니까?
Vaillancourt

1
탁월한 점, Alexandre (+1), 그렇습니다. 나는 인용의 마지막 절반이 거의 언급되지 않았다는 것을 알고 있습니다 :-) 그러나 그 전에 내 의견으로 돌아가려면 , the answer to this question is almost always a resounding "YES !!". 나는 여전히 먼저 작동하고 나중에 최적화하는 것이 낫다고 생각하지만 YMMV는 모든 사람이 자신의 의견을 가지고 있으며 모든 의견이 유효하며 OP만이 자신의 주관적 질문에 대답 할 수 있습니다.
Mawg는 모니카

1
@AlexandreVaillancourt Knuth의 논문을 계속 읽으십시오 (PDF, 인용문은 268 페이지, 8 페이지, PDF 리더에서 오른쪽 페이지에서 나옵니다). "... 그는 중요한 코드를주의 깊게 살펴 보는 것이 현명 할 것입니다. 그러나 그 코드가 식별 된 후에 만 가능 합니다. 측정 도구를 사용해온 프로그래머들은 직관적 인 추측이 실패한 것입니다. " (강조 자신)
8bittree

답변:


26

제목 이외의 것을 읽지 않고 : 예.

본문을 읽은 후 : 예. 맵과 공유 포인터 등이 캐시 방식으로 잘 수행되지 않는 것이 사실 이지만 , 내가 이해하는 한, 사용하려는 것은 병목 현상이 아니며 병에 걸리지 않을 것입니다. 데이터 구조에 관계없이 캐시를 효율적으로 사용하십시오.

가장 어리석은 실수를 피하면서 소프트웨어를 작성한 다음 테스트하고 병목 현상을 찾은 다음 최적화하십시오!

Fwiw : https://xkcd.com/1691/


3
동의했다. 얼마나 빨리 작동하지 않든 상관없이 먼저 작동시켜야합니다. 또한 가장 효과적인 최적화에는 코드 조정이 필요하지 않으며보다 효율적이고 다른 알고리즘을 찾는 것이 필요합니다.
Todd Knarr

10
최적화가 항상 조기이기 때문에 첫 번째 줄이 사실 이 아니라는 것을 알고 싶습니다. 최적화가 필요하다는 것을 알면 최적화가 조기에 이루어지지 않기 때문에이 경우 묻지 않을 것입니다. 따라서 첫 번째 줄은 최적화가 너무 이른 지 아닌지에 대한 질문을한다는 사실은 최적화가 필요한지 확실하지 않다는 것을 의미하기 때문에 정의에 의해 조기에 이루어지기 때문입니다. 휴
Jörg W Mittag

@ JörgWMittag : 동의했습니다.
steffen

3

나는 C ++에 익숙하지 않지만 일반적으로 다릅니다.

격리 알고리즘을 조기에 최적화하지 않아도 쉽게 최적화 할 수 있습니다.

그러나 원하는 핵심 성능 지표를 달성하려면 애플리케이션의 전체 디자인을 가져와야합니다.

예를 들어, 초당 수백만 건의 요청을 처리하도록 응용 프로그램을 설계해야하는 경우 응용 프로그램을 작동시키지 않고 디자인 할 때 응용 프로그램의 확장 성을 고려해야합니다.


3

물어봐야한다면 그래요 당신이 전에 조기 최적화 수단 최적화는 확실히 상당한 성능에 문제가있는 것입니다.


1

ECS? 실제로 인터페이스 디자인에 영향을 줄 수 있기 때문에 디자인의 데이터 지향적 인 측면에 많은 생각을하고 다른 담당자를 벤치마킹하는 것이 조기에 그렇지 않을 수 있다고 제안합니다 . 게임. 또한 ECS는 많은 작업과 선결제를 요구하며, 그 시점을 활용하여 디자인 수준의 성능 슬픔을 줄이려고하지 않는지 확인하기 위해 그 시간을 활용할 가치가 있다고 생각합니다. 전체 괴물 엔진. 이 부분은 나에게 눈부신 :

unordered_map<string,[yada]>

작은 문자열 최적화를 사용하더라도 다른 가변 크기 컨테이너 (unorder_maps) 내에 가변 크기 컨테이너 (문자열)가 있습니다. 테이블은 매우 희박한 경우 작은 문자열의 최적화가 해시 테이블의 각 사용되지 않는 인덱스는 여전히합니다 (SS 최적화를 위해 더 많은 메모리를 사용하는 것을 의미하는 것이기 때문에 사실, 작은 문자열 최적화 실제로,이 경우에 도움이 유해로 수 sizeof(string)것 해시 테이블의 총 메모리 오버 헤드가 저장하는 것보다 비용이 많이 드는 지점, 특히 위치 구성 요소와 같은 간단한 구성 요소 인 경우 큰 보폭으로 더 많은 캐시 미스가 발생하는 경우 해시 테이블의 한 항목에서 다음 항목으로 이동합니다.

문자열이 구성 요소 ID와 같은 일종의 키라고 가정합니다. 그렇다면 이미 비용을 크게 절감 할 수 있습니다.

unordered_map<int,[yada]>

... 예를 들어, 스크립터가 사용할 수있는 사용자에게 친숙한 이름을 가질 수있는 이점을 원한다면, 인터 닝 된 문자열을 사용하면 두 가지 이점을 모두 얻을 수 있습니다.

즉, 문자열을 합리적으로 낮은 범위의 밀도가 높은 인덱스에 매핑 할 수 있다면 다음과 같이 할 수 있습니다.

vector<[yada]> // the index and key become one and the same

내가이 조기를 고려하지 않은 이유는 다시 인터페이스 디자인에 영향을 줄 수 있기 때문입니다. DOD의 요점은 한 번에 IMO에서 상상할 수있는 가장 효율적인 데이터 표현을 제시하려고 시도해서는 안되며 (일반적으로 필요에 따라 반복적으로 달성해야 함),이를 처리하기 위해 인터페이스를 설계 할 수있을 정도로 충분히 생각해야합니다. 계단식 설계 변경없이 프로파일 링하고 최적화 할 수있는 충분한 호흡 공간을 제공하는 데이터.

순진한 예로서, 모든 코드를 이것에 결합하는 비디오 처리 소프트웨어 :

// Abstract pixel that could be concretely represented by
// RGB, BGR, RGBA, BGRA, 1-bit channels, 8-bit channels, 
// 16-bit channels, 32-bit channels, grayscale, monochrome, 
// etc. pixels.
class IPixel
{
public:
    virtual ~IPixel() {}
    ...
};

단일 픽셀 수준 에서 추상화하는 아이디어 vptr이미지 수준 에서 추상화하는 것보다 이미 비효율적입니다 ( 자체적으로 전체 픽셀보다 더 많은 메모리를 소비 할 수 있음). 종종 수백만 픽셀을 나타냅니다). 따라서 이러한 악몽 시나리오에 직면 할 필요가없고 이상적으로는 더 이상 필요하지 않도록 데이터 표현에 대해 충분히 생각하십시오. 그러나 여기서는 이러한 것들에 대해 생각하지 않아도됩니다. ECS 주변에 복잡한 엔진을 설치하고 ECS 자체가 설계 수준에서 사물을 변경해야하는 방식으로 병목 현상을 발견합니다.

ECS 캐시 미스에 관해서는 개발자들은 종종 ECS를 캐시 친화적으로 만들기 위해 너무 열심히 노력합니다. 벅이 모든 구성 요소에 완벽하게 인접한 방식으로 액세스하려고 시도하기에는 너무 적은 비용이 들기 시작하며 종종 모든 곳에서 데이터를 복사하고 섞는 것을 의미합니다. 일반적으로 메모리 영역을 캐시 라인에로드하지 않고 제거하기 만하면로드 할 수있는 방법으로 액세스하기 전에 기수 정렬 구성 요소 인덱스에 액세스하는 것이 좋습니다. 동일한 캐시 라인의 다른 부분에 액세스하기 위해 동일한 루프에서 다시 반복됩니다. ECS는 전반적으로 놀라운 효율성을 제공 할 필요가 없습니다. 물리학이나 렌더링 시스템만큼이나 입력 시스템의 이점과는 다르므로 "좋은"목표를 세우는 것이 좋습니다 보드 전체의 효율성과 실제로 필요한 곳에 "우수"합니다. 즉, 사용unordered_map그리고 string여기서 피할 수있을 정도로 쉽습니다.

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