Могу ли я заменить свои операторы if для экономии времени выполнения?

Некоторые легко запоминающиеся и соответственно неуправляемые неназначенные (на IANA) порты:

27182 (e)

31415 (pi)

60221 (avagadro's)

1
задан Tim Lorenzo Fleischmann 18 January 2019 в 13:12
поделиться

2 ответа

Одно правило при программировании - не оптимизировать микро.

Другое правило заключается в написании четкого кода.

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

Помните также, что в ассемблере нет типов bool и int как таковых: просто регистры, так что вы, вероятно, обнаружите, что все преобразования будут оптимизированы. Поэтому

b += a;

побеждает для меня; это также яснее.

0
ответ дан Bathsheba 18 January 2019 в 13:12
поделиться

Компиляторам разрешается предполагать, что базовое значение bool не испорчено, поэтому оптимизирующие компиляторы могут избежать ветвления.

Если мы посмотрим на сгенерированный код для этого искусственного теста,

int with_if_bool(bool a, int b) {
    if(a){b++;}
    return b;
}

int with_if_char(unsigned char a, int b) {
    if(a){b++;}
    return b;
}

int without_if(bool a, int b) {
    b += a;
    return b;
}

clang воспользуется этим фактом и сгенерирует точно такой же код без ветвей, который суммирует a и b для версии bool и вместо этого генерировать фактические сравнения с нулем в случае unsigned char (хотя это все еще код без ветвей):

with_if_bool(bool, int): # @with_if_bool(bool, int)
  lea eax, [rdi + rsi]
  ret
with_if_char(unsigned char, int): # @with_if_char(unsigned char, int)
  cmp dil, 1
  sbb esi, -1
  mov eax, esi
  ret
without_if(bool, int): # @without_if(bool, int)
  lea eax, [rdi + rsi]
  ret

gcc вместо этого будет обрабатывать bool так же, как если бы он был unsigned char, не используя его свойства, генерируя код, аналогичный случаю unsigned char clang.

with_if_bool(bool, int):
  mov eax, esi
  cmp dil, 1
  sbb eax, -1
  ret
with_if_char(unsigned char, int):
  mov eax, esi
  cmp dil, 1
  sbb eax, -1
  ret
without_if(bool, int):
  movzx edi, dil
  lea eax, [rdi+rsi]
  ret

Наконец, Visual C ++ будет обрабатывать версии bool и unsigned char одинаково, точно так же, как gcc, хотя и с более наивным кодовым кодом (он использует условное перемещение вместо выполнения арифметики с регистром флагов, который IIRC Традиционно был менее эффективным, не знаю, для нынешних машин).

a$ = 8
b$ = 16
int with_if_bool(bool,int) PROC ; with_if_bool, COMDAT
  test cl, cl
  lea eax, DWORD PTR [rdx+1]
  cmove eax, edx
  ret 0
int with_if_bool(bool,int) ENDP ; with_if_bool

a$ = 8
b$ = 16
int with_if_char(unsigned char,int) PROC ; with_if_char, COMDAT
  test cl, cl
  lea eax, DWORD PTR [rdx+1]
  cmove eax, edx
  ret 0
int with_if_char(unsigned char,int) ENDP ; with_if_char

a$ = 8
b$ = 16
int without_if(bool,int) PROC ; without_if, COMDAT
  movzx eax, cl
  add eax, edx
  ret 0
int without_if(bool,int) ENDP ; without_if

Во всех случаях ветви не генерируются; единственное отличие состоит в том, что на большинстве компиляторов генерируется более сложный код, который зависит от cmp или test, создавая более длинную цепочку зависимостей.

При этом я бы беспокоился об этом виде микрооптимизации только в том случае, если вы фактически выполняете свой код под профилировщиком, а результаты указывают на этот конкретный код (или на какой-то жесткий цикл, который его включает); в общем, вы должны написать разумный, семантически правильный код и сосредоточиться на использовании правильных алгоритмов / структур данных. Микрооптимизация наступает позже.


В моей программе это не сработает, поскольку на самом деле это операция типа: b+=(a==c)

Это должно быть еще лучше для оптимизатора Так как у него даже нет никаких сомнений относительно того, откуда исходит bool - он может просто принять решение прямо из регистра флагов. Как вы можете видеть , здесь gcc производит довольно схожий код для двух случаев, clang точно такой же, в то время как VC ++, как обычно, создает нечто более условное (a cmov) в if случай. [тысяча сто тридцать-один]

0
ответ дан Matteo Italia 18 January 2019 в 13:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: