Копирование большого массива или изменение индекса доступа

#arrays #performance #fortran

#массивы #Производительность #fortran

Вопрос:

Прошу прощения, если на этот вопрос есть очевидный ответ, но я не могу правильно сформулировать его, чтобы найти ответ в Интернете.

Предположим, что в Fortran у меня есть массив (> 100 000) действительных чисел. Я буду постоянно обращаться к этому массиву (последовательно) снова и снова на протяжении одного шага схемы временной интеграции. На каждом последующем шаге некоторые элементы этого массива больше не будут нужны. Я не знаю, сколько, это может быть где угодно, от ни одного из них до всех. Мой вопрос:

Что лучше: (1) Проходить через этот массив каждый шаг и копировать оставшиеся элементы, которые мне нужны, в новый массив, даже если может потребоваться удалить только очень небольшой процент, или (2) должен ли у меня быть новый массив целочисленных индексов, который я обновляю каждый раз, чтобы получить доступэтот массив. Я понимаю, что если доступ к памяти является последовательным, он должен быть очень быстрым, и я думаю, что это должно перевесить стоимость копирования массива. С другой стороны, обновление целочисленных индексов будет очень быстрым, но стоимость будет заключаться в том, что данные будут фрагментированы, и доступ к ним будет медленнее.

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

Комментарии:

1. Всегда лучше показывать реальный код, чем просто длинное описание в словах. Это слишком долго, слишком скучно, слишком двусмысленно. (TLDR)

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

Ответ №1:

Трудно сказать заранее, поэтому простым ответом действительно будет * «Измерить!»
Однако некоторые предположения могут помочь с тем, что измерять. Все, что следует из предположения, что код действительно критичен для производительности.

Задержка памяти:
100 тыс. элементов обычно превышают кэш L1 и L2, поэтому локальность памяти будет играть определенную роль. OTOH, линейное сканирование намного лучше, чем выборочный доступ.

Если задержка памяти значительна по сравнению с операциями для каждого элемента, и большинство элементов становятся «неинтересными» после заданного количества итераций, я бы стремился:

  • отметьте отдельные элементы как «которые будут пропущены в будущих итерациях»
  • уплотняйте память (т.Е. Удаляйте пропускаемые элементы), когда ~ 50% элементов становятся пропускаемыми

(Проверьте вышеуказанные условия: для наивной реализации время одной итерации увеличивается быстрее, чем линейно с увеличением количества элементов?)

Блоки, дружественные к кэшу:
Если задержка памяти является проблемой и можно применить несколько операций к небольшому фрагменту (скажем, 32 КБ данных), сделайте это.

Распараллеливание:
(слон в комнате). Может быть легко добавлен, если вы можете обрабатывать в блоках, удобных для кэша.

Комментарии:

1. Мне очень нравится идея маркировки элементов, а затем очистки при достижении порогового значения. Похоже, это использует лучшее из обоих миров!

2. Хотелось бы увидеть результаты, имеет ли это какое-либо значение вообще и т. Д.!