Ветвление при смешивании параметров шаблона и переменных в C ++ - PullRequest
0 голосов
/ 09 февраля 2019

Я пытаюсь выполнить некоторую оптимизацию цикла, как описано здесь: Оптимизация цикла против дублирования кода

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

Вот совершенно неоптимизированная версия кода:

for (int i = 0; i < 100000, i++){
  if (external_condition_1 || (external_condition_2 && internal_condition[i])){
     run_some_code;
  }
  else{
     run_some_other_code;
  }
  run_lots_of_other_code;
}

Это моя попытка обернуть цикл в шаблонную функцию, как предложено в вопросе, связанном выше, для оптимизации производительности иизбежать дублирования кода, написав несколько версий цикла:

template<bool external_condition_1, external_condition_2>myloop(){
for (int i = 0; i < 100000, i++){
  if (external_condition_1 || (external_condition_2 && internal_condition[i]){
     run_some_code;
  }
  else{
     run_some_other_code;
  }
  run_lots_of_other_code;
}

Мой вопрос: как можно написать код, чтобы избежать разветвления и дублирования кода?

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

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Мой вопрос: как можно написать код, чтобы избежать разветвлений и дублирования кода?

Ну, вы уже написали свой шаблон, чтобы избежать дублирования кода, верно?Итак, давайте посмотрим, что осталось разветвления.Чтобы сделать это, мы должны рассмотреть каждую функцию, сгенерированную из вашего шаблона (их четыре).Мы также должны применить ожидаемую оптимизацию компилятора на основе параметров шаблона.

Сначала установите условие 1 на true.Это должно создать две функции, которые по существу (используя немного псевдосинтаксиса) следующие:

myloop<true, bool external_condition_2>() {
    for (int i = 0; i < 100000, i++){
        // if ( true || whatever ) <-- optimized out
        run_some_code;
        run_lots_of_other_code;
    }
}

Нет ветвления там.Хорошо.Переходя к первому условию, являющемуся ложным, и второму условию, являющемуся истинным.

myloop<false, true>(){
    for (int i = 0; i < 100000, i++){
        if ( internal_condition[i] ){ // simplified from (false || (true && i_c[i]))
            run_some_code;
        }
        else{
            run_some_other_code;
        }
        run_lots_of_other_code;
    }
}

ОК, здесь происходит некоторое разветвление.Однако каждый i должен быть проанализирован, чтобы увидеть, какой код должен выполняться.Я думаю, что здесь больше ничего нельзя сделать без дополнительной информации о internal_condition.Позже я подумаю над этим, но давайте сейчас перейдем к четвертой функции.

myloop<false, false>() {
    for (int i = 0; i < 100000, i++){
        // if ( false || (false && whatever) ) <-- optimized out
        run_some_other_code;
        run_lots_of_other_code;
    }
}

Здесь нет разветвлений.Вы уже хорошо поработали, избегая ветвления и дублирования кода.


ОК, давайте вернемся к myloop<false,true>, где есть ветвления.Ветвление в значительной степени неизбежно просто из-за того, как настроена ваша ситуация.Вы собираетесь повторять много раз.В некоторых итерациях вы хотите сделать одно, а в других - другое.Чтобы обойти это, вам нужно пересмотреть свою настройку, чтобы вы могли делать то же самое на каждой итерации.(Оптимизация, с которой вы работаете, основана на выполнении одной и той же вещи на каждой итерации, даже если в следующий раз при запуске цикла она может измениться.)

Самый простой, но маловероятный сценарий - это где internal_condition[i] эквивалентно чему-то вроде i < 5000.Также было бы удобно, если бы вы могли выполнить весь «некоторый код» перед любым «большим количеством другого кода».Затем вы можете выполнить цикл от 0 до 4999, выполняя «некоторый код» каждую итерацию.Затем выполните цикл от 5000 до 99999, запустив «другой код».Затем третий цикл для запуска «большого количества другого кода».

Любое решение, которое я могу придумать, включает адаптацию вашей ситуации, чтобы сделать ее более похожей на невероятно простой сценарий.Можете ли вы рассчитать, сколько раз internal_condition[i] это правда?Можете ли вы повторить это много раз и сопоставить свою (новую) переменную управления циклом с соответствующим значением i (старая переменная управления цикла)?(Или, может быть, точное значение i не важно?) Затем выполните второй цикл, чтобы охватить остальные случаи?В некоторых случаях это может быть тривиальным.В других, это далеко не так.

Могут быть и другие приемы, которые могут быть выполнены, но они зависят от более подробной информации о том, что вы делаете, что вам нужно делать, и что вы думаете, что нужно делать, ноне совсем(Возможно, что требуемый уровень детализации сокрушит StackOverflow.) Важен ли порядок?Важно ли точное значение i?

В конце я бы выбрал профилирование кода.Профилируйте код без дублирования кода, но с разветвлением.Профилируйте код с минимальным разветвлением, но с дублированием кода.Есть ли измеримое изменение?Если это так, подумайте о том, как вы можете изменить свое внутреннее состояние так, чтобы i мог охватывать большие диапазоны без изменения значения внутреннего условия.Затем разделите вашу петлю на более мелкие части.

0 голосов
/ 09 февраля 2019

В C ++ 17, чтобы гарантировать отсутствие дополнительной оценки веток, вы можете сделать:

template <bool external_condition_1, bool external_condition_2>
void myloop()
{
    for (int i = 0; i < 100000, i++){
        if constexpr (external_condition_1) {
            run_some_code;
        } else if constexpr (external_condition_2){
            if (internal_condition[i]) {
                 run_some_code;
            } else {
                 run_some_other_code;
            }
        } else {
            run_some_other_code;
        }
        run_lots_of_other_code;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...