Рассмотрите некоторый код, который нужно выполнить повторно в любом месте от 1 до 1000 000 раз, а количество повторений неизвестно во время компиляции. Я понимаю, что разворачивание цикла будет незначительной оптимизацией, учитывая большое количество циклов, и будет оптимизироваться только до max_unrolls, указанного во время компиляции. Идея, которую я придумал, состоит в том, чтобы реализовать двоичный (или базовый 2) неполный цикл, который по существу выполняет несколько раз несколько раз, что указано во время выполнения. Я придумал некоторый код, чтобы продемонстрировать эту идею, сжатая версия показана ниже. Метод, используемый в приведенном ниже коде, имеет ряд проблем с точки зрения удобства использования.Как реализовать разворот цикла 2-го цикла во время выполнения в целях оптимизации
- Требуется, чтобы кодер вручную скопировал базу 2 разворота, по существу, скопировал разворот 2^n-1 раз.
- Это также необходимо переделать для каждой новой функции, которая должна использовать этот метод.
вопрос имеет тройное значение. Во-первых, я что-то упускаю, компилятор уже достаточно интеллектуальный, чтобы сделать это сам? Во-вторых, что является эффективным способом реализации этого, так что становится возможным сравнить его с стандартным циклом for
, одновременно решая вышеуказанные проблемы. В-третьих, насколько вам известно, есть библиотека, которая уже реализовала это.
Обращаем ваше внимание: Я делаю это исключительно ради удовольствия, но у меня нет опыта, чтобы знать, будет ли это эффективно. Я провел тестирование кода, но нашел только очень небольшие улучшения, однако, я считаю, что мне не удалось развернуть вручную достаточно далеко, чтобы было сделано справедливое сравнение. Также я знаю, что этот метод имеет потенциал для создания массивных двоичных размеров, однако я считаю, что это было бы целесообразным компиляцией памяти времени. Кроме того, если вы публикуете какую-либо сборку, то, вероятно, мне понадобится еще год или около того, чтобы понять ее.
inline void some_reapeated_function(int &function_parameter_1, int &function_parameter_2)
{
function_parameter_1 /= function_parameter_2;
}
// Function to be called when you need it to be unrolled.
int runtime_unroll(unsigned int &no_of_loops, int &function_parameter_1, int &function_parameter_2)
{
std::vector<bool> binary_vector;
// Stores the number of loops in a binary representation in a vector.
binary_function.reserve(no_of_loops);
while(no_of_loops)
{
if (no_of_loops&1)
binary_vector.push_back(false);
else
binary_vector.push_back(true);
no_of_loops>>=1;
}
// If binary of no_of_loops contains a 2^0 execute once.
if (binary_vector[0])
{
some_reapeated_function(function_parameter_1,function_parameter_2);
}
// If binary of no_of_loops contains a 2^1 execute twice.
if (binary_vector[1])
{
some_reapeated_function(function_parameter_1,function_parameter_2);
some_reapeated_function(function_parameter_1,function_parameter_2);
}
//If binary of no_of_loops contains a 2^2 execute 4 times.
if (binary_vector[2])
{
some_reapeated_function(function_parameter_1,function_parameter_2);
some_reapeated_function(function_parameter_1,function_parameter_2);
some_reapeated_function(function_parameter_1,function_parameter_2);
some_reapeated_function(function_parameter_1,function_parameter_2);
}
/* This example only covers from 1 to 2^3-1 or up to 7 unrolls.
This can continue depending on the number of repetitions needed and
could incorporate a for loop to continue after the loop has fully unrolled */
}
Более стандартная практика представляет собой частично развернутый цикл, который выполняет некоторое количество операций (например, 8) на каждой итерации и второй цикл, который выполняет остаток. Прошедший определенный размер цикла, дальнейшее развертывание не будет иметь заметной выгоды и, вероятно, ухудшит ситуацию из-за использования большего количества кэша команд. Вы также можете попробовать [устройство Даффа] (https://en.wikipedia.org/wiki/Duff's_device), чтобы избавиться от второго цикла. – interjay
@interjay Идея функции, которую я пытаюсь реализовать, состоит в том, чтобы сделать число разворот полностью гибким и, таким образом, оптимизировать цикл независимо от количества требуемых итераций. Представьте себе 'int' в двоичной форме, где каждый из 1 представляет собой функцию, выполняемую до 2^n раз, где n - индекс каждого бита в целых числах? Даффс устройство интересно, хотя, спасибо! – silvergasp