После длительного тестирования вашего кода, как я уже сказал в комментариях, я полагаю, что вы сталкиваетесь с большим количеством ошибок в вашем текущем решении. Линия:
if (testStore)
counters[ch] = count + 1;
может заставить компилятор полностью загрузить новую строку кэша в память и сместить текущий контент. В этом сценарии могут также быть некоторые проблемы с предсказанием ветвления. Это сильно зависит от аппаратного обеспечения, и я не знаю действительно хорошего решения для тестирования этого на любом интерпретируемом языке (это также довольно сложно в скомпилированных языках, где аппаратное обеспечение установлено и хорошо известно).
После прохождения разборки вы можете ясно увидеть, что вы также вводите целую кучу новых инструкций, которые могут еще больше увеличить вышеупомянутые проблемы.

В целом, я бы посоветовал вам переписать полный алгоритм, поскольку есть лучшие места для повышения производительности, вместо того, чтобы выбирать это одно маленькое задание. Это была бы оптимизация, которую я бы предложил (это также улучшает читабельность):
- Инвертируйте петли
i
и j
. Это полностью удалит переменную allEmpty
.
- Приведите
ch
к int
с var ch = (int) val[j];
- потому что вы ВСЕГДА используете его в качестве индекса.
- Подумайте, почему это вообще может быть проблемой. Вы вводите новую инструкцию, а любая инструкция платная. Если это действительно «горячая точка» вашего кода, вы можете начать думать о лучших решениях (помните: «преждевременная оптимизация - корень всего зла»).
- Так как это «тестовая настройка», как следует из названия, это вообще важно? Просто удали его.
РЕДАКТИРОВАТЬ: Почему я предложил инвертировать в циклы? С этой маленькой перестановкой кода:
foreach (var val in vals)
{
foreach (int ch in val)
{
var count = counters[ch];
tmp ^= count;
if (testStore)
{
counters[ch] = count + 1;
}
}
}
Я пришел из среды выполнения, подобной этой:

к таким временам выполнения:

Вы все еще думаете, что это не стоит пробовать? Я сохранил здесь несколько порядков и почти исключил эффект if
(чтобы быть понятным - все оптимизации отключены в настройках). Если есть особые причины не делать этого, вы должны рассказать нам больше о контексте, в котором будет использоваться этот код.
EDIT2 : для подробного ответа. Мое лучшее объяснение, почему возникает эта проблема, заключается в том, что вы перекрестно ссылаетесь на строки кэша. В строках:
for (var i = 0; i < vals.Length; i++)
{
var val = vals[i];
вы загружаете действительно массивный набор данных. Это намного больше, чем сама строка кэша. Так что, скорее всего, его нужно будет загружать каждую итерацию свежим из памяти в новую строку кэша (смещая старый контент). Это также известно как «очистка кэша», если я правильно помню. Спасибо @mjwills за то, что указал на это в своем комментарии.
В моем предложенном решении, с другой стороны, содержимое строки кэша может оставаться в живых, пока внутренний цикл не выходит за его границы (что случается намного реже, если вы используете это направление доступа к памяти).
Это самое близкое объяснение того, почему мой код работает намного быстрее, и он также поддерживает предположение, что у вас есть серьезные проблемы с кэшированием вашего кода.