На каком процессоре вы это тестируете? Я смутно помню, что развертывание циклов помогает, когда процессор может обрабатывать несколько операций одновременно, но только до максимального числа параллельных выполнений. Так что если ваш процессор может обрабатывать только 8 одновременных инструкций, то развертывание до 16 не поможет. Но кто-то со знанием более поздней конструкции процессора должен будет подправить / исправить меня.
РЕДАКТИРОВАТЬ : Согласно этого PDF , Centrino Core2 Duo имеет два процессора, каждый из которых способен выполнять 4 одновременных инструкции. Хотя обычно это не так просто. Если ваш компилятор не оптимизирует оба ядра (т. Е. Когда вы запускаете диспетчер задач (если вы работаете в Windows, top, если вы используете Linux), вы увидите, что использование процессора максимально), ваш процесс будет работает на одном ядре за раз. Процессор также имеет 14 этапов выполнения, поэтому, если вы сможете поддерживать конвейер заполненным, вы получите более быстрое выполнение.
Продолжая следовать теоретическому маршруту, вы получите повышение скорости на 33% за одну развертку, поскольку вы начинаете использовать преимущества одновременного выполнения инструкций. Переход на 4 развертывания не очень помогает, потому что вы все еще в пределах этого ограничения на 4 одновременных инструкции. Переход на 8 развертываний помогает, потому что процессор теперь может заполнять конвейер более полно, так что за такт будет выполняться больше инструкций.
Для этого последнего, подумайте о том, как работает McDonald's через (я думаю, что это относительно широко распространено?). Автомобиль проезжает мимо, заказывает у одного окна, платит у второго окна и получает еду у третьего окна. Если второй привод входит, когда первый все еще находится в порядке, то к тому моменту, когда оба заканчивают (предполагая, что каждая операция в приводе занимает один «цикл» или единицу времени), то к полному времени, когда 4 цикла пройдут, будут выполнены 2 полные операции. , Если каждая машина выполняет все свои операции в одном окне, то первая машина будет выполнять 3 цикла для заказа, оплаты и получения еды, а затем вторая машина также будет выполнять 3 цикла для заказа, оплаты и получения еды, всего из 6 циклов. Таким образом, время работы за счет конвейеризации уменьшается.
Конечно, вы должны поддерживать конвейер заполненным, чтобы добиться наибольшего улучшения скорости. 14 этапов - это много этапов, поэтому переход на 16 развертываний даст вам некоторое улучшение, поскольку в процессе может быть больше операций.
Переход к 32, вызывающий снижение производительности, может быть связан с пропускной способностью процессора из кеша (опять же догадываюсь, не могу знать наверняка, не видя точно ваш код, а также машинный код). Если все инструкции не могут поместиться в кэш или в регистры, тогда необходимо некоторое время, чтобы подготовить их к запуску (т. Е. Люди должны сесть в свои машины и, прежде всего, проехать на машине). Будет некоторое снижение скорости, если все они доберутся туда все сразу, и для продолжения операции потребуется некоторое перетасовывание линии.
Обратите внимание, что каждое движение от src к dst не является свободным или отдельной операцией. У вас есть поиск в массивах, и это стоит времени.
Что касается того, почему вторая версия работает так быстро, я рискну предположить, что это связано с оператором []. Каждый раз, когда вызывается, вы выполняете поиск в массивах src и dst, устанавливаете указатели на местоположения и затем извлекаете память. Другой код идет прямо к указателям массивов и напрямую обращается к ним; в основном, для каждого из перемещений из src в dst в перемещении задействовано меньше операций, потому что поиск был обработан явно посредством размещения указателя. Если вы используете [], выполните следующие действия:
- делать любую математику внутри []
- взять указатель на это место (startOfArray + [] в памяти)
- вернуть результат этого места в памяти
Если вы идете вместе с указателем, вы просто выполняете математику, чтобы выполнить прогулку (обычно просто сложение, без умножения), а затем возвращаете результат, потому что вы уже сделали второй шаг.
Если я прав, тогда вы можете получить лучшие результаты со вторым кодом, разворачивая также его внутренний цикл, так что несколько операций могут быть переданы по конвейеру одновременно.