На основании информации, приведенной в вопросе, можно только догадываться и называть некоторые идеи.
Вы правильно измерили?Имейте в виду, что для получения надежных результатов производительности необходимо (как минимум)
- Запускать сборки выпуска без подключенного отладчика
- Повторять тест достаточно часто и усреднять результаты
- Сделай тест честным, т.е.дайте всем испытуемым одинаковую «конфигурацию ресурсов»
Чтобы убедиться, что источник (предполагаемого) падения производительности действительно связан с встраиванием функции, можно исследовать сгенерированный код IL.Или даже лучше: машинные инструкции, сгенерированные компилятором JIT.
Для ILNumerics мы реализовали пользовательскую быструю сортировку и выполнили множество мер производительности.Окончательный алгоритм работает в несколько раз быстрее, чем версия CLR.Ручная подкладка - это только одно улучшение, которое было необходимо для повышения производительности.Другие:
- Не используется рекурсия
- Использование небезопасного сравнения / обмена
- Использование сортировки вставки для небольших разделов
- Оптимизация для ограниченного размеравременный массив (замена стека)
Очень часто источник странных результатов производительности обнаруживается в том, что память (неправильно) используется алгоритмом.Другой может заключаться в другом потоке команд, который в конечном итоге более или менее преуспевает в оптимизации любого задействованного компилятора / процессора.Общая производительность исполнения - очень сложный зверь, которого трудно угадать детерминистически, и, следовательно, профилировщик - ваш лучший друг!
@ Edit: Рассматривая ваш основной тестПохоже, что обычно вы измеряете пропускную способность памяти вашего процессора / основной памяти.Размер массива int [] 5 * 10e6 составляет примерно 19 МБ.Скорее всего, это вне диапазона ваших кешей.Таким образом, процессор будет ждать памяти из-за принудительного отсутствия кеша в большинстве случаев.Это затрудняет оценку влияния любой переформулировки кода.Вместо этого я предлагаю попробовать измерить этот способ: (псевдокод)
Цель состоит в том, чтобы заставить быструю сортировку использовать только данные из кешей.Поэтому убедитесь, что не воссоздаете копии из новой памяти, а имеете только два глобальных экземпляра: оригинал и копию для сортировки.Оба должны помещаться в ваш (последний уровень) кэш одновременно!При некотором запасе (для других процессов в системе) хорошим предположением является использование только половины доступного размера кэша последнего уровня для обоих массивов.В зависимости от вашего истинного размера кеша длина теста 250 тыс. Выглядит более разумной.
@ Edit2: Я запустил ваш код, получил те же результаты и посмотрел (оптимизированные) машинные инструкции вVS отладчик.Вот соответствующая часть из обеих версий:
Not inlined:
69: do { pIndex--; } while (arr[pIndex] > pivot);
00000017 dec ebx
00000018 cmp ebx,esi
0000001a jae 00000053
0000001c cmp dword ptr [ecx+ebx*4+8],edi
00000020 jg 00000017
70: do { leftPoint++; } while (arr[leftPoint] < pivot);
00000022 inc edx
00000023 cmp edx,esi
00000025 jae 00000053
00000027 cmp dword ptr [ecx+edx*4+8],edi
0000002b jl 00000022
Inlined:
97: do { pIndex--; } while (arr[pIndex] > pivot);
00000038 dec dword ptr [ebp-14h]
0000003b mov eax,dword ptr [ebp-14h]
0000003e cmp eax,edi
00000040 jae 00000097
00000042 cmp dword ptr [esi+eax*4+8],ebx
00000046 jg 00000038
98: do { leftPoint++; } while (arr[leftPoint] < pivot);
00000048 inc ecx
00000049 cmp ecx,edi
0000004b jae 00000097
0000004d cmp dword ptr [esi+ecx*4+8],ebx
00000051 jl 00000048
Как видно, версия «без встроенной» лучше использует регистры для уменьшения рабочего индекса (строка 69/97).Очевидно, что JIT решил не помещать и не вставлять соответствующий регистр в стек, поскольку другой код в той же функции использует тот же регистр.Поскольку это горячий цикл (а CLR не распознает это), общая скорость выполнения страдает.Таким образом, в данном конкретном случае ручное встраивание функции Partition невыгодно.
Однако, как вы знаете, нет гарантии, что другие версии CLR делают то же самое.Различия могут даже возникнуть для 64 бит.