문제

최근 한 동료가 나에게 모든 것을 단일 파일로 컴파일하면 별도의 개체 파일을 컴파일하는 것보다 훨씬 더 효율적인 코드가 생성된다고 지적했습니다. 링크 시간 최적화가 켜져 있어도.또한 프로젝트의 총 컴파일 시간도 크게 단축되었습니다.C++를 사용하는 주된 이유 중 하나가 코드 효율성이라는 점을 고려하면 이는 나에게 놀라운 일이었습니다.

분명히 아카이버/링커가 객체 파일로 라이브러리를 만들거나 이를 실행 파일에 링크할 때 단순한 최적화라도 불이익을 받습니다.아래 예에서 컴파일러 대신 링커를 사용하여 사소한 인라인 처리를 수행하면 성능이 1.8% 저하됩니다.이와 같은 일반적인 상황을 처리할 수 있을 만큼 컴파일러 기술이 발전해야 할 것 같지만 실제로는 그렇지 않습니다.

다음은 Visual Studio 2008을 사용한 간단한 예입니다.

#include <cstdlib>
#include <iostream>
#include <boost/timer.hpp>

using namespace std;

int foo(int x);
int foo2(int x) { return x++; }

int main(int argc, char** argv)
{
  boost::timer t;

  t.restart();
  for (int i=0; i<atoi(argv[1]); i++)
    foo (i);
  cout << "time : " << t.elapsed() << endl;

  t.restart();
  for (int i=0; i<atoi(argv[1]); i++)
    foo2 (i);
  cout << "time : " << t.elapsed() << endl;
}

foo.cpp

int foo (int x) { return x++; }

실행 결과:연결된 사용 시 1.8% 성능 저하 foo 인라인 대신 foo2.

$ ./release/testlink.exe  100000000
time : 13.375
time : 13.14

그리고 그렇습니다. 링커 최적화 플래그(/LTCG)가 켜져 있습니다.

도움이 되었습니까?

해결책

저는 컴파일러 전문가는 아니지만, 객체 출력에서 ​​작동하기 위해 콘텐츠 자체를 사용해야 하는 링커와 달리 컴파일러는 언어 트리에서 작동하므로 최적화하기 위해 처리할 수 있는 정보가 훨씬 더 많고 표현력이 훨씬 떨어진다고 생각합니다. 컴파일러가 본 코드보다따라서 링커와 컴파일러 개발 팀은 이론적으로 컴파일러가 수행하는 트릭과 일치할 수 있는 링커 최적화를 만드는 데 더 적은 노력을 쏟습니다.

그런데, 귀하의 원래 질문을 ltcg 토론에 집중하게 해서 죄송합니다.이제 귀하의 질문이 링크 시간과 링크 시간에 더 관심이 있다는 점을 이해합니다.컴파일 시간 정적 최적화가 가능/사용 가능합니다.

다른 팁

동료가 구식입니다. 이 기술은 2003 년부터 (MS C ++ 컴파일러에서) 여기에있었습니다. /ltcg. 링크 시간 코드 생성은이 문제를 정확히 다루고 있습니다. 내가 아는 것에서 GCC 차세대 컴파일러의 레이더 에이 기능이 있습니다.

LTCG는 모듈에서 인라인 기능과 같은 코드를 최적화 할뿐만 아니라 실제로 캐시 로컬을 최적화하고 특정 부하에 대한 분기를 최적화하기 위해 실제로 리어 맨 코드를 참조하십시오. 프로필 유도 최적화. 이 옵션은 빌드를 완료하는 데 몇 시간이 걸릴 수 있으므로 릴리스 빌드에만 예약되어 있습니다. 계측 실행 가능을 연결하고 프로파일 링 하중을 실행 한 다음 프로파일 링 결과와 다시 연결합니다. 링크에는 LTCG로 정확히 최적화 된 내용에 대한 세부 정보가 포함되어 있습니다.

인라인 -예를 들어, 함수 A가 존재하는 경우 기능 B를 자주 호출하고 함수 B가 비교적 작 으면 프로파일 유도 최적화가 함수 B에서 BUNLENE가됩니다.

가상 통화 추측 -기능 포인터를 통한 가상 호출 또는 기타 호출이 종종 특정 함수를 대상으로하는 경우 프로파일 유도 최적화는 조건부로 실행되는 직접 호출을 자주 표적으로 표적화하는 기능에 삽입 할 수 있으며 직접 호출을 상환 할 수 있습니다.

등록 할당 - 프로파일 데이터로 최적화하면 더 나은 레지스터 할당이 발생합니다.

기본 블록 최적화 - 기본 블록 최적화를 통해 주어진 프레임 내에서 일시적으로 실행되는 일반적으로 실행되는 기본 블록을 동일한 페이지 세트 (Locality)에 배치 할 수 있습니다. 이것은 사용 된 페이지 수를 최소화하므로 메모리 오버 헤드를 최소화합니다.

크기/속도 최적화 - 프로그램이 많은 시간을 소비하는 기능은 속도를 위해 최적화 할 수 있습니다.

기능 레이아웃 - 통화 그래프 및 프로파일 링 된 발신자/칼리 동작을 기반으로 동일한 실행 경로를 따라있는 경향이 같은 섹션에 배치됩니다.

조건부 분기 최적화 -값 프로브를 사용하면 프로파일 유도 최적화가 스위치 문의 주어진 값이 다른 값보다 더 자주 사용되는지 확인할 수 있습니다. 그런 다음이 값을 스위치 문에서 철수 할 수 있습니다. 최적화기가 IF/Else를 주문할 수있는 IF/Else 명령으로 동일하게 수행 할 수 있으므로 IF 또는 Else 블록이 어느 블록이 더 자주 진실한 지에 따라 먼저 배치됩니다.

죽은 코드 분리 - 프로파일 링 중에 호출되지 않은 코드는 섹션 세트의 끝에 추가되는 특수 섹션으로 이동됩니다. 이것은이 섹션을 종종 사용하는 페이지에서 효과적으로 보관합니다.

EH 코드 분리 -예외적으로 실행되는 EH 코드는 프로파일 유도 최적화가 예외적 인 조건에서만 발생하는지 결정할 수있을 때 종종 별도의 섹션으로 이동할 수 있습니다.

메모리 내부 - 고유의 확장은 고유를 자주 호출하는지 결정할 수 있다면 더 잘 결정될 수 있습니다. 내재는 이동 또는 사본의 블록 크기에 따라 최적화 될 수 있습니다.

당신의 동료는 우리 대부분보다 똑똑합니다. 처음에는 조잡한 접근 방식 인 것처럼 보이지만, 프로젝트는 단일 .CPP 파일로 인한 프로젝트가 링크 타임-최적화와 같은 다른 접근 방식이 가지고 있지 않으며 신뢰할 수 있음

그러나 당신은 2 년 전에이 물었다. 그리고 나는 그 이후로 많은 변화가 그 이후로 (적어도 G ++와 함께) 변화했다고 증언한다. 예를 들어 Devirtualization은 훨씬 더 신뢰할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top