Почему завершение блока ввода-вывода занимает так много времени при пересечении процессоров?

Я пытаюсь выжать максимальную производительность из блочного драйвера Linux для высокопроизводительного устройства хранения. Одна проблема, которая немного озадачила меня на данный момент, заключается в следующем: если пользовательская задача запускает операцию ввода-вывода (чтение или запись) на одном процессоре, а прерывание устройства происходит на другом процессоре, перед этим у меня задерживается около 80 микросекунд. задача возобновляет выполнение.

Я вижу это, используя O_DIRECT против блочного устройства, так что это не связано с кэшем страниц или файловой системой. Драйвер использует make_request чтобы получать операции, поэтому он не имеет очереди запросов и не использует какой-либо планировщик ввода-вывода ядра (вам придется поверить мне, так намного быстрее).

Я могу продемонстрировать себе, что проблема возникает между звонками bio_endio на одном процессоре, а задача перенесена на другой процессор. Если задача находится на том же процессоре, она запускается очень быстро, а если задача - на другом физическом процессоре, это занимает намного больше времени - обычно на 80 микросекунд дольше в моей текущей тестовой системе (x86_64 на чипсете Intel 5520 [NUMA])).

Я могу мгновенно удвоить свою производительность, настроив процесс и привязку процессора IRQ к одному и тому же физическому ЦП, но это не является хорошим долгосрочным решением - я бы предпочел добиться хорошей производительности независимо от того, где происходят входы / выходы. И у меня есть только один IRQ, поэтому я могу управлять им только одним процессором за раз - бесполезно, если на многих процессорах запущено много потоков.

Я вижу эту проблему на ядрах от Centos 5.4 2.6.18 до основной версии 2.6.32.

Итак, вопрос: почему пользовательский процесс занимает больше времени, если я позвонил bio_endio с другого процессора? Это проблема планировщика? И есть ли способ устранить или снизить задержку?

4 ответа

Решение

Похоже, я немного неправильно понял проблему: похоже, она связана с отсутствием кэша; когда обработка прерываний ЦП не была ЦП, запустившим ввод-вывод, ЦП может достичь 100% загрузки, а затем все замедляется, создавая впечатление, что между процессорами происходит длительная задержка.

Спасибо всем за их идеи.

Этот патч был только что опубликован в LKML, реализуя QUEUE_FLAG_SAME_CPU на уровне блочных устройств, который описывается как:

Добавьте флаг, чтобы сделать запрос завершенным на процессоре, где запрос отправлен. Флаг подразумевает QUEUE_FLAG_SAME_COMP, По умолчанию он выключен.

Похоже, это может быть именно то, что вам нужно...

Это может быть просто задержка, присущая выдаче IPI от ЦП, который завершил биографию к ЦП, где запланирована задача - чтобы проверить это, попробуйте загрузиться с idle=poll,

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

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

Насколько я понимаю.

Другие вопросы по тегам