Сразу ввод / вывод выполняется медленнее, чем чтение немного за раз - PullRequest
1 голос
/ 20 января 2011

Я работаю над оптимизацией и алгоритмом, который мы готовим для установки на GPU с использованием cuda. ​​

Часть ввода / вывода считывает с 3 разных изображений, по одной строке за раз. Это было прямо в середине цикла для запуска фильтра над изображениями. Я решил попытаться предварительно загрузить значения, которые были сгенерированы, удалив ввод-вывод в его собственный цикл и выгрузив значения в массивы, которые содержали изображения и использовались в вычислениях.

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

Что может быть причиной этого? Неужели ошибки кеша из больших буферов действительно сильно снижают производительность? Это не проблема памяти - с 24 ГБ на этой машине у него много оперативной памяти.

Не уверен, что еще это может быть, открыто для выслушивания идей

Ответы [ 3 ]

2 голосов
/ 20 января 2011

@ Дерек предоставил следующую дополнительную информацию:

(время выполнения) ... "больше минуты, по сравнению с 10 - 14 секундами раньше. Хотя я не делаю никаких особых потоков, хотяУ меня есть некоторые прагмы OpenMP. Перемещение ввода-вывода за пределы цикла фильтра не изменило ни одного из них. Я использую CentOS 5.5. Размер изображения составляет около 72 МБ "

огромная разница во времени выполнения.Поскольку используется OpenMP, мы можем предположить, что существует несколько потоков.Поскольку вы имеете дело только с 72 МБ данных, я не могу понять, как разница во времени ввода-вывода может быть такой большой.Мы можем быть уверены, что время чтения меньше, чем ваши исходные 10-14 секунд, поэтому, если у вас нет ошибки в этой части кода, дополнительное время находится в разделе фильтра.Изображения предположительно двоичные?Поскольку @Satya предложила профилировать ваш код или хотя бы добавить некоторые распечатки времени, это может помочь определить, в чем заключается проблема.

«Преимущество» чтения в цикле может быть:

  1. ОС дает вам некоторый параллелизм, потому что она способна выполнять некоторые операции ввода-вывода параллельно с вашими вычислениями, например, чтение вперед.Вы теряете этот параллелизм, когда читаете все заранее, фактически блокируя во время чтения.
  2. Считанные данные находятся в кеше в тот момент, когда ваш фильтр обращается к данным.Промахи в кеше могут реально снизить производительность, если обработка невелика относительно пропускной способности памяти.Трудно поверить, что это имело бы существенное значение в этом случае использования, потому что дисковый ввод-вывод намного медленнее, чем память.

Учитывая ваше последнее обновление, похоже, мы имеем дело с # 2.Однако следует обратить внимание на шаблоны доступа к памяти (включая все потоки). Возможно, вы наблюдаете переполнение кэша, поскольку данные, которые раньше использовались в основной памяти, теперь находятся дальше друг от друга.Это может оказать большое влияние, потому что, если у вас много обращений к памяти, и все они пропускают кэш, вы всегда несете затраты на дальнейший доступ к данным, что может быть разницей в порядок.

Решением этой проблемы является размещение вашей памяти в виде полос, например, n строк первого изображения, затем n строк второго изображения, а затем n строк третьего изображения.IIRC эта техника называется «чередование».Точный размер полосы зависит от вашего процессора, но вы можете поэкспериментировать с ним (или начать с того же объема данных, который использовался для чтения во внутреннем цикле, если он достаточно большой).

Например:

stripe_number = 0;
do
{
    count = fread(striped_buffer+(STRIPE_SIZE*stripe_number*NUM_IMAGES), 1, STRIPE_SIZE, image_file);
    stripe_number++;
} while(count != 0);

Читайте по одному файлу за раз, чтобы не искать на своем диске туда-сюда.

Независимо от того, чтобы максимизировать производительность, вы, вероятно, захотите использовать асинхронный / перекрывающийся ввод-вывод дляваш следующий бит данных изображения будет поступать в то время, когда вы обрабатываете предыдущий бит.

Если вы разрабатываете под Windows, это может дать вам начало выполнения перекрывающегося ввода-вывода: http://msdn.microsoft.com/en-us/library/ms686358%28v=vs.85%29.aspx

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

0 голосов
/ 20 января 2011

В дополнение к @Guy: answer, я должен упомянуть файлы с отображением в памяти, у них есть лучшие стороны обоих подходов.Однако чтение 70Mb должно занять около секунды, поэтому проблема кроется в другом месте.

Это может быть вызвано согласованностью основных кэшей.Я не знаю много об этом, но если два потока одновременно имеют доступ на запись к одной и той же странице памяти (или, что еще хуже, к одной и той же строке кэша), то их кэши должны быть синхронизированы.Когда вы читаете все изображение одновременно, то все ваши потоки обработки будут обрабатывать их одновременно.Будут ли они записывать результаты в близких адресах памяти?Если вы построчно читаете изображения, они будут тратить некоторое время на ожидание завершения ввода-вывода, поэтому это будет происходить не так часто.

0 голосов
/ 20 января 2011

Да, вы загружаете свое изображение в кэш L2 дважды - когда вы загружаете его из файла, а затем из памяти. Вы также должны потратить некоторое время на перемещение данных из кэша в память.

В качестве опции вы можете попробовать загрузить некоторые части, например 2-8 МБ (в зависимости от размера кэша L2)

...