Проблемы с производительностью драйвера miniport WavePci
Влияние звукового драйвера на производительность системы можно значительно снизить, следуя следующим общим принципам:
Сведите к минимуму код, выполняемый во время обычной работы.
Выполняйте код только при необходимости.
Учитывайте общее потребление системных ресурсов (а не только загрузку ЦП).
Оптимизируйте код для скорости и размера.
Кроме того, драйверы miniport WavePci должны устранять несколько проблем с производительностью, характерных для звуковых устройств. В следующем обсуждении рассматриваются в первую очередь проблемы отрисовки звука, хотя некоторые из предлагаемых методов также применяются к захвату звука.
Механизмы обслуживания потоковой передачи
Прежде чем обсуждать оптимизацию производительности, необходимо ознакомиться с механизмами WavePci для обслуживания потоков.
При обработке потока отрисовки или захвата волны звуковое устройство должно регулярно обслуживаться драйвером минипорта. Когда для потока доступны новые сопоставления, драйвер добавляет эти сопоставления в очередь DMA потока. Драйвер также удаляет из очереди все сопоставления, которые уже были обработаны. Дополнительные сведения о сопоставлениях см. в разделе Задержка WavePci.
Для выполнения обслуживания драйвер мини-порта предоставляет отложенный вызов процедуры (DPC) или подпрограмму обслуживания прерываний (ISR) в зависимости от того, задан ли интервал системным таймером или прерываниями, управляемыми DMA. В последнем случае оборудование DMA обычно запускает прерывание каждый раз, если завершает передачу некоторого объема потоковых данных.
При каждом выполнении DPC или ISR он определяет, какие потоки требуют обслуживания. DPC или ISR обслуживает поток, вызывая метод IPortWavePci::Notify . Этот метод принимает в качестве параметра вызова группу служб потока, которая является объектом типа IServiceGroup. Метод Notify вызывает метод RequestService группы служб (см. раздел IServiceSink::RequestService).
Объект группы служб содержит группу приемников служб, которые являются объектами типа IServiceSink. IServiceGroup является производным от IServiceSink, и оба интерфейса имеют методы RequestService . Когда метод Notify вызывает метод RequestService группы служб, группа служб отвечает вызовом метода RequestService для каждого приемника службы в группе.
Группа служб потока содержит по крайней мере один приемник службы, который драйвер порта добавляет в группу служб сразу после создания потока. Драйвер порта вызывает метод IMiniportWavePci::NewStream драйвера минипорта, чтобы получить указатель на группу служб. Метод RequestService приемника службы — это подпрограмма службы, зависят от потока драйвера порта. Эта подпрограмма выполняет следующие действия:
Вызывает метод IMiniportWavePciStream::Service драйвера miniport.
Активирует все новые ожидающие события позиции или часов в потоке с момента последнего выполнения подпрограммы службы.
Как описано в разделе События KS, клиенты могут регистрироваться для получения уведомлений, когда поток достигает определенной позиции или когда часы достигают определенной метки времени. Метод NewStream имеет возможность не предоставлять группу служб. В этом случае драйвер порта настраивает собственный таймер, чтобы пометить интервалы между вызовами служебной процедуры.
Как и метод NewStream , метод IMiniportWavePci::Init драйвера miniport также выводит указатель на группу служб. После вызова Init драйвер порта добавляет приемник службы в группу служб. Этот конкретный приемник службы содержит подпрограмму службы для фильтра в целом. (В предыдущем абзаце описывается приемник службы для потока, связанного с закреплением фильтра.) Эта подпрограмма службы вызывает метод IMiniportWavePci::Service драйвера miniport. Подпрограмма службы выполняется каждый раз, когда DPC или ISR вызывает Notify с группой служб для фильтра. Метод Init может не предоставлять группу служб. В этом случае драйвер порта никогда не вызывает свою процедуру фильтрации.
Аппаратные прерывания
Некоторые драйверы мини-порта создают слишком много или недостаточно аппаратных прерываний. На некоторых устройствах отрисовки WavePci с аппаратным ускорением DirectSound аппаратное прерывание происходит только в том случае, если набор сопоставлений почти исчерпан и механизм отрисовки находится под угрозой голода. На других устройствах WavePci с аппаратным ускорением аппаратное прерывание происходит при каждом завершении сопоставления или при любом другом относительно небольшом интервале. В этом случае ISR часто обнаруживает, что он имеет мало чего делать, но каждое прерывание по-прежнему использует системные ресурсы с переключениями регистров и перезагрузкой кэша. Первым шагом в повышении производительности драйвера является максимальное сокращение количества прерываний без риска голода. После устранения ненужных прерываний можно добиться дополнительного повышения производительности, разработав ISR для более эффективной работы.
В некоторых драйверах ISR тратят время, вызывая метод Notify потока каждый раз, когда происходит прерывание оборудования, независимо от того, запущен ли поток на самом деле. Если ни один поток не находится в состоянии RUN, DMA неактивен, и любое время, затрачиваемое на получение сопоставлений, сопоставлений выпусков или проверка для новых событий в любых потоках, тратится впустую. В эффективном драйвере ISR проверяет выполнение потока перед вызовом метода Notify потока.
Однако драйвер с этим типом ISR должен убедиться, что все ожидающие события в потоке активируются при выходе потока из состояния RUN. В противном случае события могут быть отложены или потеряны. Эта проблема возникает только во время перехода между запуском и паузой в операционных системах, более старых, чем Microsoft Windows XP. В Windows XP и более поздних версиях драйвер порта автоматически сообщает о любых событиях неоплаченных позиций сразу же при изменении состояния потока с RUN на PAUSE. Однако в более старых операционных системах драйвер мини-порта отвечает за активацию любых незаполненных событий, выполняя окончательный вызов Notify сразу после приостановки потока. Дополнительные сведения см. в разделе Оптимизация PAUSE/ACQUIRE ниже.
Типичный драйвер miniport WavePci управляет одним потоком воспроизведения из системного драйвера KMixer. В текущей реализации KMixer для буферизации потока воспроизведения используется как минимум три типа IRP сопоставления. Каждая IRP содержит достаточно буферного хранилища примерно на 10 миллисекундах звука. Если драйвер мини-порта запускает аппаратное прерывание каждый раз, когда контроллер DMA завершает окончательное сопоставление в IRP, прерывания должны происходить с довольно регулярными интервалами в 10 миллисекундах, что достаточно часто, чтобы очередь DMA не голодала.
DPC таймера
Если драйвер управляет любыми потоками DirectSound с аппаратным ускорением, он должен использовать DPC таймера (см. раздел Объекты таймера и DPC) вместо аппаратных прерываний на основе DMA. Аналогично, устройство WavePci на pci карта с встроенным таймером может использовать аппаратное прерывание на основе таймера вместо DPC.
В случае с буфером DirectSound весь буфер может быть присоединен к одной IRP. Если буфер большой и драйвер мини-порта планирует аппаратное прерывание только по достижении конца буфера, последовательные прерывания могут происходить так далеко друг от друга, что очередь DMA голодает. Кроме того, если драйвер управляет большим количеством потоков DirectSound с аппаратным ускорением и каждый поток создает собственные прерывания, то совокупное влияние всех прерываний может снизить производительность системы. В этих обстоятельствах драйверу мини-порта следует избегать использования аппаратных прерываний для планирования обслуживания отдельных потоков. Вместо этого он должен обслуживать все потоки в одном DPC, который должен выполняться в обычные интервалы, создаваемые таймером.
Если задать интервал таймера равным 10 миллисекундам, интервал между последовательными выполнениями DPC аналогичен описанному выше для аппаратного прерывания в случае одного потока воспроизведения KMixer. Таким образом, DPC может обрабатывать поток воспроизведения KMixer в дополнение к потокам DirectSound с аппаратным ускорением.
Когда последний поток выходит из состояния RUN, драйвер мини-порта должен отключить таймер DPC, чтобы избежать потери циклов ЦП системы. Сразу после отключения DPC драйвер должен убедиться, что все события часов или позиций, ожидающие в ранее запущенных потоках, сбрасываются. В Windows 98/Me и Windows 2000 драйвер должен вызвать Notify , чтобы активировать все ожидающие события в приостановленных потоках. В Windows XP и более поздних версиях операционная система автоматически активирует все ожидающие события при выходе потока из состояния RUN, не требуя вмешательства драйвера мини-порта.
Оптимизация PAUSE/ACQUIRE
В Windows 98/Me и Windows 2000 подпрограмма потоковой службы драйвера портов WavePci (метод RequestService ) всегда создает вызов метода IMiniportWavePciStream::Service драйвера мини-порта, независимо от того, находится ли поток в состоянии RUN. В этих операционных системах метод Service должен проверка, выполняется ли поток, прежде чем тратить время на выполнение фактической работы. (Однако, если DPC или ISR драйвера мини-порта уже оптимизированы для вызова Notify только для запущенных потоков, добавление этого проверка в метод Service может оказаться избыточным.)
В Windows XP и более поздних версиях эта оптимизация не нужна, так как метод Notify вызывает метод Service только для запущенных потоков.
Использование интерфейса IPreFetchOffset
Пользователи DirectSound знакомы с двумя понятиями курсора воспроизведения и курсора записи. Курсор воспроизведения указывает положение в потоке данных, выдаваемых с устройства (лучшая оценка драйвера выборки в настоящее время в DAC). Позиция записи — это позиция в потоке следующего безопасного места для записи дополнительных данных клиентом. Для WavePci предполагается, что курсор записи расположен в конце последнего запрошенного сопоставления. Если драйвер минипорта получил большое количество необработанных сопоставлений, смещение между курсором воспроизведения и курсором записи может быть очень большим — достаточно большим, чтобы не выполнить определенные тесты позиции звука WHQL. В Windows XP и более поздних версиях интерфейс IPreFetchOffset устраняет эти проблемы.
Драйвер мини-порта использует IPreFetchOffset для указания характеристик предварительной выборки оборудования master шиной, которые в значительной степени определяются размером оборудования FIFO. Звуковая подсистема использует эти данные для установки постоянного смещения между курсором воспроизведения и курсором записи. Это постоянное смещение, которое может быть значительно меньше, чем смещение по умолчанию, использует тот факт, что данные могут быть записаны в сопоставление даже после передачи сопоставления на оборудование, при условии, что курсор воспроизведения находится достаточно далеко от расположения, в которое записываются данные. (В этой инструкции предполагается, что драйвер не копирует данные и не управляет ими в сопоставлениях.) Типичное смещение может быть в порядке 64 выборок в зависимости от конструкции двигателя. При таком небольшом смещении драйвер WavePci может полностью реагировать и работать, при этом запрашивая большое количество сопоставлений.
Обратите внимание, что в настоящее время DirectSound заполняет курсор записи для контакта с аппаратным ускорением на 10 миллисекунд.
Дополнительные сведения см. в разделе Смещения предварительной выборки.
Обработка данных в сопоставлениях
По возможности старайтесь не заметив, чтобы драйвер оборудования прикасался к данным в сопоставлениях. Любая программная обработка данных, содержащихся в сопоставлениях, должна быть разделена на программный фильтр отдельно от аппаратного драйвера. Выполнение такой обработки драйвером оборудования снижает его эффективность и создает проблемы с задержкой.
Драйвер оборудования должен стремиться быть прозрачным в отношении своих реальных возможностей оборудования. Драйвер никогда не должен утверждать, что обеспечивает аппаратную поддержку преобразования данных, которое фактически выполняется в программном обеспечении.
Примитивы синхронизации
Драйвер с меньшей вероятностью будет иметь взаимоблокировку или проблемы с производительностью сейчас и в будущем, если его код разработан таким образом, чтобы избежать блокировки по возможности. В частности, поток выполнения драйвера должен стремиться выполняться до завершения без риска застоя при ожидании другого потока или ресурса. Например, потоки драйвера могут использовать функции InterlockedXxx (например, см. раздел InterlockedIncrement) для координации доступа к определенным общим ресурсам без риска блокировки.
Хотя это эффективные методы, вы не сможете безопасно удалить все блокировки спина, мьютексы и другие блокирующие примитивы синхронизации из пути выполнения. Используйте функции InterlockedXxx с осторожностью, зная, что неопределенное ожидание может привести к нехватке данных.
Прежде всего, не создавайте пользовательские примитивы синхронизации. Встроенные примитивы Windows (мьютексы, спин-блокировки и т. д.), скорее всего, будут изменены по мере необходимости для поддержки новых функций планировщика в будущем, а драйвер, использующий пользовательские конструкции, практически гарантированно не будет работать в будущем.
Интерфейс IPinCount
В Windows XP и более поздних версиях интерфейс IPinCount позволяет драйверу мини-порта более точно учитывать аппаратные ресурсы, потребляемые при выделении булавки. Вызывая метод IPinCount::P inCount драйвера miniport, драйвер порта выполняет следующие действия:
Предоставляет текущий счетчик контактов фильтра (поддерживаемый драйвером порта) драйверу мини-порта.
Предоставляет драйверу мини-порта возможность пересматривать количество контактов, чтобы динамически отражать текущую доступность аппаратных ресурсов.
Для некоторых звуковых устройств волновые потоки с различными атрибутами (трехмерные, стерео/моно и т. д.) также могут иметь разные "весы" с точки зрения количества потребляемых ими аппаратных ресурсов. При открытии или закрытии "упрощенного" потока драйвер увеличивает или уменьшает количество доступных контактов на единицу. Однако при открытии "тяжеловесного" потока драйверу мини-порта может потребоваться уменьшать количество доступных контактов на два, а не на один, чтобы более точно указать количество контактов, которые можно создать с оставшимися ресурсами.
Процесс отменяется при закрытии тяжеловесного потока. Число доступных контактов может увеличиться более чем на один, чтобы отразить тот факт, что из недавно освобожденных ресурсов можно создать два или более простых потоков.