IT story

C ++ 컴파일 시간을 단축하기 위해 어떤 기술을 사용할 수 있습니까?

hot-time 2020. 4. 11. 10:12
반응형

C ++ 컴파일 시간을 단축하기 위해 어떤 기술을 사용할 수 있습니까?


C ++ 컴파일 시간을 단축하기 위해 어떤 기술을 사용할 수 있습니까?

이 질문은 Stack Overflow question C ++ programming style에 대한 의견에서 나 왔으며 어떤 아이디어가 있는지 듣고 싶습니다.

관련 질문을 보았습니다. 왜 C ++ 컴파일이 그렇게 오래 걸립니까? 하지만 많은 솔루션을 제공하지는 않습니다.


프로젝트 간 미리 컴파일 된 헤더 공유를 Visual Studio에서 지원합니다.


언어 기술

핌프 숙어

여기여기 에서 불투명 포인터 또는 핸들 클래스 라고도 하는 Pimpl 관용구를 살펴보십시오 . 컴파일 속도를 높일뿐만 아니라 비 투척 스왑 기능 과 결합하면 예외 안전성도 향상 됩니다. Pimpl 관용구를 사용하면 헤더 간의 종속성을 줄이고 수행해야하는 재 컴파일 양을 줄일 수 있습니다.

전달 선언

가능하면 앞으로 선언을 사용하십시오 . 컴파일러 SomeIdentifier가 구조체 또는 포인터 또는 그 밖의 것만 알고 있으면 전체 정의를 포함시키지 말고 컴파일러가 필요한 것보다 많은 작업을 수행하도록하십시오. 계단식 효과를 낼 수 있으므로이 방법이 필요 이상으로 느려집니다.

I / O의 스트림은 특히 빌드 둔화에 대한 알려져있다. 헤더 파일에 필요한 경우 구현 파일에서만 헤더 <iosfwd>를 포함 <iostream>하고 #include를 시도 하고 #include하십시오 <iostream>. <iosfwd>헤더는 앞으로 선언 만 보유하고 있습니다. 불행히도 다른 표준 헤더에는 각각의 선언 헤더가 없습니다.

함수 시그니처에서 값을 기준으로 전달하는 것을 선호합니다. 이렇게하면 헤더 파일에 각 유형 정의를 #include 할 필요가 없으며 유형을 전달하기 만하면됩니다. 물론 불분명 한 버그를 피하기 위해 비 const 참조에 대한 const 참조를 선호하지만 이것은 또 다른 질문의 문제입니다.

가드 조건

보호 조건을 사용하여 헤더 파일이 단일 변환 단위에 두 번 이상 포함되지 않도록하십시오.

#pragma once
#ifndef filename_h
#define filename_h

// Header declarations / definitions

#endif

pragma와 ifndef를 모두 사용하면 일반 매크로 솔루션의 이식성과 일부 컴파일러가 pragma once지시문 이있을 때 수행 할 수있는 컴파일 속도 최적화를 얻을 수 있습니다 .

상호 의존성 감소

일반적으로 코드 디자인이 모듈 식이고 상호 의존성이 낮을수록 모든 것을 다시 컴파일해야하는 횟수가 줄어 듭니다. 또한 추적해야 할 내용이 적기 때문에 컴파일러가 개별 블록에 대해 동시에 수행해야하는 작업량을 줄일 수 있습니다.

컴파일러 옵션

미리 컴파일 된 헤더

이들은 많은 번역 단위에 대해 포함 된 헤더의 공통 섹션을 한 번 컴파일하는 데 사용됩니다. 컴파일러는이를 한 번 컴파일하고 내부 상태를 저장합니다. 그런 다음 동일한 헤더 세트로 다른 파일을 컴파일 할 때 헤드 상태를 신속하게로드 할 수 있습니다.

미리 컴파일 된 헤더에 거의 변경되지 않은 항목 만 포함 시키거나 필요에 따라 전체 재 구축을 더 자주 수행 할 수 있습니다. 이것은위한 좋은 장소입니다 STL의 헤더와 다른 라이브러리 파일이 포함됩니다.

ccache 는 캐싱 기술을 활용하여 작업 속도를 높이는 또 다른 유틸리티입니다.

병렬 처리 사용

많은 컴파일러 / IDE는 동시에 여러 개의 코어 / CPU를 사용하여 컴파일을 지원합니다. 에서 GNU 제조사 (일반적으로 GCC와 함께 사용) 사용 -j [N]옵션을 선택합니다. Visual Studio에는 환경 설정에 여러 프로젝트를 병렬로 빌드 할 수있는 옵션이 있습니다. 또한 프로젝트 레벨 병렬 처리 대신 파일 레벨 병렬 처리 /MP옵션사용할 수도 있습니다 .

다른 병렬 유틸리티 :

더 낮은 최적화 수준 사용

컴파일러가 최적화하려고하면할수록 더 어려워집니다.

공유 라이브러리

덜 자주 수정 된 코드를 라이브러리로 옮기면 컴파일 시간이 단축 될 수 있습니다. 공유 라이브러리 ( .so또는 .dll) 를 사용 하면 연결 시간도 줄일 수 있습니다.

더 빠른 컴퓨터를 얻으십시오

더 많은 RAM, 더 빠른 하드 드라이브 (SSD 포함) 및 더 많은 CPU / 코어는 모두 컴파일 속도에 차이를 만듭니다.


STAPL 프로젝트에서 일하고 있습니다.이 템플릿은 C ++ 라이브러리입니다. 가끔 컴파일 시간을 줄이기 위해 모든 기술을 다시 방문해야합니다. 여기에서는 우리가 사용하는 기술을 요약했습니다. 이러한 기술 중 일부는 이미 위에 나열되어 있습니다.

가장 시간이 많이 걸리는 섹션 찾기

심볼 길이와 컴파일 시간 사이에 입증 된 상관 관계는 없지만 평균 심볼 크기가 작을수록 모든 컴파일러의 컴파일 시간이 향상 될 수 있습니다. 따라서 첫 번째 목표는 코드에서 가장 큰 기호를 찾는 것입니다.

방법 1-크기를 기준으로 기호 정렬

nm명령을 사용하여 크기를 기준으로 심볼을 나열 할 수 있습니다 .

nm --print-size --size-sort --radix=d YOUR_BINARY

이 명령 --radix=d에서 10 진수로 크기를 볼 수 있습니다 (기본값은 16 진). 이제 가장 큰 기호를보고 해당 클래스를 중단하고 기본 클래스에서 템플릿 화되지 않은 부분을 고려하거나 클래스를 여러 클래스로 분할하여 클래스를 다시 디자인 할 수 있는지 확인하십시오.

방법 2-길이를 기준으로 기호 정렬

일반 nm명령을 실행하고 원하는 스크립트 ( AWK , Python 등)로 파이프 하여 길이 에 따라 기호를 정렬 할 수 있습니다. 우리의 경험을 바탕으로,이 방법은 방법 1보다 후보를 더 잘 만드는 가장 큰 문제를 식별합니다.

방법 3-Templight 사용

" Templight템플릿 인스턴스화의 시간과 메모리 소비를 프로파일 링하고 대화 형 디버깅 세션을 수행하여 템플릿 인스턴스화 프로세스에 대한 내성을 확보 하는 Clang 기반 도구입니다."

LLVM 및 Clang ( 지침 ) 을 확인 하고 Templight 패치를 적용하여 Templight를 설치할 수 있습니다 . LLVM 및 Clang의 기본 설정은 디버그 및 어설 션에 있으며 컴파일 시간에 상당한 영향을 줄 수 있습니다. Templight에 둘 다 필요한 것처럼 보이므로 기본 설정을 사용해야합니다. LLVM 및 Clang 설치 프로세스는 약 1 시간 정도 걸립니다.

패치를 적용한 후 templight++설치시 지정한 빌드 폴더에있는 코드를 사용하여 코드를 컴파일 할 수 있습니다.

templight++PATH에 있는지 확인하십시오 . 이제 컴파일하려면 CXXFLAGSMakefile 또는 명령 줄 옵션에 다음 스위치를 추가하십시오 .

CXXFLAGS+=-Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system

또는

templight++ -Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system

컴파일이 완료되면 같은 폴더에 .trace.memory.pbf 및 .trace.pbf가 생성됩니다. 이러한 추적을 시각화하기 위해 Templight 도구사용하여 다른 형식으로 변환 할 수 있습니다. templight-convert를 설치하려면 다음 지시 사항따르십시오 . 우리는 일반적으로 callgrind 출력을 사용합니다. 프로젝트가 작은 경우 GraphViz 출력을 사용할 수도 있습니다.

$ templight-convert --format callgrind YOUR_BINARY --output YOUR_BINARY.trace

$ templight-convert --format graphviz YOUR_BINARY --output YOUR_BINARY.dot

생성 된 callgrind 파일은 kcachegrind사용하여 열 수 있으며 , 가장 많은 시간 / 메모리를 소비하는 인스턴스화를 추적 할 수 있습니다.

템플릿 인스턴스화 횟수 감소

템플릿 인스턴스화 수를 줄이는 정확한 솔루션은 없지만 다음과 같은 몇 가지 지침이 있습니다.

둘 이상의 템플릿 인수로 클래스 리팩터링

예를 들어 수업이 있으면

template <typename T, typename U>
struct foo { };

그리고 모두 TU10 가지 옵션을 가질 수 있습니다, 당신은이 추상적에 다른 클래스에 코드의 공통 부분 해결하기 위해 100 가지 방법으로이 클래스의 가능한 템플릿 인스턴스화를 증가하고있다. 다른 방법은 상속 계층 (클래스 계층 구조 역전)을 사용하는 것이지만이 기술을 사용하기 전에 디자인 목표가 손상되지 않는지 확인하십시오.

템플릿이 아닌 코드를 개별 번역 단위로 리팩토링

이 기술을 사용하면 공통 섹션을 한 번 컴파일하고 나중에 다른 TU (번역 단위)와 연결할 수 있습니다.

extern 템플릿 인스턴스화 사용 (C ++ 11부터)

클래스의 가능한 모든 인스턴스화를 알고 있으면이 기술을 사용하여 모든 사례를 다른 번역 단위로 컴파일 할 수 있습니다.

예를 들면 다음과 같습니다.

enum class PossibleChoices = {Option1, Option2, Option3}

template <PossibleChoices pc>
struct foo { };

이 클래스에는 세 가지 가능한 인스턴스가있을 수 있습니다.

template class foo<PossibleChoices::Option1>;
template class foo<PossibleChoices::Option2>;
template class foo<PossibleChoices::Option3>;

위의 내용을 번역 단위에 넣고 클래스 정의 아래의 헤더 파일에서 extern 키워드를 사용하십시오.

extern template class foo<PossibleChoices::Option1>;
extern template class foo<PossibleChoices::Option2>;
extern template class foo<PossibleChoices::Option3>;

이 기법을 사용하면 일반적인 인스턴스화 세트로 다른 테스트를 컴파일 할 때 시간을 절약 할 수 있습니다.

참고 : MPICH2는이 시점에서 명시 적 인스턴스화를 무시하고 항상 모든 컴파일 단위에서 인스턴스화 된 클래스를 컴파일합니다.

화합 빌드 사용

유니티 빌드의 기본 개념은 하나의 파일에 사용하는 모든 .cc 파일을 포함하고 해당 파일을 한 번만 컴파일하는 것입니다. 이 방법을 사용하면 다른 파일의 공통 섹션을 다시 인스턴스화하지 않고 프로젝트에 많은 공통 파일이 포함 된 경우 디스크 액세스에도 저장할 수 있습니다.

예를 들어,의 당신이 세 개의 파일이 있다고 가정하자 foo1.cc, foo2.cc, foo3.cc그들은 모두 포함 tuple에서 STL . foo-all.cc다음과 같은 모양을 만들 수 있습니다 .

#include "foo1.cc"
#include "foo2.cc"
#include "foo3.cc"

이 파일을 한 번만 컴파일하면 세 파일 간의 공통 인스턴스가 줄어 듭니다. 개선이 중요한지 아닌지를 일반적으로 예측하기는 어렵습니다. 그러나 한 가지 분명한 사실은 빌드에서 병렬 처리 손실 된다는 것입니다 (더 이상 세 파일을 동시에 컴파일 할 수 없음).

또한 이러한 파일 중 하나라도 많은 메모리를 사용하는 경우 컴파일이 끝나기 전에 실제로 메모리가 부족할 수 있습니다. GCC 와 같은 일부 컴파일러에서는 메모리 부족으로 인해 컴파일러에 ICE (Internal Compiler Error)가 발생할 수 있습니다. 따라서 모든 장단점을 알고 있지 않으면이 기술을 사용하지 마십시오.

미리 컴파일 된 헤더

PCH (사전 컴파일 된 헤더)는 헤더 파일을 컴파일러가 인식 할 수있는 중간 표현으로 컴파일하여 컴파일 시간을 크게 절약 할 수 있습니다. 사전 컴파일 된 헤더 파일을 생성하려면 일반 컴파일 명령으로 헤더 파일 만 컴파일하면됩니다. 예를 들어 GCC에서 :

$ g++ YOUR_HEADER.hpp

이것은이 생성됩니다 YOUR_HEADER.hpp.gch file( .gch같은 폴더에 GCC에서 PCH 파일의 확장자입니다). YOUR_HEADER.hpp, 다른 파일에 포함하면 컴파일러가 이전에 동일한 폴더 YOUR_HEADER.hpp.gch대신 사용합니다 YOUR_HEADER.hpp.

이 기술에는 두 가지 문제가 있습니다.

  1. 미리 컴파일 된 헤더 파일이 안정적이며 변경되지 않는지 확인해야합니다 ( 항상 makefile을 변경할 수 있음 )
  2. 컴파일 장치 당 하나의 PCH 만 포함 할 수 있습니다 (대부분의 컴파일러에서). 즉, 미리 컴파일 할 헤더 파일이 두 개 이상인 경우 하나의 파일 (예 :)에 포함시켜야합니다 all-my-headers.hpp. 그러나 이것은 모든 장소에 새로운 파일을 포함시켜야한다는 것을 의미합니다. 다행히도 GCC에는이 문제에 대한 해결책이 있습니다. 사용 -include하고 그것을 새로운 헤더 파일을 제공합니다. 이 기술을 사용하여 쉼표로 다른 파일을 분리 할 수 ​​있습니다.

예를 들면 다음과 같습니다.

g++ foo.cc -include all-my-headers.hpp

이름이 없거나 익명 인 네임 스페이스 사용

익명 네임 스페이스 ( 명명없는 네임 스페이스)는 생성 된 이진 크기를 크게 줄일 수 있습니다. 명명되지 않은 네임 스페이스는 내부 연결을 사용하므로 해당 네임 스페이스에서 생성 된 심볼은 다른 TU (번역 또는 컴파일 단위)에 표시되지 않습니다. 컴파일러는 일반적으로 명명되지 않은 네임 스페이스에 대해 고유 한 이름을 생성합니다. 이는 foo.hpp 파일이있는 경우 다음을 의미합니다.

namespace {

template <typename T>
struct foo { };
} // Anonymous namespace
using A = foo<int>;

그리고이 파일을 두 개의 TU (2 개의 .cc 파일과 별도로 컴파일)에 포함시킵니다. 두 개의 foo 템플릿 인스턴스는 동일하지 않습니다. 이는 하나의 정의 규칙 (ODR)에 위배 됩니다. 같은 이유로 이름없는 네임 스페이스를 사용하는 것은 헤더 파일에서 사용하지 않는 것이 좋습니다. .cc이진 파일에 기호가 표시되지 않도록 파일 에서 자유롭게 사용 하십시오. 경우에 따라 .cc파일의 모든 내부 세부 정보를 변경 하면 생성 된 이진 크기가 10 % 감소한 것으로 나타났습니다.

가시성 옵션 변경

최신 컴파일러에서는 DSO (Dynamic Shared Objects)에서 심볼이 표시되거나 보이지 않도록 선택할 수 있습니다. 가시성을 변경하면 컴파일러 성능, 링크 시간 최적화 (LTO) 및 생성 된 이진 크기를 개선 할 수 있습니다. GCC에서 STL 헤더 파일을 보면 널리 사용되는 것을 볼 수 있습니다. 가시성 선택을 가능하게하려면 함수, 클래스, 변수 및 더 중요한 컴파일러마다 코드를 변경해야합니다.

가시성의 도움으로 생성 된 공유 객체에서 개인으로 간주되는 심볼을 숨길 수 있습니다. GCC에서는 -visibility컴파일러 옵션에 기본값을 숨기거나 숨겨서 기호의 가시성을 제어 할 수 있습니다 . 이는 이름이없는 네임 스페이스와 비슷하지만보다 정교하고 방해가되는 방식입니다.

사례 당 가시성을 지정하려면 함수, 변수 및 클래스에 다음 속성을 추가해야합니다.

__attribute__((visibility("default"))) void  foo1() { }
__attribute__((visibility("hidden")))  void  foo2() { }
__attribute__((visibility("hidden")))  class foo3   { };
void foo4() { }

GCC의 기본 가시성은 공유 라이브러리 (로 위의 컴파일하는 경우 즉, 기본 (공개)이다 -shared) 방법, foo2및 클래스가 foo3다른 TU가에 표시되지 않습니다 ( foo1foo4표시됩니다). 당신이 컴파일하는 경우 -visibility=hiddenfoo1표시됩니다. 비록 foo4숨겨져있을 것입니다.

GCC wiki의 가시성에 대해 자세히 읽을 수 있습니다 .


"Indie 게임 디자인 및 프로그래밍 게임"에서 다음 기사를 추천합니다.

사실, 그것들은 꽤 오래되었습니다. 사실적인 결과를 얻으려면 최신 버전 (또는 사용 가능한 버전)으로 모든 것을 다시 테스트해야합니다. 어느 쪽이든, 그것은 아이디어의 좋은 소스입니다.


과거에 나를 위해 잘 작동 한 기술 : 여러 C ++ 소스 파일을 독립적으로 컴파일하지 말고 다음과 같이 다른 모든 파일을 포함하는 하나의 C ++ 파일을 생성하십시오.

// myproject_all.cpp
// Automatically generated file - don't edit this by hand!
#include "main.cpp"
#include "mainwindow.cpp"
#include "filterdialog.cpp"
#include "database.cpp"

물론 이것은 소스가 변경 될 경우 포함 된 모든 소스 코드를 다시 컴파일해야하기 때문에 종속성 트리가 더 나빠질 수 있습니다. 그러나 하나의 번역 단위로 여러 소스 파일을 컴파일하는 것이 더 빠르며 (적어도 MSVC 및 GCC 실험에서는 ) 더 작은 바이너리가 생성됩니다. 또한 컴파일러가 최적화 가능성이 더 높다고 생각합니다 (한 번에 더 많은 코드를 볼 수 있기 때문에).

이 기술은 다양한 경우에 실패합니다. 예를 들어, 둘 이상의 소스 파일이 동일한 이름의 전역 함수를 선언하는 경우 컴파일러가 구제됩니다. 그래도 다른 답변에 설명 된이 기술을 찾을 수 없으므로 여기에서 언급합니다.

가치있는 것을 위해, KDE 프로젝트 는 1999 년 이후이 같은 기술을 사용하여 최적화 된 바이너리를 빌드 할 수있었습니다 (아마도 릴리스 용). 빌드 구성 스크립트로의 전환을 호출했습니다 --enable-final. 고고 학적 관심에서이 기능을 발표 한 게시물을 발굴했습니다 : http://lists.kde.org/?l=kde-devel&m=92722836009368&w=2


이 주제에 대한 전체 책이 있으며 제목은 Large-Scale C ++ Software Design (John Lakos가 작성)입니다.

이 책은 템플릿보다 오래된 것이므로, 그 책의 내용에 "템플릿을 사용하면 컴파일러가 느려질 수있다"고 덧붙인다.


나는 다른 대답에 링크 할 것입니다 : 어떻게 컴파일 시간을 줄이고 Visual C ++ 프로젝트 (기본 C ++)의 시간을 연결합니까? . 추가하고 싶은 또 다른 요점은 종종 문제를 일으키는 사전 컴파일 된 헤더를 사용하는 것입니다. 그러나 GUI 툴킷 헤더와 같이 거의 변경되지 않는 부분에만 사용하십시오. 그렇지 않으면 결국 비용을 절약하는 것보다 더 많은 시간이 소요됩니다.

또 다른 옵션은 GNU make로 작업 할 때 옵션을 켜는 것입니다 -j<N>.

  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg.

나는 3이중 코어를 가지고 있기 때문에 보통 그것을 가지고 있습니다. 그런 다음 다른 번역 단위에 대해 컴파일러가 병렬로 실행됩니다. 모든 객체 파일을 연결하는 링커 프로세스가 하나뿐이므로 링크를 병렬로 수행 할 수 없습니다.

그러나 링커 자체는 스레드 될 수 있으며 이것이 ELF 링커가하는 일입니다. ELF 객체 파일을 이전보다 훨씬 빠르게 링크 하고 실제로 binutils에 포함 되었다고하는 스레드 C ++ 코드에 최적화 되어 있습니다 .GNU gold ld


여기 몇 가지가 있습니다 :

  • 다중 컴파일 작업을 시작하여 모든 프로세서 코어를 사용하십시오 ( make -j2좋은 예).
  • 최적화를 끄거나 낮추십시오 (예 : GCC가 또는 -O1보다 빠릅니다 ).-O2-O3
  • 미리 컴파일 된 헤더를 사용하십시오 .

위의 모든 코드 트릭 (포워드 선언, 퍼블릭 헤더의 헤더 포함을 최소화하고 Pimpl을 사용 하여 구현 파일 내부의 대부분의 세부 정보를 밀어 넣음 )을 적용하고 다른 언어로 얻을 수있는 것이 없다면 빌드 시스템을 고려하십시오. . Linux를 사용하는 경우 distcc (분산 컴파일러) 및 ccache (캐시 컴파일러) 사용을 고려하십시오.

첫 번째 distcc는 전 처리기 단계를 로컬로 실행 한 다음 네트워크에서 사용 가능한 첫 번째 컴파일러로 출력을 보냅니다. 네트워크의 모든 구성된 노드에서 동일한 컴파일러 및 라이브러리 버전이 필요합니다.

후자 인 ccache는 컴파일러 캐시입니다. 전처리기를 다시 실행 한 다음 전 처리기 파일이 동일한 컴파일러 매개 변수로 이미 컴파일되었는지 내부 데이터베이스 (로컬 디렉토리에 보유)를 확인합니다. 그렇다면 바이너리를 팝업하고 컴파일러의 첫 번째 실행에서 출력합니다.

둘 다 동시에 사용할 수 있으므로 ccache에 로컬 사본이 없으면 distcc를 사용하여 네트를 통해 다른 노드로 보내거나 추가 처리없이 솔루션을 주입 할 수 있습니다.


내가 대학을 졸업했을 때, 내가 본 최초의 실제 생산 가치가있는 C ++ 코드는 헤더가 정의 된 이들 사이에 이러한 #ifndef ... #endif 지시문이있었습니다. 나는이 중요한 것들에 대해 코드를 작성하는 사람에게 매우 순진한 방식으로 물었고 대규모 프로그래밍 세계에 소개되었습니다.

요점으로 돌아가서, 중복 헤더 정의를 방지하기 위해 지시문을 사용하는 것이 컴파일 시간을 줄이는 데 가장 먼저 배웠습니다.


더 많은 RAM.

누군가 다른 대답으로 RAM 드라이브에 대해 이야기했습니다. 나는 80286Turbo C ++ (나이를 보여줌)로 이것을 했고 그 결과는 놀랍습니다. 머신이 충돌했을 때 데이터가 손실 된 것과 같습니다.


가능하면 앞으로 선언을 사용하십시오. 클래스 선언이 포인터 또는 형식에 대한 참조 만 사용하는 경우이를 선언하고 구현 파일에 형식의 헤더를 포함시킬 수 있습니다.

예를 들면 다음과 같습니다.

// T.h
class Class2; // Forward declaration

class T {
public:
    void doSomething(Class2 &c2);
private:
    Class2 *m_Class2Ptr;
};

// T.cpp
#include "Class2.h"
void Class2::doSomething(Class2 &c2) {
    // Whatever you want here
}

포함이 적을수록 전처리기에 충분한 작업을 수행 할 수 있습니다.


Unity Builds를 사용할 수 있습니다 .

​​


사용하다

#pragma once

번역 단위에 두 번 이상 포함 된 경우 헤더의 텍스트는 한 번만 포함되고 구문 분석됩니다.


완전성을 위해 : 빌드 시스템이 어리 석고 컴파일러가 작업을 수행하는 데 오랜 시간이 걸리기 때문에 빌드가 느려질 수 있습니다.

유닉스 환경에서이 주제에 대한 토론은 재귀 적 유해한 것으로 간주 (PDF)를 읽으 십시오 .


  • 컴퓨터 업그레이드

    1. 쿼드 코어 (또는 듀얼 쿼드 시스템) 확보
    2. 많은 RAM을 확보하십시오.
    3. RAM 드라이브를 사용하여 파일 I / O 지연을 크게 줄입니다. (하드 드라이브처럼 작동하는 IDE 및 SATA RAM 드라이브를 만드는 회사가 있습니다).
  • 그런 다음 다른 일반적인 제안이 있습니다.

    1. 가능한 경우 사전 컴파일 된 헤더를 사용하십시오.
    2. 프로젝트의 부품 사이의 커플 링 양을 줄이십시오. 하나의 헤더 파일을 변경하면 일반적으로 전체 프로젝트를 다시 컴파일 할 필요가 없습니다.

RAM 드라이브 사용에 대한 아이디어가있었습니다 . 내 프로젝트의 경우 결국 큰 차이를 만들지 않는 것으로 나타났습니다. 그러나 그들은 여전히 ​​작습니다. 시도 해봐! 나는 그것이 얼마나 도움이되었는지에 관심이 있습니다.


어디에서 시간을 보내십니까? CPU 바운드입니까? 메모리 바운드? 디스크 바운드? 더 많은 코어를 사용할 수 있습니까? 더 많은 RAM? RAID가 필요하십니까? 현재 시스템의 효율성을 높이고 싶습니까?

.

gcc / g ++에서 ccache 를 보았 습니까? make_clean _; _ make를 많이 수행하면 도움이 될 수 있습니다.


동적 연결 (.so)은 정적 연결 (.a)보다 훨씬 빠릅니다. 특히 네트워크 드라이브 속도가 느린 경우. .a 파일의 모든 코드를 처리하고 작성해야하기 때문입니다. 또한 훨씬 큰 실행 파일을 디스크에 기록해야합니다.


컴파일 시간이 아니라 빌드 시간에 관한 것입니다.

  • 빌드 파일을 작업 할 때 동일한 파일을 다시 빌드해야하는 경우 ccache를 사용하십시오.

  • make 대신 ninja-build사용하십시오 . 현재 ~ 100 소스 파일로 프로젝트를 컴파일 중이며 ccache에 의해 모든 것이 캐시됩니다. 5 분이면 닌자가 1보다 작아야합니다.

를 사용하여 cmake에서 닌자 파일을 생성 할 수 있습니다 -GNinja.


빠른 하드 디스크.

컴파일러는 많은 (그리고 아마도 큰) 파일을 디스크에 씁니다. 일반적인 하드 디스크 대신 SSD를 사용하면 컴파일 시간이 훨씬 단축됩니다.


Linux (및 다른 * NIX)에서 출력을 유지하지 않고 다른 TTY로 변경하여 컴파일 속도를 높일 수 있습니다 .

다음은 실험입니다 : printf프로그램을 느리게합니다


탐색 대기 시간이 길어 네트워크 공유가 빌드 속도를 크게 느리게합니다. 네트워크 공유 드라이브가 매우 빠르더라도 Boost와 같은 것은 나에게 큰 차이가있었습니다. 네트워크 공유에서 로컬 SSD로 전환했을 때 장난감 부스트 프로그램을 컴파일하는 시간이 약 1 분에서 1 초로 단축되었습니다.


멀티 코어 프로세서가있는 경우 Visual Studio (2005 이상) 및 GCC 는 모두 멀티 프로세서 컴파일을 지원합니다. 하드웨어가 있다면 가능하게 할 수 있습니다.


"기술"은 아니지만 많은 소스 파일이있는 Win32 프로젝트가 "Hello World"빈 프로젝트보다 빠르게 컴파일되는 방법을 알 수 없었습니다. 따라서, 이것이 저와 같은 사람에게 도움이되기를 바랍니다.

Visual Studio에서 컴파일 시간을 늘리는 한 가지 옵션은 증분 연결 ( / INCREMENTAL )입니다. 링크 타임 코드 생성 ( / LTCG ) 과 호환되지 않으므로 릴리스 빌드를 수행 할 때 증분 링크를 비활성화해야합니다.

참고 URL : https://stackoverflow.com/questions/373142/what-techniques-can-be-used-to-speed-up-c-compilation-times

반응형