Замена оператора IF (случайное условие) на логическую логику - время выполнения идентично?

0

(Настройка: Win 7 64, MSVC, 3-го поколения Core i7, 64-разрядное соединение, -O2 включено)

В приведенном ниже коде три functions- имеет оператор IF, который выполняет другой код в зависимости от того, выполнено ли условие. Я заменил этот оператор IF некоторой логической логикой. Однако тайминги идентичны.... Я ожидал, что отсутствие предсказания ветвления приведет к более быстрому коду:

#include <iostream>

unsigned long long iterations = 1000000000;

void test1(){
    volatile int c = 0;

    for(int i=0; i<iterations; i++){
        bool condition = __rdtsc() % 2 == 0;
        if(condition){
            c = 4;
        }
        else{
            c = 5;
        }
    }
}

void test2(){
    volatile int c = 0;

    for(int i=0; i<iterations; i++){
        bool condition = __rdtsc() % 2 == 0;
        c = (4 * condition) + (5 * !condition);
    }
}

int main(){
    unsigned long long s = 0;
    unsigned long long f = 0;
    unsigned long long s2 = 0;
    unsigned long long f2 = 0;
    unsigned int x = 0;
    unsigned int y = 0;

    start = __rdtscp(&x);
    test1();
    finish = __rdtscp(&y);

    start2 = __rdtscp(&x);
    test2();
    finish2 = __rdtscp(&y);

    std::cout << "1: " << f - s<< std::endl;
    std::cout << "2: " << f2- s2<< std::endl;
}

UPDATE asm:

int main(){
 push        rbp  
 push        rsi  
 push        rdi  
 push        r14  
 sub         rsp,20h  
    unsigned long long start = 0;
    unsigned long long finish = 0;
    unsigned long long start2 = 0;
    unsigned long long finish2 = 0;
    unsigned long long start3 = 0;
    unsigned long long finish3 = 0;
    unsigned int x = 0;
 xor         r8d,r8d  
 mov         dword ptr [x],r8d  
    unsigned int y = 0;
 mov         dword ptr [y],r8d  

    start = __rdtscp(&x);
 rdtscp  
 lea         r9,[x]  
 shl         rdx,20h  
 mov         dword ptr [r9],ecx  
 or          rax,rdx  
    test1();
 mov         dword ptr [rsp+60h],r8d  
 mov         ecx,r8d  

    start = __rdtscp(&x);
 mov         r10,rax  
 nop         word ptr [rax+rax]  
    test1();
 rdtsc  
 shl         rdx,20h  
 or          rax,rdx  
 xor         al,0FFh  
 and         al,1  
 neg         al  
 sbb         eax,eax  
 inc         ecx  
 add         eax,5  
 mov         dword ptr [rsp+60h],eax  
 movsxd      rax,ecx  
 cmp         rax,3E8h  
    test1();
 jb          main+40h (013FFE1280h)  
    finish = __rdtscp(&y);
 rdtscp  
 lea         r9,[y]  
 shl         rdx,20h  
 or          rax,rdx  
 mov         dword ptr [r9],ecx  
 mov         rbp,rax  

    start2 = __rdtscp(&x);
 rdtscp  
 lea         r9,[x]  
 shl         rdx,20h  
 mov         dword ptr [r9],ecx  
 or          rax,rdx  
    test2();
 mov         dword ptr [rsp+60h],r8d  
 mov         r9d,r8d  

    start2 = __rdtscp(&x);
 mov         r14,rax  
 nop         word ptr [rax+rax]  
    test2();
 rdtsc  
 shl         rdx,20h  
 inc         r9d  
 or          rax,rdx  
 xor         al,0FFh  
 and         al,1  
    test2();
 movzx       ecx,al  
 lea         eax,[rcx+rcx*8]  
 mov         dword ptr [rsp+60h],eax  
 movsxd      rax,r9d  
 cmp         rax,3E8h  
 jb          main+0A0h (013FFE12E0h)  
    finish2 = __rdtscp(&y);
  • 0
    вы компилировали с оптимизацией?
  • 1
    Они генерируют другой код? Компиляторы знают некоторые приемы удаления таких веток.
Показать ещё 5 комментариев
Теги:
optimization
performance
cpu
branch

1 ответ

2

Сгенерированный код не содержит каких-либо внутренних ветвей для любой функции, поэтому нет штрафа за неправильное предсказание.

В первом он преобразует логическое значение в нуль или -1 (вокруг sbb eax,eax) и добавляет его к 5. Это довольно стандартная оптимизация при работе с булевыми.

Во втором он умножается на девять (rcx+rcx*8), потому что у вас есть 5 * condition 5 * !condition не 5 * !condition

  • 0
    Спасибо за это - так быстро разбил пример, что я не заметил.
  • 0
    Затраты на чтение счетчика также могут уменьшить разницу между двумя кодами. Несколько удивительно, что компилятор не просто использовал c=4+(__rdtsc() &0x1) . С другой стороны, умный компилятор распознал бы отсутствие побочных эффектов (без использования c ) и просто исключил бы цикл.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню