Улучшение производительности

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

Минимизируйте синхронизацию аппаратного доступа

В Поездке Запроса I/O Через Штабель Массового хранения Вы изучили, как I/O запрашивает перемещения вниз штабель драйвера массового хранения на потоке клиента и как это завершается позже Вашим драйвером HBA на его потоке цикла работы. В этой модели для одного запроса I/O возможно войти в Ваш драйвер одновременно, другой запрос I/O завершается. Когда дело обстоит так, драйвер HBA может отослать команду на шине одновременно, это пытается обработать входящее прерывание. Для некоторых аппаратных средств эта ситуация может вызвать проблемы синхронизации.

Некоторые устройства HBA требуют специальной синхронизации, потому что, например, они не предоставляют одновременный доступ к своим регистрам. Если Ваши аппаратные средства имеют такое требование, несомненно, будут синхронизировать отправку и завершение запросов I/O на Вашем водительском цикле работы.

Как описано в (Требуемых) Запросах на прерывание Дескриптора, IOSCSIParallelInterfaceController вызовы объектов Ваш HandleInterruptRequest метод во вторичном контексте прерывания, с сохраненной блокировкой цикла работы. Для синхронизации выпуска команды с обработкой прерываний, поэтому, необходимо выполнить самый чувствительный код с сохраненной блокировкой. Один способ сделать это должно поместить чувствительный, код доступа регистра в отдельный метод и передать его объекту логического элемента команды работать в runAction подпрограмма. (Для получения дополнительной информации о IOCommandGate::runAction функционируйте, см. документацию для IOCommandGate в Ссылке Платформы Ядра.), Поскольку объект логического элемента команды берет блокировку цикла работы прежде, чем выполнить ее подпрограмму действия, никакие другие источники событий на том же цикле работы (такие как источник события прерывания) не могут работать одновременно. Обратите внимание на то, что Вы не должны создавать свой собственный логический элемент команды. Вместо этого можно использовать GetCommandGate метод доступа получить указатель на логический элемент команды, создаваемый IOSCSIParallelInterfaceController объект.

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

Сообщите о надлежащем размере транзакции

Для достижения лучшей производительности необходимо указать максимальный размер транзакции I/O, который могут обработать аппаратные средства. Учитывая эту информацию, система может отправить к Вашим аппаратным средствам запросы I/O надлежащего размера, и это может увеличить Вашу водительскую пропускную способность.

Информация о максимальном размере транзакции I/O статична и принадлежит Реестра I/O, где другой Набор I/O объекты, такие как другие объекты в штабеле драйвера массового хранения, может найти его. IOKitKeys.h заголовочный файл в платформе Ядра определяет восемь ключей, которые можно использовать для добавления этой информации к водительскому Info.plist файл (каждый ключ требует значения типа OSNumber). Таблица 3-1 перечисляет эти ключи и требуются ли они.

Таблица 3-1  ключи размера транзакции I/O

Ключ

Требуемый

Описание

IOMaximumSegmentCountRead

Да

Максимальное количество физически непересекающихся сегментов (состоящих из нескольких несмежных участков), которые могут быть обработаны на на чтение основание I/O.

IOMaximumSegmentCountWrite

Да

Максимальное количество физически непересекающихся сегментов (состоящих из нескольких несмежных участков), которые могут быть обработаны на на запись основание I/O.

IOMaximumSegmentByteCountRead

Да

Максимальный размер в байтах для каждого физически непересекающегося сегмента (состоящего из нескольких несмежных участков).

IOMaximumSegmentByteCountWrite

Да

Максимальный размер в байтах для каждого физически непересекающегося сегмента (состоящего из нескольких несмежных участков).

IOMaximumByteCountRead

Нет

Для большинства устройств это значение равно продукту значений IOMaximumSegmentByteCountRead и IOMaximumSegmentCountRead ключи.

IOMaximumByteCountWrite

Нет

Для большинства устройств это значение равно продукту значений IOMaximumSegmentByteCountWrite и IOMaximumSegmentCountWrite ключи.

IOMaximumBlockCountRead

Нет

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

IOMaximumBlockCountWrite

Нет

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

Сообщите о надлежащем максимальном количестве задачи

Для достижения лучшей полной производительности системы, в то время как драйвер HBA работает необходимо сообщить, что разумная максимальная задача включает ReportMaximumTaskCount метод. Как описано в Сообщают Специфичную для устройства (Требуемую) информацию, Вы используете этот метод для создания отчетов о максимальном количестве выдающихся задач, которые может обработать устройство HBA. Несмотря на то, что Вы никогда не должны возвращать число, больше, чем поддерживаемое максимальное количество задачи Вашего устройства (если оно определяет один), можно быть в состоянии улучшить производительность системы путем создания отчетов о числе, балансирующем производительность драйвера с той из системы в целом.

IOSCSIParallelInterfaceController класс использует число, которое Вы возвращаете в ReportMaximumTaskCount метод для выделения надлежащего числа SCSIParallelTask объекты. Это - хорошая идея запустить тесты I/O на Вашем драйвере HBA, чтобы узнать, является ли это число предварительно выделенных объектов слишком большим (создание Вашего водительского места, больше, чем необходимый и ухудшение производительности системы) или слишком маленький (то, чтобы заставлять Ваш драйвер блокировать на завершениях I/O слишком часто и ухудшающейся производительности драйвера). Поскольку полная производительность системы влияет на Ваших водительских пользователей, рекомендуется найти оптимальное максимальное значение количества задачи, позволяющее драйверу быть добропорядочным гражданином в OS X.

Выключите объединение прерывания

На других платформах Вы можете быть приучены к выполнению объединения прерывания в Вашем драйвере HBA. Если, например, Ваш драйвер имеет тенденцию выполнять многочисленные очень маленькие транзакции I/O, он мог бы быть целесообразен ожидать нескольких прерываний завершения вместо того, чтобы обработать каждое завершение, как это происходит. Несмотря на то, что пакетная обработка данных завершений I/O может увеличить число операций в секунду I/O, это может ухудшить пропускную способность I/O. Это может быть компромиссом, который Вы готовы принять, но необходимо знать о преимуществах и недостатках объединения прерывания в OS X.

OS X, более вероятно, обработает транзакции I/O синхронно, чем асинхронно. Когда система действительно обработает транзакции I/O асинхронно, она, более вероятно, обработает большие транзакции (например, мегабайт в размере), которые не являются хорошими кандидатами на пакетную обработку. Несмотря на то, что это может казаться парадоксальным, обычно лучше избежать объединения прерывания в Вашем OS X драйвер HBA и вместо этого обработать транзакции I/O отдельно. Как со всеми решениями производительности, однако, необходимо протестировать это с определенными аппаратными средствами и драйвером и проектом соответственно.

Обработайте совместно используемые прерывания

Важно не предположить, что Ваше устройство имеет свою собственную, специализированную линию прерывания. Например, блок расширения может иметь совместно используемую линию прерывания, и иногда два слота платы PCI могут совместно использовать линию прерывания. Другой типичный пример является платой HBA, которая является многофункциональной платой PCI. Этот тип карты может иметь только одну микросхему на нем, но та микросхема может иметь многократные функции (также вызываемые устройства). Когда I/O, Кит обнаруживает такие аппаратные средства, они создают независимого политика IOPCIDevice объект представлять каждую функцию в Реестре I/O. Каждый из них IOPCIDevice объекты являются соответствующими отдельным IOSCSIParallelInterfaceDevice объект (и, если Вы существуете, отдельный экземпляр пользовательского драйвера HBA). Несмотря на то, что каждая функция имеет свой собственный драйвер, эти функции могли бы совместно использовать единственную линию прерывания на самой карте. Когда дело обстоит так, больше чем одна функция может утверждать совместно используемую линию прерывания, когда это должно работать, чтобы быть сделанным. Это заставляет контроллер прерываний вызывать каждую водительскую подпрограмму обработки прерываний поочередно, чтобы найти, что правильная обрабатывает прерывание.

Набор I/O обеспечивает IOFilterInterruptEventSource класс (подкласс IOInterruptEventSource) позволить драйверам обрабатывать совместно использованные прерывания безопасным способом. В дополнение к подпрограмме завершения действия, используемой для обработки прерывания, IOFilterInterruptEventSource класс определяет функцию обратного вызова, которую вызывают в каждом драйвере, совместно использующем линию прерывания. Каждый драйвер реализует эту функцию как фильтр, проверяя, чтобы видеть, ли прерывание действительно для него и отвечающий соответственно. Если возвращается драйвер true в его подпрограмме фильтра Набор I/O автоматически запускает того водительского обработчика прерываний на своем цикле работы, и прерывание остается отключенным в аппаратных средствах до возвратов обработчика прерываний.

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

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

В Вашей реализации FilterInterruptRequest метод, необходимо сначала определить, ли прерывание для Вас. Если это не для Вас, необходимо позволить контроллеру прерываний вызывать другие драйверы и позволять им шанс обработать прерывание. В этом случае Ваша реализация должна сразу возвратиться false.

Если прерывание для Вас, необходимо выполнить в следующем Ваш FilterInterruptRequest метод:

  1. Отключите прерывания для устройства.

  2. Вызовите SignalInterrupt метод. Этот метод планирует Ваше водительское HandleInterruptRequest метод на цикле работы, не отключая линию прерывания.

  3. Возвратиться false.

Затем в Вашем HandleInterruptRequest метод, Вы должны:

  1. Очистите аппаратное условие, повысившее прерывание.

  2. Обработайте прерывание и завершите запрос I/O.

  3. Повторно включите прерывания для устройства.