Nice programing

-O3 / -Ofast 이상의 G ++ 최적화

nicepro 2020. 12. 30. 20:21
반응형

-O3 / -Ofast 이상의 G ++ 최적화


문제

최적화가 필요한 시뮬레이션 작업을위한 중간 규모의 프로그램이 있습니다. 우리는 이미 GprofValgrind사용한 프로파일 링을 포함하여 프로그래밍 기술의 한계까지 소스를 최적화하는 데 최선을 다했습니다 .

마지막으로 완료되면 몇 달 동안 여러 시스템에서 프로그램을 실행하려고합니다. 따라서 우리는 최적화를 한계까지 밀어 붙이는 데 정말로 관심이 있습니다.

모든 시스템은 비교적 새로운 하드웨어 (Intel i5 또는 i7)에서 Debian / Linux를 실행합니다.

질문

-O3 / -Ofast를 넘어서는 최신 버전의 g ++를 사용하여 가능한 최적화 옵션은 무엇입니까?

우리는 또한 비용이 많이 드는 사소한 최적화에 관심이 있습니다.

지금 우리가 사용하는 것

지금은 다음과 같은 g ++ 최적화 옵션을 사용합니다.

  • -Ofast: 최고 "표준"최적화 수준. 포함 된 -ffast-math것은 계산에 문제를 일으키지 않았으므로 표준을 준수하지 않음에도 불구하고 그것을 사용하기로 결정했습니다.
  • -march=native: 모든 CPU 특정 명령 사용 가능.
  • -flto 여러 컴파일 단위에서 링크 시간 최적화를 허용합니다.

대부분의 답변은 다른 컴파일러 또는 외부 라이브러리와 같은 대체 솔루션을 제안하며 대부분의 경우 많은 재 작성 또는 통합 작업이 필요합니다. 나는 질문이 무엇을 요구하는지 고수하려고 노력할 것이며, OP의 요청에 따라 컴파일러 플래그를 활성화하거나 코드를 최소한으로 변경하여 GCC만으로 수행 할 수있는 작업에 집중할 것입니다. 이것은 "당신은 이것을해야한다"는 대답이 아니라, 저에게 잘 맞았고 당신의 특정한 상황과 관련이 있다면 시도해 볼 수있는 GCC 조정 모음입니다.


원래 질문에 대한 경고

세부 사항으로 들어가기 전에 질문에 대한 몇 가지 경고, 일반적으로 함께 올 사람들을 위해 질문을 읽고 "OP가 O3 이상으로 최적화되고 있습니다. 그와 동일한 플래그를 사용해야합니다!"라고 말합니다.

  • -march=native특정 CPU 아키텍처에 고유명령어를 사용할 수 있으며 다른 아키텍처에서 반드시 사용할 수있는 것은 아닙니다. 다른 CPU가있는 시스템에서 실행되는 경우 프로그램이 전혀 작동하지 않거나 상당히 느려질 수 있습니다 (이 또한 활성화 됨 mtune=native). 사용하기로 결정한 경우이 점에 유의 하십시오. 여기에 더 많은 정보가 있습니다 .
  • -Ofast언급했듯이 일부 비표준 준수 최적화를 가능하게하므로주의해서 사용해야합니다. 여기에 더 많은 정보가 있습니다 .

시도 할 다른 GCC 플래그

다른 플래그에 대한 세부 정보가 여기 에 나열 됩니다 .

  • -Ofast-ffast-math차례 가능하게하는, -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans-fcx-limited-range. 당신은 심지어 더 갈 수있는 부동 소수점 연산 최적화 선택적으로 일부 추가하여 여분의 플래그 와 같은 -fno-signed-zeros, -fno-trapping-math그리고 다른 사람을. 이는 -Ofast계산에 포함되지 않으며 추가 성능 향상을 제공 할 수 있지만 실제로 도움이되며 계산에 영향을주지 않는지 확인해야합니다.
  • GCC는 또한 "-O"옵션으로 활성화되지 않는 많은 다른 최적화 플래그 를 제공합니다. 이들은 "깨진 코드를 생성 할 수있는 실험적 옵션"으로 나열되어 있으므로주의해서 사용해야하며 정확성 및 벤치마킹 테스트를 통해 효과를 확인해야합니다. 그럼에도 불구하고 저는 자주 사용합니다 -frename-registers.이 옵션은 원치 않는 결과를 생성 한 적이 없으며 눈에 띄는 성능 향상을 제공하는 경향이 있습니다 (예 : 벤치마킹 할 때 측정 할 수 있음). 이것은 프로세서에 매우 의존하는 플래그 유형입니다. -funroll-loops또한 때때로 좋은 결과를 제공 -frename-registers하지만 (을 암시하기도 하지만) 실제 코드에 따라 다릅니다.

PGO

GCC에는 프로필 기반 최적화 기능이 있습니다. 이에 대한 정확한 GCC 문서는 많지 않지만 그럼에도 불구하고 실행하는 것은 매우 간단합니다.

  • 먼저 -fprofile-generate.
  • 프로그램을 실행 시키십시오 (코드가 프로필 정보를 .gcda 파일로 생성하므로 실행 시간이 상당히 느려집니다).
  • 프로그램을 -fprofile-use. 애플리케이션이 다중 스레드 인 경우 -fprofile-correction플래그 도 추가하십시오 .

GCC를 사용하는 PGO는 놀라운 결과를 제공하고 성능을 크게 향상시킬 수 있습니다 (최근 작업중인 프로젝트 중 하나에서 15-20 % 속도 증가를 보았습니다). 분명히 여기서 문제는 애플리케이션의 실행을 충분히 대표 할 수있는 일부 데이터 를 보유하는 것입니다 . 이는 항상 사용 가능하거나 확보하기 쉬운 것은 아닙니다.

GCC의 병렬 모드

GCC 는 GCC 4.2 컴파일러가 출시되었을 때 처음 출시 된 병렬 모드를 특징 으로합니다.

기본적으로 C ++ 표준 라이브러리에있는 여러 알고리즘의 병렬 구현을 제공합니다 . 전역 적으로 활성화하려면 컴파일러에 -fopenmp-D_GLIBCXX_PARALLEL플래그를 추가하기 만하면 됩니다. 필요한 경우 각 알고리즘을 선택적으로 활성화 할 수도 있지만 약간의 코드 변경이 필요합니다.

이 병렬 모드에 대한 모든 정보는 여기 에서 찾을 수 있습니다 .

대규모 데이터 구조에서 이러한 알고리즘을 자주 사용하고 많은 하드웨어 스레드 컨텍스트를 사용할 수있는 경우 이러한 병렬 구현은 성능을 크게 향상시킬 수 있습니다. sort지금까지 의 병렬 구현 만 사용 했지만 대략적인 아이디어를 제공하기 위해 내 응용 프로그램 중 하나에서 정렬하는 데 걸리는 시간을 14 초에서 4 초로 줄일 수있었습니다 (테스트 환경 : 사용자 지정 비교 기능이있는 1 억 개의 개체 벡터) 8 코어 머신).

추가 트릭

이전 포인트 섹션과 달리이 부분에서는 코드에서 약간의 변경필요합니다 . 또한 GCC에 따라 다르므로 (일부는 Clang에서도 작동 함) 컴파일 타임 매크로를 사용하여 코드를 다른 컴파일러에서 이식 가능한 상태로 유지해야합니다. 이 섹션에는 몇 가지 고급 기술이 포함되어 있으며, 무슨 일이 일어나고 있는지 어셈블리 수준을 이해하지 못하는 경우 사용해서는 안됩니다. 또한 프로세서와 컴파일러는 요즘 꽤 똑똑하기 때문에 여기에 설명 된 기능에서 눈에 띄는 이점을 얻는 것이 까다로울 수 있습니다.

  • 여기 에 나열된 GCC 내장 . 과 같은 __builtin_expect구문은 컴파일러가 분기 예측 정보를 제공하여 더 나은 최적화를 수행하도록 도울 수 있습니다 . 이와 같은 다른 구조 __builtin_prefetch는 데이터에 액세스하기 전에 캐시로 데이터를 가져 와서 캐시 누락을 줄이는 데 도움이 될 수 있습니다 .
  • 여기 에 나열된 기능 속성 . 특히 hotcold속성을 살펴 봐야 합니다. 전자는 해당 함수가 프로그램 핫스팟 임을 컴파일러에 알리고 더 적극적으로 함수를 최적화하고 더 나은 지역성을 위해 텍스트 섹션의 특수 하위 섹션에 배치합니다. 나중에 크기에 맞게 함수를 최적화하고 텍스트 섹션의 다른 특수 하위 섹션에 배치합니다.

이 답변이 일부 개발자에게 유용하다는 것이 입증되기를 바라며 모든 편집이나 제안을 기꺼이 고려할 것입니다.


비교적 새로운 하드웨어 (Intel i5 또는 i7)

인텔 컴파일러 및 고성능 라이브러리 사본에 투자하지 않으 시겠습니까? 일반적으로 10 %에서 30 % 또는 그 이상으로 최적화에서 GCC를 능가 할 수 있으며, 숫자를 많이 사용하는 프로그램의 경우 훨씬 더 그렇습니다. 또한 인텔은 고성능 번호 처리 (병렬) 응용 프로그램을위한 여러 확장 및 라이브러리를 제공합니다.이 경우 코드에 통합 할 수 있습니다. 몇 달의 실행 시간을 절약 할 수 있다면 큰 성과를 거둘 수 있습니다.

우리는 이미 프로그래밍 기술의 한계까지 소스를 최적화하는 데 최선을 다했습니다.

In my experience, the kind of micro- and nano- optimizations that you typically do with the help of a profiler tend to have a poor return on time-investments compared to macro-optimizations (streamlining the structure of the code) and, most importantly and often overlooked, memory access optimizations (e.g., locality of reference, in-order traversal, minimizing indirection, wielding out cache-misses, etc.). The latter usually involves designing the memory structures to better reflect the way the memory is used (traversed). Sometimes it can be as simple as switching a container type and getting a huge performance boost from that. Often, with profilers, you get lost in the details of the instruction-by-instruction optimizations, and memory layout issues don't show up and are usually missed when forgetting to look at the bigger picture. It's a much better way to invest your time, and the payoffs can be huge (e.g., many O(logN) algorithms end up performing almost as slow as O(N) just because of poor memory layouts (e.g., using a linked-list or linked-tree is a typical culprit of huge performance problems compared to a contiguous storage strategy)).


If you can afford it, try VTune. It provides MUCH more info than simple sampling (provided by gprof, as far as I know). You might give the Code Analyst a try. Latter is a decent, free software but it might not work correctly (or at all) with Intel CPUs.

Being equipped with such tool, it allows you to check various measure such as cache utilization (and basically memory layout), which - if used to its full extend - provides a huge boost to efficiency.

When you are sure that you algorithms and structures are optimal, then you should definitely use the multiple cores on i5 and i7. In other words, play around with different parallel programming algorithms/patterns and see if you can get a speed up.

When you have truly parallel data (array-like structures on which you perform similar/same operations) you should give OpenCL and SIMD instructions(easier to set up) a try.


huh, then final thing you may try: ACOVEA project: Analysis of Compiler Optimizations via an Evolutionary Algorithm -- as obvious from the description, it tries a genetic algorithm to pick the best compiler options for your project (doing compilation maaany times and check for timing, giving a feedback to the algorithm :) -- but results could be impressive! :)


Some notes about the currently chosen answer (I do not have enough reputation points yet to post this as a comment):

The answer says:

-fassociative-math, -freciprocal-math, -fno-signed-zeros, and -fno-trapping-math. These are not included in -Ofast and can give some additional performance increases on calculations

Perhaps this was true when the answer was posted, but the GCC documentation says that all of these are enabled by -funsafe-math-optimizations, which is enabled by -ffast-math, which is enabled by -Ofast. This can be checked with the command gcc -c -Q -Ofast --help=optimizer, which shows which optimizations are enabled by -Ofast, and confirms that all of these are enabled.

The answer also says:

other optimisation flags which aren't enabled by any "-O" options... -frename-registers

Again, the above command shows that, at least with my GCC 5.4.0, -frename-registers is enabled by default with -Ofast.


It is difficult to answer without further detail:

  • what type of number crunching?
  • what libraries are you using?
  • what degree of paralelization?

Can you write down the part of your code which takes the longest? (Typically a tight loop)

If you are CPU bound the answer will be different than if you are IO bound.

Again, please provide further detail.


I would recommend taking a look at the type of operations that costitute the heavy lifting, and look for an optimized library. There are quite a lot of fast, assembly optimized, SIMD vectorized libraries out there for common problems (mostly math). Reinventing the wheel is often tempting, but it is usually not worth the effort if an existing soltuion can cover your needs.Since you have not stated what sort of simulation it is I can only provide some examples.

http://www.yeppp.info/

http://eigen.tuxfamily.org/index.php?title=Main_Page

https://github.com/xianyi/OpenBLAS


with gcc intel turn of / implement -fno-gcse (works well on gfortran) and -fno-guess-branch-prbability (default in gfortran)

ReferenceURL : https://stackoverflow.com/questions/14492436/g-optimization-beyond-o3-ofast

반응형