μΉ΄ν…Œκ³ λ¦¬ 보관물: C++

C++

if… else if 문을 ν™•λ₯  적으둜 μ£Όλ¬Έν•˜λ©΄ μ–΄λ–€ νš¨κ³Όκ°€ μžˆμŠ΅λ‹ˆκΉŒ? something else if (somewhat_likely) //do something else

특히 일련의 if… else if문이 있고 각 문이 평가 ν•  μƒλŒ€ ν™•λ₯ μ„ 미리 μ•Œκ³  trueμžˆλ‹€λ©΄ ν™•λ₯  μˆœμ„œλŒ€λ‘œ μ •λ ¬ν•˜λŠ” 데 μ‹€ν–‰ μ‹œκ°„μ˜ 차이가 μ–Όλ§ˆλ‚˜λ©λ‹ˆκΉŒ? 예λ₯Ό λ“€μ–΄, 이것을 μ„ ν˜Έν•΄μ•Όν•©λ‹ˆκΉŒ?

if (highly_likely)
  //do something
else if (somewhat_likely)
  //do something
else if (unlikely)
  //do something

이에?:

if (unlikely)
  //do something
else if (somewhat_likely)
  //do something
else if (highly_likely)
  //do something

μ •λ ¬ 된 버전이 더 λΉ λ₯Ό 것 κ°™μ§€λ§Œ, κ°€λ…μ„±μ΄λ‚˜ λΆ€μž‘μš©μ˜ 쑴재λ₯Ό μœ„ν•΄ μ΅œμ ν™”λ˜μ§€ μ•Šμ€ μˆœμ„œλ‘œ μ£Όλ¬Έν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ‹€μ œλ‘œ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  λ•ŒκΉŒμ§€ CPUκ°€ λΆ„κΈ° μ˜ˆμΈ‘μ„ μ–Όλ§ˆλ‚˜ 잘 μˆ˜ν–‰ν•˜λŠ”μ§€ λ§ν•˜κΈ°λ„ μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ 이것을 μ‹€ν—˜ν•˜λŠ” κ³Όμ •μ—μ„œ νŠΉμ • 사둀에 λŒ€ν•œ λ‚΄ μžμ‹ μ˜ μ§ˆλ¬Έμ— λŒ€λ‹΅ν–ˆμ§€λ§Œ λ‹€λ₯Έ 의견 / 톡찰λ ₯도 λ“£κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

μ€‘μš” :이 μ§ˆλ¬Έμ€ ifν”„λ‘œκ·Έλž¨ λ™μž‘μ— λ‹€λ₯Έ 영ν–₯을주지 μ•ŠμœΌλ©΄ μ„œ 문을 μž„μ˜λ‘œ μž¬μ •λ ¬ ν•  수 μžˆλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€ . λ‚΄ λŒ€λ‹΅μ— λ”°λ₯΄λ©΄, μ„Έ κ°€μ§€ 쑰건뢀 ν…ŒμŠ€νŠΈλŠ” μƒν˜Έ 배타적이며 λΆ€μž‘μš©μ΄ μ—†μŠ΅λ‹ˆλ‹€. λΆ„λͺ…νžˆ, μ›ν•˜λŠ” 행동을 λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ μ§„μˆ μ„ μΌμ •ν•œ μˆœμ„œλ‘œ ν‰κ°€ν•΄μ•Όν•œλ‹€λ©΄ νš¨μœ¨μ„± λ¬Έμ œλŠ” λ¬Έμ œκ°€λœλ‹€.



λ‹΅λ³€

일반적으둜 λͺ¨λ“  인텔 CPUκ°€ ν¬μ›Œλ“œ 브랜치λ₯Ό 처음 λ³Ό λ•Œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” κ²ƒμœΌλ‘œ κ°„μ£Όν•˜λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. Godbolt의 μž‘μ—…μ„ μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€ .

κ·Έ ν›„, λΈŒλžœμΉ˜λŠ” 브랜치 예츑 μΊμ‹œλ‘œ λ“€μ–΄κ°€κ³ , 과거의 λΈŒλžœμΉ˜λŠ” μ˜ˆμΈ‘μ„ μ•Œλ¦¬κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.

λ”°λΌμ„œ κΈ΄λ°€ν•œ λ£¨ν”„μ—μ„œ 잘λͺ»λœ μˆœμ„œμ˜ 영ν–₯은 μƒλŒ€μ μœΌλ‘œ μž‘μŠ΅λ‹ˆλ‹€. 브랜치 μ˜ˆμΈ‘κΈ°λŠ” μ–΄λ–€ 브랜치 μ„ΈνŠΈκ°€ κ°€μž₯ κ°€λŠ₯성이 높은지 μ•Œκ²Œ 될 것이며 λ£¨ν”„μ—μ„œ μ‚¬μ†Œν•œ μ–‘μ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ©΄ μž‘μ€ 차이가 크게 μ¦κ°€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

일반적으둜 λŒ€λΆ€λΆ„μ˜ μ»΄νŒŒμΌλŸ¬λŠ” 기본적으둜 (λ‹€λ₯Έ μ΄μœ κ°€ μ—†μŒ) 생성 된 λ¨Έμ‹  μ½”λ“œλ₯Ό μ½”λ“œμ—μ„œ μ£Όλ¬Έν•œ 방식과 거의 λ™μΌν•˜κ²Œ μ£Όλ¬Έν•©λ‹ˆλ‹€. λ”°λΌμ„œ 문이 μ‹€νŒ¨ ν•  λ•Œ μ •λ°©ν–₯ λΆ„κΈ° 인 경우.

λ”°λΌμ„œ β€œμ²« 번째 λ§Œλ‚¨β€μ—μ„œ μ΅œμƒμ˜ λΆ„κΈ° μ˜ˆμΈ‘μ„ 얻을 κ°€λŠ₯성을 μ€„μ΄λŠ” μˆœμ„œλ‘œ λΆ„κΈ°λ₯Ό μ£Όλ¬Έν•΄μ•Όν•©λ‹ˆλ‹€.

일련의 쑰건에 걸쳐 μ—¬λŸ¬ 번 λ‹¨λ‹¨νžˆ 반볡되고 μ‚¬μ†Œν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 마이크둜 벀치 λ§ˆν¬λŠ” λͺ…λ Ή 수 λ“±μ˜ μž‘μ€ 영ν–₯으둜 인해 μƒλŒ€μ  λΆ„κΈ° 예츑 λ¬Έμ œμ—λŠ” 거의 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œμ΄ 경우 κ²½ν—˜ 법칙이 μ‹ λ’°ν•  수 μ—†μœΌλ―€λ‘œλ₯Ό ν”„λ‘œνŒŒμΌ λ§ν•΄μ•Όν•©λ‹ˆλ‹€ .

λ˜ν•œ 벑터화 및 기타 μ—¬λŸ¬ μ΅œμ ν™”κ°€ μž‘μ€ νƒ€μ΄νŠΈ 루프에 μ μš©λ©λ‹ˆλ‹€.

λ”°λΌμ„œ 일반적인 μ½”λ“œμ—μ„œ κ°€μž₯ κ°€λŠ₯성이 높은 μ½”λ“œλ₯Ό if블둝 내에 λ„£μœΌλ©΄ μΊμ‹œλ˜μ§€ μ•Šμ€ λΆ„κΈ° 예츑 λˆ„λ½μ΄ μ΅œμ†Œν™”λ©λ‹ˆλ‹€. 꽉 μ‘°μ΄λŠ” 경우 일반 κ·œμΉ™μ— 따라 μ‹œμž‘ν•˜μ‹­μ‹œμ˜€. 더 λ§Žμ€ 정보가 ν•„μš”ν•˜λ©΄ ν”„λ‘œνŒŒμΌ 링 μ΄μ™Έμ˜ 선택은 거의 μ—†μŠ΅λ‹ˆλ‹€.

일뢀 ν…ŒμŠ€νŠΈκ°€ λ‹€λ₯Έ ν…ŒμŠ€νŠΈλ³΄λ‹€ 훨씬 μ €λ ΄ν•˜λ©΄ λ‹Ήμ—°νžˆμ΄ λͺ¨λ“  것이 μ°½ λ°–μœΌλ‘œ λ‚˜μ˜΅λ‹ˆλ‹€.


λ‹΅λ³€

λ‚˜λŠ” 두 κ°€μ§€ λ‹€λ₯Έ if… else if블둝 의 μ‹€ν–‰ μ‹œκ°„μ„ μ •ν•˜κΈ° μœ„ν•΄ λ‹€μŒ ν…ŒμŠ€νŠΈλ₯Ό κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜λ‚˜λŠ” ν™•λ₯  μˆœμ„œλ‘œ μ •λ ¬λ˜κ³  λ‹€λ₯Έ ν•˜λ‚˜λŠ” μ—­μˆœμœΌλ‘œ μ •λ ¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

int main()
{
    long long sortedTime = 0;
    long long reverseTime = 0;

    for (int n = 0; n != 500; ++n)
    {
        //Generate a vector of 5000 random integers from 1 to 100
        random_device rnd_device;
        mt19937 rnd_engine(rnd_device());
        uniform_int_distribution<int> rnd_dist(1, 100);
        auto gen = std::bind(rnd_dist, rnd_engine);
        vector<int> rand_vec(5000);
        generate(begin(rand_vec), end(rand_vec), gen);

        volatile int nLow, nMid, nHigh;
        chrono::time_point<chrono::high_resolution_clock> start, end;

        //Sort the conditional statements in order of increasing likelyhood
        nLow = nMid = nHigh = 0;
        start = chrono::high_resolution_clock::now();
        for (int& i : rand_vec) {
            if (i >= 95) ++nHigh;               //Least likely branch
            else if (i < 20) ++nLow;
            else if (i >= 20 && i < 95) ++nMid; //Most likely branch
        }
        end = chrono::high_resolution_clock::now();
        reverseTime += chrono::duration_cast<chrono::nanoseconds>(end-start).count();

        //Sort the conditional statements in order of decreasing likelyhood
        nLow = nMid = nHigh = 0;
        start = chrono::high_resolution_clock::now();
        for (int& i : rand_vec) {
            if (i >= 20 && i < 95) ++nMid;  //Most likely branch
            else if (i < 20) ++nLow;
            else if (i >= 95) ++nHigh;      //Least likely branch
        }
        end = chrono::high_resolution_clock::now();
        sortedTime += chrono::duration_cast<chrono::nanoseconds>(end-start).count();

    }

    cout << "Percentage difference: " << 100 * (double(reverseTime) - double(sortedTime)) / double(sortedTime) << endl << endl;
}

/ O2와 ν•¨κ»˜ MSVC2017을 μ‚¬μš©ν•˜λ©΄ μ •λ ¬ 된 버전이 μ •λ ¬λ˜μ§€ μ•Šμ€ 버전보닀 μΌκ΄€λ˜κ²Œ μ•½ 28 % λΉ λ¦…λ‹ˆλ‹€. luk32의 μ˜κ²¬μ— 따라, λ‚˜λŠ” λ˜ν•œ 두 ν…ŒμŠ€νŠΈμ˜ μˆœμ„œλ₯Ό λ°”κΎΈμ–΄ λˆˆμ— λ„λŠ” 차이λ₯Ό λ§Œλ“­λ‹ˆλ‹€ (22 % λŒ€ 28 %). 이 μ½”λ“œλŠ” Intel Xeon E5-2697 v2의 Windows 7μ—μ„œ μ‹€ν–‰λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이것은 λ¬Όλ‘  λ¬Έμ œμ— 따라 λ‹€λ₯΄λ©° 결정적인 λ‹΅λ³€μœΌλ‘œ ν•΄μ„λ˜μ–΄μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€.


λ‹΅λ³€

λŒ€μƒ μ‹œμŠ€ν…œμ΄ μ‹€μ œλ‘œ 영ν–₯μ„λ°›λŠ” 것이 ν™•μ‹€ν•˜μ§€ μ•ŠμœΌλ©΄ μ•ˆλ©λ‹ˆλ‹€. 기본적으둜 가독성이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” λ‹Ήμ‹ μ˜ κ²°κ³Όλ₯Ό μ˜μ‹¬ν•©λ‹ˆλ‹€. 예제λ₯Ό μ•½κ°„ μˆ˜μ • ν–ˆμœΌλ―€λ‘œ 싀행을 μ·¨μ†Œν•˜λŠ” 것이 더 μ‰½μŠ΅λ‹ˆλ‹€. 였히렀 Ideone 은 μ—­μˆœμ΄ λΉ λ₯΄μ§€ 만 μΌκ΄€μ„±μžˆκ²Œ λ³΄μ—¬μ€λ‹ˆλ‹€. νŠΉμ • λ‹¬λ¦¬κΈ°μ—μ„œλ„ λ•Œλ•Œλ‘œ λ’€μ§‘μ–΄μ§‘λ‹ˆλ‹€. κ²°κ³Όκ°€ 결정적이지 μ•Šλ‹€κ³  λ§ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. 콜리 루 λŠ” μ‹€μ œ μ°¨μ΄λ„λ³΄κ³ ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‚˜μ€‘μ— λ‚΄ odroid xu4μ—μ„œ Exynos5422 CPUλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

ν˜„λŒ€ CPUμ—λŠ” λΆ„κΈ° μ˜ˆμΈ‘κΈ°κ°€ μžˆμŠ΅λ‹ˆλ‹€. 데이터와 λͺ…λ Ήμ–΄λ₯Ό λͺ¨λ‘ 프리 페치 (pre-fetch)ν•˜κΈ°μœ„ν•œ λ§Žμ€ 둜직이 있으며, μ΅œμ‹  x86 CPUλŠ” λ‹€μ†Œ λ˜‘λ˜‘ν•©λ‹ˆλ‹€. ARM λ˜λŠ” GPU와 같은 일뢀 슬림 μ•„ν‚€ν…μ²˜λŠ”μ΄ 취약점에 μ·¨μ•½ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ‹€μ œλ‘œ μ»΄νŒŒμΌλŸ¬μ™€ λŒ€μƒ μ‹œμŠ€ν…œμ— 크게 μ˜μ‘΄ν•©λ‹ˆλ‹€.

지점 μˆœμ„œ μ΅œμ ν™”λŠ” 맀우 μ·¨μ•½ν•˜κ³  μž„μ‹œμ μ΄λΌκ³  말할 수 μžˆμŠ΅λ‹ˆλ‹€. 정말 λ―Έμ„Έ μ‘°μ • λ‹¨κ³„λ‘œλ§Œ μˆ˜ν–‰ν•˜μ‹­μ‹œμ˜€.

μ•”ν˜Έ:

#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

int main()
{
    //Generate a vector of random integers from 1 to 100
    random_device rnd_device;
    mt19937 rnd_engine(rnd_device());
    uniform_int_distribution<int> rnd_dist(1, 100);
    auto gen = std::bind(rnd_dist, rnd_engine);
    vector<int> rand_vec(5000);
    generate(begin(rand_vec), end(rand_vec), gen);
    volatile int nLow, nMid, nHigh;

    //Count the number of values in each of three different ranges
    //Run the test a few times
    for (int n = 0; n != 10; ++n) {

        //Run the test again, but now sort the conditional statements in reverse-order of likelyhood
        {
          nLow = nMid = nHigh = 0;
          auto start = chrono::high_resolution_clock::now();
          for (int& i : rand_vec) {
              if (i >= 95) ++nHigh;               //Least likely branch
              else if (i < 20) ++nLow;
              else if (i >= 20 && i < 95) ++nMid; //Most likely branch
          }
          auto end = chrono::high_resolution_clock::now();
          cout << "Reverse-sorted: \t" << chrono::duration_cast<chrono::nanoseconds>(end-start).count() << "ns" << endl;
        }

        {
          //Sort the conditional statements in order of likelyhood
          nLow = nMid = nHigh = 0;
          auto start = chrono::high_resolution_clock::now();
          for (int& i : rand_vec) {
              if (i >= 20 && i < 95) ++nMid;  //Most likely branch
              else if (i < 20) ++nLow;
              else if (i >= 95) ++nHigh;      //Least likely branch
          }
          auto end = chrono::high_resolution_clock::now();
          cout << "Sorted:\t\t\t" << chrono::duration_cast<chrono::nanoseconds>(end-start).count() << "ns" << endl;
        }
        cout << endl;
    }
}

λ‹΅λ³€

κ·Έλƒ₯ λ‚΄ 5 μ„ΌνŠΈ. μ§„μˆ μ΄ λ‹€μŒμ— μ˜μ‘΄ν•΄μ•Όν•˜λŠ” 경우 주문의 νš¨κ³Όκ°€μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

  1. 각 if 문의 κ°€λŠ₯μ„±

  2. λΆ„κΈ° μ˜ˆμΈ‘μžκ°€ μ‹œμž‘ν•  μˆ˜μžˆλŠ” 반볡 νšŸμˆ˜μž…λ‹ˆλ‹€.

  3. μ½”λ“œ νžŒνŠΈμ™€ 같은 컴파일러 힌트

μ΄λŸ¬ν•œ μš”μ†Œλ₯Ό νƒμƒ‰ν•˜κΈ° μœ„ν•΄ λ‹€μŒ κΈ°λŠ₯을 λ²€μΉ˜λ§ˆν‚Ήν–ˆμŠ΅λ‹ˆλ‹€.

ordered_ifs ()

for (i = 0; i < data_sz * 1024; i++) {
    if (data[i] < check_point) // highly likely
        s += 3;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (data[i] == check_point) // very unlikely
        s += 1;
}

reversed_ifs ()

for (i = 0; i < data_sz * 1024; i++) {
    if (data[i] == check_point) // very unlikely
        s += 1;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (data[i] < check_point) // highly likely
        s += 3;
}

ordered_ifs_with_hints ()

for (i = 0; i < data_sz * 1024; i++) {
    if (likely(data[i] < check_point)) // highly likely
        s += 3;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (unlikely(data[i] == check_point)) // very unlikely
        s += 1;
}

reversed_ifs_with_hints ()

for (i = 0; i < data_sz * 1024; i++) {
    if (unlikely(data[i] == check_point)) // very unlikely
        s += 1;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (likely(data[i] < check_point)) // highly likely
        s += 3;
}

데이터

데이터 배열은 0μ—μ„œ 100 μ‚¬μ΄μ˜ λ‚œμˆ˜λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

const int RANGE_MAX = 100;
uint8_t data[DATA_MAX * 1024];

static void data_init(int data_sz)
{
    int i;
        srand(0);
    for (i = 0; i < data_sz * 1024; i++)
        data[i] = rand() % RANGE_MAX;
}

κ²°κ³Ό

λ‹€μŒ κ²°κ³ΌλŠ” Intel i5 @ 3,2 GHz 및 G ++ 6.3.0에 λŒ€ν•œ κ²ƒμž…λ‹ˆλ‹€. 첫 번째 μΈμˆ˜λŠ” check_point (즉, κ°€λŠ₯성이 높은 if 문의 경우 %% ν™•λ₯ )이고 두 번째 μΈμˆ˜λŠ” data_sz (예 : 반볡 횟수)μž…λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/50/8                   25636 ns      25635 ns      27852
ordered_ifs/75/4                    4326 ns       4325 ns     162613
ordered_ifs/75/8                   18242 ns      18242 ns      37931
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs/100/8                   3381 ns       3381 ns     207612
reversed_ifs/50/4                   5342 ns       5341 ns     126800
reversed_ifs/50/8                  26050 ns      26050 ns      26894
reversed_ifs/75/4                   3616 ns       3616 ns     193130
reversed_ifs/75/8                  15697 ns      15696 ns      44618
reversed_ifs/100/4                  3738 ns       3738 ns     188087
reversed_ifs/100/8                  7476 ns       7476 ns      93752
ordered_ifs_with_hints/50/4         5551 ns       5551 ns     125160
ordered_ifs_with_hints/50/8        23191 ns      23190 ns      30028
ordered_ifs_with_hints/75/4         3165 ns       3165 ns     218492
ordered_ifs_with_hints/75/8        13785 ns      13785 ns      50574
ordered_ifs_with_hints/100/4        1575 ns       1575 ns     437687
ordered_ifs_with_hints/100/8        3130 ns       3130 ns     221205
reversed_ifs_with_hints/50/4        6573 ns       6572 ns     105629
reversed_ifs_with_hints/50/8       27351 ns      27351 ns      25568
reversed_ifs_with_hints/75/4        3537 ns       3537 ns     197470
reversed_ifs_with_hints/75/8       16130 ns      16130 ns      43279
reversed_ifs_with_hints/100/4       3737 ns       3737 ns     187583
reversed_ifs_with_hints/100/8       7446 ns       7446 ns      93782

뢄석

1. 주문이 μ€‘μš”ν•˜λ‹€

4K 반볡과 (거의) 100 % ν™•λ₯ λ‘œ μ„ ν˜Έλ„κ°€ 높은 μ§„μˆ μ˜ 경우 κ·Έ μ°¨μ΄λŠ” 223 %에 λ‹¬ν•©λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/100/4                   1673 ns       1673 ns     417073
reversed_ifs/100/4                  3738 ns       3738 ns     188087

4K 반볡 및 μ„ ν˜Έλ„κ°€ 높은 50 % ν™•λ₯ μ˜ 경우 μ°¨μ΄λŠ” μ•½ 14 %μž…λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
reversed_ifs/50/4                   5342 ns       5341 ns     126800

2. 반볡 νšŸμˆ˜κ°€ μ€‘μš”

맀우 μ’‹μ•„ν•˜λŠ” μ§„μˆ μ˜ (거의) 100 % ν™•λ₯ μ— λŒ€ν•œ 4K와 8K 반볡의 μ°¨μ΄λŠ” (μ˜ˆμƒλŒ€λ‘œ) μ•½ 2 λ°°μž…λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs/100/8                   3381 ns       3381 ns     207612

κ·ΈλŸ¬λ‚˜ μ„ ν˜Έλ„κ°€ 높은 λ¬Έμž₯의 50 % ν™•λ₯ μ— λŒ€ν•œ 4K와 8K 반볡의 μ°¨μ΄λŠ” 5,5 λ°°μž…λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/50/8                   25636 ns      25635 ns      27852

μ™œ κ·Έλ ‡μŠ΅λ‹ˆκΉŒ? λΆ„κΈ° 예츑 λ³€μˆ˜κ°€ λˆ„λ½λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μœ„μ—μ„œ μ–ΈκΈ‰ ν•œ 각 사둀에 λŒ€ν•œ λΆ„κΈ° λˆ„λ½μ΄ μžˆμŠ΅λ‹ˆλ‹€.

ordered_ifs/100/4    0.01% of branch-misses
ordered_ifs/100/8    0.01% of branch-misses
ordered_ifs/50/4     3.18% of branch-misses
ordered_ifs/50/8     15.22% of branch-misses

λ”°λΌμ„œ i5μ—μ„œ 브랜치 μ˜ˆμΈ‘κΈ°λŠ” κ·Έλ ‡κ²Œ 크지 μ•Šμ€ 브랜치 및 λŒ€κ·œλͺ¨ 데이터 μ„ΈνŠΈμ— λŒ€ν•΄ λ†€λžλ„λ‘ μ‹€νŒ¨ν•©λ‹ˆλ‹€.

힌트 힌트

4K 반볡의 경우 κ²°κ³ΌλŠ” 50 % ν™•λ₯ μ—μ„œλŠ” λ‹€μ†Œ λ‚˜μ˜κ³  100 % ν™•λ₯ μ— λŒ€ν•΄μ„œλŠ” λ‹€μ†Œ λ‚˜μ•„μ§‘λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs_with_hints/50/4         5551 ns       5551 ns     125160
ordered_ifs_with_hints/100/4        1575 ns       1575 ns     437687

κ·ΈλŸ¬λ‚˜ 8K 반볡의 경우 κ²°κ³Όκ°€ 항상 쑰금 더 μ’‹μŠ΅λ‹ˆλ‹€.

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/8                   25636 ns      25635 ns      27852
ordered_ifs/100/8                   3381 ns       3381 ns     207612
ordered_ifs_with_hints/50/8        23191 ns      23190 ns      30028
ordered_ifs_with_hints/100/8        3130 ns       3130 ns     221205

λ”°λΌμ„œ νžŒνŠΈλ„ λ„μ›€μ΄λ˜μ§€λ§Œ 쑰금만 λ„μ›€μ΄λ©λ‹ˆλ‹€.

결둠은 항상 μ½”λ“œλ₯Ό λ²€μΉ˜λ§ˆν‚Ήν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. κ²°κ³ΌλŠ” 놀라 울 수 μžˆμŠ΅λ‹ˆλ‹€.

희망이 λ„μ›€μ΄λ©λ‹ˆλ‹€.


λ‹΅λ³€

μœ μΌν•œ μ§„μ§œ 닡이 같이 여기에 λ‹€λ₯Έ λͺ‡ κ°€μ§€ 닡변을 λ°”νƒ•μœΌλ‘œ, 그것은 λ³Έλ‹€ : 그것은 μ˜μ‘΄ν•œλ‹€ . 그것은 적어도 λ‹€μŒμ— 달렀 μžˆμŠ΅λ‹ˆλ‹€ (κ·ΈλŸ¬λ‚˜μ΄ μˆœμ„œλŒ€λ‘œ μ€‘μš”ν•˜μ§€λŠ” μ•Šμ§€λ§Œ).

  • 각 μ§€μ μ˜ μƒλŒ€ ν™•λ₯ . 이것은 μ›λž˜ μ§ˆλ¬Έμž…λ‹ˆλ‹€. 기쑴의 닡변을 λ°”νƒ•μœΌλ‘œ ν™•λ₯  순으둜 μ •λ ¬ν•˜λŠ” 데 λ„μ›€μ΄λ˜λŠ” λͺ‡ κ°€μ§€ μ‘°κ±΄μ΄μžˆλŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄μ§€λ§Œ 항상 κ·Έλ ‡μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. μƒλŒ€ ν™•λ₯ μ΄ 크게 λ‹€λ₯΄μ§€ μ•Šμ€ 경우 μˆœμ„œκ°€ μ–΄λ–€ μˆœμ„œλ‘œλ“  차이가 λ‚˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 첫 번째 쑰건이 99.999 %의 μ‹œκ°„μ— λ°œμƒν•˜κ³  λ‹€μŒ 쑰건이 남은 κ²ƒμ˜ 일뢀인 κ²½μš°μ—λŠ” κ°€μž₯ κ°€λŠ₯성이 높은 것을 λ¨Όμ € λ°°μΉ˜ν•˜λŠ” 것이 타이밍 μΈ‘λ©΄μ—μ„œ μœ λ¦¬ν•˜λ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€.
  • 각 λΈŒλžœμΉ˜μ— λŒ€ν•œ μ°Έ / κ±°μ§“ 쑰건 계산 λΉ„μš©. 쑰건을 ν…ŒμŠ€νŠΈν•˜λŠ” 데 λ“œλŠ” μ‹œκ°„ λΉ„μš©μ΄ ν•œ μ§€μ μ—μ„œ λ‹€λ₯Έ 지점에 λΉ„ν•΄ μ‹€μ œλ‘œ 높은 경우 μ΄λŠ” 타이밍과 νš¨μœ¨μ„±μ— 큰 영ν–₯을 쀄 수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, κ³„μ‚°ν•˜λŠ” 데 1 μ‹œκ°„ λ‹¨μœ„ (예 : λΆ€μšΈ λ³€μˆ˜μ˜ μƒνƒœ 확인)κ°€ κ±Έλ¦¬λŠ” 쑰건과 κ³„μ‚°ν•˜λŠ” 데 μˆ˜μ‹­, 수백, 수천 λ˜λŠ” 심지어 수백만 μ‹œκ°„ λ‹¨μœ„κ°€ ν•„μš”ν•œ λ‹€λ₯Έ 쑰건 (예 : λ””μŠ€ν¬μƒμ˜ 파일 λ˜λŠ” λŒ€κ·œλͺ¨ λ°μ΄ν„°λ² μ΄μŠ€μ— λŒ€ν•œ λ³΅μž‘ν•œ SQL 쿼리 μˆ˜ν–‰). μ½”λ“œκ°€ 맀번 μˆœμ„œλŒ€λ‘œ 쑰건을 ν™•μΈν•œλ‹€κ³  κ°€μ •ν•˜λ©΄ 더 λΉ λ₯Έ 쑰건이 λ¨Όμ €λ˜μ–΄μ•Όν•©λ‹ˆλ‹€ (λ¨Όμ € μ‹€νŒ¨ν•œ λ‹€λ₯Έ 쑰건에 μ’…μ†λ˜μ§€ μ•ŠλŠ” ν•œ).
  • 컴파일러 / 인터프리터 일뢀 컴파일러 (λ˜λŠ” 인터프리터)μ—λŠ” μ„±λŠ₯에 영ν–₯을 쀄 μˆ˜μžˆλŠ” λ‹€λ₯Έ μ’…λ₯˜μ˜ μ΅œμ ν™”κ°€ 포함될 수 μžˆμŠ΅λ‹ˆλ‹€ (일뢀 μ˜΅μ…˜μ€ 컴파일 및 / λ˜λŠ” μ‹€ν–‰ 쀑에 νŠΉμ • μ˜΅μ…˜μ„ μ„ νƒν•œ κ²½μš°μ—λ§Œ λ‚˜νƒ€λ‚¨). λ”°λΌμ„œ λ™μΌν•œ λΆ„κΈ°λ₯Ό μ •ν™•νžˆ λ™μΌν•œ 컴파일러λ₯Ό μ‚¬μš©ν•˜μ—¬ λ™μΌν•œ μ‹œμŠ€ν…œμ—μ„œ 두 개의 컴파일 및 달리 λ™μΌν•œ μ½”λ“œμ˜ 싀행을 λ²€μΉ˜λ§ˆν‚Ήν•˜μ§€ μ•ŠλŠ” ν•œ μœ μΌν•œ 차이점은 컴파일러 λ³€ν˜•μ— λŒ€ν•œ μ•½κ°„μ˜ μ—¬μœ λ₯Ό μ£Όμ–΄μ•Όν•©λ‹ˆλ‹€.
  • 운영 체제 / ν•˜λ“œμ›¨μ–΄ luk32 및 Yakkμ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ λ‹€μ–‘ν•œ CPUμ—λŠ” 운영 μ²΄μ œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 자체 μ΅œμ ν™” κΈ°λŠ₯이 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 벀치 λ§ˆν¬λŠ” μ—¬κΈ°μ„œλ„ λ³€ν˜•λ˜κΈ° μ‰½μŠ΅λ‹ˆλ‹€.
  • μ½”λ“œ 블둝 μ‹€ν–‰ λΉˆλ„ λΆ„κΈ°λ₯Ό ν¬ν•¨ν•˜λŠ” 블둝에 거의 μ•‘μ„ΈμŠ€ν•˜μ§€ μ•ŠλŠ” 경우 (예 : μ‹œμž‘ 쀑 ν•œ 번만) λΆ„κΈ°λ₯Ό λ°°μΉ˜ν•˜λŠ” μˆœμ„œλŠ” 거의 μ€‘μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ ν•œνŽΈμœΌλ‘œ, μ½”λ“œμ˜ μ€‘μš”ν•œ λΆ€λΆ„μ—μ„œ μ½”λ“œκ°€μ΄ μ½”λ“œ 블둝을 λ§μΉ˜λŠ” 경우 벀치 λ§ˆν¬μ— 따라 μˆœμ„œκ°€ μ€‘μš” ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν™•μ‹€ν•˜κ²Œ μ•Œ μˆ˜μžˆλŠ” μœ μΌν•œ 방법은 μ½”λ“œλ₯Ό μ΅œμ’…μ μœΌλ‘œ μ‹€ν–‰ν•  μ˜λ„ 된 μ‹œμŠ€ν…œκ³Ό λ™μΌν•˜κ±°λ‚˜ 맀우 μœ μ‚¬ν•œ μ‹œμŠ€ν…œμ—μ„œ νŠΉμ • 사둀λ₯Ό λ²€μΉ˜λ§ˆν‚Ήν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. ν•˜λ“œμ›¨μ–΄, 운영 체제 등이 λ‹€λ₯Έ λ‹€μ–‘ν•œ μ‹œμŠ€ν…œμ—μ„œ μ‹€ν–‰ν•˜λ €λŠ” 경우 μ—¬λŸ¬ λ³€ν˜•μ„ 벀치 λ§ˆν¬ν•˜μ—¬ μ–΄λŠ 것이 κ°€μž₯ μ ν•©ν•œ μ§€ ν™•μΈν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. ν•œ μœ ν˜•μ˜ μ‹œμŠ€ν…œμ—μ„œλŠ” ν•˜λ‚˜μ˜ μˆœμ„œλ‘œ, λ‹€λ₯Έ μœ ν˜•μ˜ μ‹œμŠ€ν…œμ—μ„œλŠ” λ‹€λ₯Έ μˆœμ„œλ‘œ μ½”λ“œλ₯Ό μ»΄νŒŒμΌν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‚΄ 개인적인 κ²½ν—˜ κ·œμΉ™ (λŒ€λΆ€λΆ„μ˜ 경우 벀치 λ§ˆν¬κ°€μ—†λŠ” 경우)은 λ‹€μŒμ„ κΈ°μ€€μœΌλ‘œ μ£Όλ¬Έν•΄μ•Όν•©λ‹ˆλ‹€.

  1. 이전 쑰건의 결과에 μ˜μ‘΄ν•˜λŠ” 쑰건
  2. 쑰건 계산 λΉ„μš©
  3. 각 μ§€μ μ˜ μƒλŒ€ ν™•λ₯ .

λ‹΅λ³€

ν•„μžκ°€ 일반적으둜 κ³ μ„±λŠ₯ μ½”λ“œμ— λŒ€ν•΄μ΄ 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법은 κ°€μž₯ 읽기 μ‰¬μš΄ μˆœμ„œλ₯Ό μœ μ§€ν•˜μ§€λ§Œ μ»΄νŒŒμΌλŸ¬μ— 힌트λ₯Ό μ œκ³΅ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ‹€μŒμ€ Linux μ»€λ„μ˜ ν•œ μ˜ˆμž…λ‹ˆλ‹€ .

if (likely(access_ok(VERIFY_READ, from, n))) {
    kasan_check_write(to, n);
    res = raw_copy_from_user(to, from, n);
}
if (unlikely(res))
    memset(to + (n - res), 0, res);

μ—¬κΈ°μ„œλŠ” μ•‘μ„ΈμŠ€ 확인이 ν†΅κ³Όλ˜κ³ μ— 였λ₯˜κ°€ λ°˜ν™˜λ˜μ§€ μ•ŠλŠ”λ‹€κ³  κ°€μ • resν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ if 절 쀑 ν•˜λ‚˜λ₯Ό μž¬μ •λ ¬ν•˜λ €κ³ ν•˜λ©΄ μ½”λ“œκ°€ ν˜Όλ™ 될 수 μžˆμ§€λ§Œ, 맀크둜 likely()와 unlikely()λ§€ν¬λ‘œλŠ” μ‹€μ œλ‘œ 정상적인 κ²½μš°μ™€ μ˜ˆμ™ΈλŠ” 무엇인지 μ§€μ ν•¨μœΌλ‘œμ¨ 가독성을 ν–₯μƒμ‹œν‚΅λ‹ˆλ‹€.

μ΄λŸ¬ν•œ 맀크둜의 Linux κ΅¬ν˜„μ€ GCC νŠΉμ • κΈ°λŠ₯을 μ‚¬μš© ν•©λ‹ˆλ‹€ . clangκ³Ό Intel C μ»΄νŒŒμΌλŸ¬λŠ” λ™μΌν•œ ꡬ문을 μ§€μ›ν•˜λŠ” κ²ƒμœΌλ‘œ λ³΄μ΄μ§€λ§Œ MSVCμ—λŠ” κ·ΈλŸ¬ν•œ κΈ°λŠ₯이 μ—†μŠ΅λ‹ˆλ‹€ .


λ‹΅λ³€

λ˜ν•œ μ»΄νŒŒμΌλŸ¬μ™€ μ»΄νŒŒμΌν•˜λŠ” ν”Œλž«νΌμ— 따라 λ‹€λ¦…λ‹ˆλ‹€.

이둠적으둜 κ°€μž₯ κ°€λŠ₯성이 높은 쑰건은 μ œμ–΄ 점프λ₯Ό κ°€λŠ₯ν•œ ν•œ μ κ²Œν•΄μ•Όν•©λ‹ˆλ‹€.

일반적으둜 κ°€μž₯ κ°€λŠ₯성이 높은 쑰건은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

if (most_likely) {
     // most likely instructions
} else …

κ°€μž₯ μΈκΈ°μžˆλŠ” asm은 condition이 true 일 λ•Œ μ ν”„ν•˜λŠ” 쑰건뢀 λΆ„κΈ°λ₯Ό 기반으둜 ν•©λ‹ˆλ‹€ . κ·Έ C μ½”λ“œλŠ” λ‹€μŒκ³Ό 같은 μ˜μ‚¬ asm으둜 λ³€ν™˜ 될 κ²ƒμž…λ‹ˆλ‹€.

jump to ELSE if not(most_likely)
// most likely instructions
jump to end
ELSE:
…

이것은 점프가 CPUκ°€ μ‹€ν–‰ νŒŒμ΄ν”„ 라인을 μ·¨μ†Œν•˜κ³  ν”„λ‘œκ·Έλž¨ μΉ΄μš΄ν„°κ°€ λ³€κ²½ λ˜μ—ˆκΈ° λ•Œλ¬Έμ— μ€‘λ‹¨λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€ (μ‹€μ œλ‘œλŠ” νŒŒμ΄ν”„ 라인을 μ§€μ›ν•˜λŠ” μ•„ν‚€ν…μ²˜μ˜ 경우). 그런 λ‹€μŒ μ»΄νŒŒμΌλŸ¬μ— κ΄€ν•œ 것인데, μ΄λŠ” 컨트둀이 덜 μ ν”„ν•˜λ„λ‘ ν†΅κ³„μ μœΌλ‘œ κ°€μž₯ κ°€λŠ₯성이 높은 쑰건을 κ°–λŠ” 것에 λŒ€ν•œ μ •κ΅ν•œ μ΅œμ ν™”λ₯Ό μ μš©ν•˜κ±°λ‚˜ μ μš©ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.


이 글은 C++ μΉ΄ν…Œκ³ λ¦¬λ‘œ λΆ„λ₯˜λ˜μ—ˆκ³  λ‹˜μ— μ˜ν•΄ 에 μž‘μ„±λμŠ΅λ‹ˆλ‹€.