Маленькая повторная арифметика против создания новых переменных

Я пишу на C ++ для устройств с низкой спецификацией (~ 3 МБ ОЗУ, ~ 70 МГц ЦП), и мне интересно, что будет работать более эффективно (и насколько). Это упрощенный сегмент кода, который будет выполняться 120-600 раз в секунду:

void checkCollisions(int x, int y)
{
int p1x = x, p1y = y+2;
int p2x = x, p2y = y+3;
int p3x = x+3, p3y = y+3;
// And so on...

if (wallAt(p1x-1, p1y) || wallAt(p2x-1, p2y))
setCollision(LEFT, true);
if (wallAt(p1x, p1y) || wallAt(p4x, p4y) || wallAt(p5x, p5y))
inGround = true;
else
inGround = false;
// And so on...
}

Или заменить целые числа их определениями:

void checkCollisionsAlt(int x, int y)
{
if (wallAt(x-1, y+2) || wallAt(x-1, y+3))
setCollision(LEFT, true);
if (wallAt(x, y+2) || wallAt(x+3, y) || wallAt(x+2, y))
inGround = true;
else
inGround = false;
// And so on...
}

Вот схема примера:

Пример диаграммы

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

0

Решение

Несколько моментов для размышления:

  1. Если полная версия также не имеет рекурсии, вы можете меньше беспокоиться о переменных (p1x и т. Д.) В стеке.
  2. Потребление стека эфемерно и не должно поражать вас, если у вас нет патологического кода, такого как глубокая рекурсия с тяжелым каждым кадром.
  3. Рекурсия обычно плохая идея с ограниченным бюджетом памяти.
  4. Тот факт, что вы используете их как переменные с явным именем, не означает, что они будут такими во время выполнения.
  5. Любой достойный компилятор может распознать время жизни переменных и отправить их в регистры. Пожалуйста, проверьте это с уровнем оптимизации компилятора, который вы используете в настоящее время, и рассмотрите возможность его увеличения, если это необходимо.

Кроме того, каков ожидаемый диапазон этих значений p1x и т. Д. Почему бы не использовать short int?

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

Примечание. Любые и ВСЕ распределения кучи должны быть тщательно проверены. Попробуйте реализовать пользовательский распределитель, вместо того чтобы использовать стандартные служебные данные блока памяти malloc (). Конечно, вы не подняли кучу вопросов, но просто помните об этом.

1

Другие решения

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

1

Если машина работает на частоте 70 МГц, это означает, что она имеет 117 000 циклов каждые 600 секунд.

Если инструкции занимают в среднем 10 циклов каждый, он может выполнить 11 700 инструкций за 600 секунд.

Когда я смотрю на ваш код, я предполагаю около 100 инструкций для его выполнения.
100/11 700 = примерно 1% времени, потраченного на выполнение этого кода.

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

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

0
По вопросам рекламы [email protected]