본문 바로가기
Language/C++최적화

C++최적화 (2단원)

by y.j 2021. 9. 21.
728x90

2. 컴퓨터 하드웨어의 최적화

 - 왜 최적화가 필요한지 알 수 있다.

 - 프로세서의 구조를 통해서 어떤 방법으로 최적화해야 하는지 유추하는 방법을 알아봄.

 

  C++은 컴퓨터의 거짓말을 믿습니다.

  • C++ 프로그램은 '마치' 명령문을 순서대로 실행하는 것처럼 작동하기만 하면 됩니다.
  • C++ 컴파일러와 컴퓨터 자체는 계산의 의미가 변경되지 않은 선에서 실행순서를 변경하여
  • 프로그램 실행을 빠르게 할 수도 있습니다.

  C++11부터는 단일 실행 주소만 있다고 믿지 않습니다.

  • 이제 C++표준 라이브러리는 스레들 시작 및 중지하고 스레드 간에 메모리 접근을 동기화하는 기능을 제공한다.
  • 특정 메모리 주소는 일반 메모리가 아닌 장치 레지스터가 될 수 있다.
  • 동일한 스레드가 두 번 연속해서 읽는 사이에 변할 수 있으며,이는 하드웨어에 일부 변경이 있었음을 나타낸다.
  • C++에서는 이러한 위치를 volatile로 나타내어 최적화하는 대신 컴파일러가 변수의 새 복사본을 가져온다.

       * volatile 레지스터 참조 변수

  

  C++11 std::atomic<>이라는 마법 주문을 제공합니다.

  • std::atomic<>은 메모리를 잠시 동안 마치 단순한 선형 바이트 저장소인 것처럼 작동하게 만들고,
  • 멀티스레드 실행, 멀티 레이어 메모리 캐시 등으로 현대 마이크로프로세서의 모든 복잡성을 제거하려고 한다.

      *voliatile이 하고 있는 일은 아닙니다.

 

   운영체제도 프로그램과 사용자에게 거짓말을 합니다.

  • 실제로 운영체제의 모든 목적은 각 프로그램에게 납득할 거짓말을 하는 것입니다.
       1. 프로그램이 컴퓨터에서 단독으로 사용되고,    
       2. 물리 메모리는 무한하며,
       3. 프로그램의 스레드를 실행 할 수 있는 프로세서가 무한이다.
  • 이러한 거짓말은 프로그램을 느리게 실행할 때를 제외하고는 큰 영향을 미치지 않는다.

   컴퓨터의 진실

  •   메모리는 느립니다.
    1. 메인 메모리는 마이크로프로세서에 있는 게이트와 레지스터보다 매우 느리다.
    2. 메모리에 접근하는 비용은 프로세서의 다른 비용들을 압도한다.
     * 폰노이만 현상
       - 메모리와 CPU사이에 BUS가 하나이면서 순차적으로 정보를 처리하기 때문에 성능에 제한이 걸린다.

       *  BUS메모리와 CPU사이의 연결 통로

 

  • 메모리는 워드 단위로 접근합니다.

      1. 정렬되지 않은 메모리 접근의 단점 :

     C++에서 int, double, 포인터처럼 여러 바이트를 갖는 자료형을 가져 올 때,
     해당 데이터를 구성하는 바이트가 실제 메모리에서는 두 워드에 걸쳐 있을 수 있다.

     정렬되지 않은 접근은 모든 바이트가 같은 워드에 있을 때보다 시간이 2배로 걸린다.

     2 .정렬된 메모리 접근의 단점 :

     사용하지 않는 데이터가 구조체에 포함될 수 있다.
  • 메모리마다 접근 속도가 다르다.

      1. 메모리 마다 속도가 다르고 어떤 컴퓨터는 캐시 메모리가 여러단계로 이루어져 있다.

             * 캐시메모리도 10배 이상 속도차이가 날 수 있다.

 

        2. 캐시메모리는 빠를수록 용량이 적기 때문에 실행유닛에서

             캐시에 없는 데이터를 가져와야 하는 경우에 현재 캐시에 있는 데이터 중 일부를 삭제해야 합니다.

 

        3. 1바이트만 읽어도 근처에 있는 바이트가 함께 캐싱            

            이러한 정책은 적게 사용하는 메모리 위치보다 많이 사용하는 메모리 위치에 더 빠르게 접근할 수 있다.

                인접한 위치의 메모리가 멀리 떨어진 곳의 메모리보다(평균적으로) 더 빨리 접근 가능

                 ex) 반복문 코드 블록에 사용된다.

                 ex) if문은 코드 블록이 서로 근처에 있지 않기 때문에 오래 걸린다.

 

      4. 워드를 저장하는 방법에는 빅 엔디언과 리틀 엔디언이 있다.

         메모리를 할당 할 때, 첫 번째 바이트를 최상위 비트로 정할 것인가? 최하위 비트로 정할 것인가?

           * 빅 엔디언 : 최상위 비트로 정함

           * 리틀 엔디언 : 최하위 비트로 정함

          디스크와 네트워크는 한 번에 1바이트 씩 보내기 때문에

          데이터를 디스크에 기록하거나 네트워크를 통해 전송할 때 중요하다.

            * 보내는 컴퓨터와 받는 컴퓨터의 엔디언이 일치하지 않으면 서로 다른 값을 받게 됨

  

      5. 메모리는 한정된 자원이며 캐시메모리의 부족으로 가상메모리를 사용하게 된다.

         가상메모리가 캐시메모리 보다 크다.

          * 가상메모리는 디스크에서 블록을 검색하는데 수십 밀리초가 걸린다.

         여러 메모리 위치에서 분산 접근을 하는 경우 캐시메모리에 데이터가 없을 수 있다.

         * 페이지 스레싱이 일어난다.

         * 페이지 스레싱 : CPU보다 페이지폴드로 처리하는데 시간을 다 할애하는 것

 

     6. 명령 실행은 느리다.

        파이프라인이 복잡해질수록 명령들을 한꺼번에 처리 할 수 있지만,

        명령 A가 명령 B에 필요한 값을 계산다한다고 하면, 명령 A가 완료될 때까지 멈출 수 밖에 없게 된다.

 

     7. 컴퓨터는 의사 결정을 잘 하지 못합니다.

        실행의 흐름을 변경하는 명령(점프, 함수호출 ..)을 처리하는 동안 실행주소가 갱신될 때까지

        메모리에서 잠시 동안 읽을 수 없고, 파이프라인에 놓일 수 없다.

         * 계산이 의사결정보다 빠르다.

 

     8. 프로그램 실행에는 여러 스트림이 있습니다.

       운영체제는 디스크, 인터페이스, 사운드 등 여러가지 장치와 연결되어 있고, 자원을 사용하기 위해 서로 경쟁한다.

       콘테스트 스위칭이 일어나고 상당한 비용이 든다.

 

     9. 운영체제 기능을 호출하는 비용은 높습니다.

        시스템 호출 비용이 프로그램 내에 함수 호출비용보다 훨씬 더 크다.

 

   C++도 거짓말을 합니다.

  • 구조체를 전체를 복사하는데, 단순히 멤버 변수만 복사하면 된다고 생각하지만 복잡한 임의의 식이 정해질 수 있다.

    * 문장의 형태만으로는 비용이 얼마나 드는 알 수 없다.

  •    문장은 순서대로 실행되지 않습니다.
  •    컴파일러는 성능을 향상하려고 내부에서 문장을 재정렬하고 때로는 순서를 변경한다.
  •    컴파일러는 다중 스레드를 고려하지 않기 때문에 명시적인 동기화 코드를 추가개햐 한다.
  •    동기화 코드는 동시에 실행 될 수 있는 스레드가 데이터를 공유함으로써 얻을 수 있는 동시성의 양을 줄입니다.
728x90

'Language > C++최적화' 카테고리의 다른 글

C++최적화 (1단원)  (0) 2021.09.17

댓글