Desempenho em drivers de rede
- Minimizando o comprimento do caminho de envio e recebimento
- Particionamento de dados e código para minimizar o compartilhamento entre processadores
- Evitando o compartilhamento falso
- Usando mecanismos de bloqueio corretamente
- Usando O AMD de 64 bits
- Garantindo o alinhamento adequado do buffer
- Usando Scatter-Gather DMA
- Suporte à limitação do lado do recebimento
Minimizando o comprimento do caminho de envio e recebimento
Embora os caminhos de envio e recebimento sejam diferentes de driver para driver, há algumas regras gerais para otimizações de desempenho:
Otimize para os caminhos comuns. A ferramenta Kernprof.exe é fornecida com os builds de desenvolvedor e IDW do Windows que extraem as informações necessárias. O desenvolvedor deve examinar as rotinas que consomem mais ciclos de CPU e tentar reduzir a frequência dessas rotinas sendo chamadas ou o tempo gasto nessas rotinas.
Reduza o tempo gasto no DPC para que o driver do adaptador de rede não use recursos excessivos do sistema, o que faria com que o desempenho geral do sistema sofresse.
Verifique se o código de depuração não foi compilado na versão final lançada do driver; isso evita a execução de código em excesso.
Particionamento de dados e código para minimizar o compartilhamento entre processadores
O particionamento é necessário para minimizar os dados compartilhados e o código entre processadores. O particionamento ajuda a reduzir a utilização do barramento do sistema e melhora a eficácia do cache do processador. Para minimizar o compartilhamento, os gravadores de driver devem considerar o seguinte:
Implemente o driver como um miniporto desserializado, conforme descrito em Drivers de miniporto NDIS desserializados.
Use estruturas de dados por processador para reduzir o acesso a dados global e compartilhado. Isso permite que você mantenha contadores de estatística sem sincronização, o que reduz o comprimento do caminho do código e aumenta o desempenho. Para estatísticas vitais, tenha contadores por processador que são adicionados juntos no momento da consulta. Se você precisar ter um contador global, use operações interligadas em vez de bloqueios de rotação para manipular o contador. Consulte Usando mecanismos de bloqueio corretamente abaixo para obter informações sobre como evitar o uso de bloqueios de rotação.
Para facilitar isso, KeGetCurrentProcessorNumberEx pode ser usado para determinar o processador atual. Para determinar o número de processadores ao alocar estruturas de dados por processador, KeQueryGroupAffinity pode ser usado.
O número total de bits definidos na máscara de afinidade indica o número de processadores ativos no sistema. Os drivers não devem assumir que todos os bits definidos na máscara serão contíguos porque os processadores podem não ser numerados consecutivamente nas versões futuras do sistema operacional. O número de processadores em um computador SMP é um valor baseado em zero.
Se o driver mantiver dados por processador, você poderá usar a função KeQueryGroupAffinity para reduzir a contenção de linha de cache.
Evitando o compartilhamento falso
O compartilhamento falso ocorre quando os processadores solicitam variáveis compartilhadas que são independentes umas das outras. No entanto, como as variáveis estão na mesma linha de cache, elas são compartilhadas entre os processadores. Nessas situações, a linha de cache viajará entre processadores para cada acesso a qualquer uma das variáveis nela, causando um aumento nas liberações e recarregamentos do cache. Isso aumenta a utilização do barramento do sistema e reduz o desempenho geral do sistema.
Para evitar o compartilhamento falso, alinhe estruturas de dados importantes (como bloqueios de rotação, cabeçalhos de fila de buffer, listas vinculadas com singly) aos limites da linha de cache usando NdisGetSharedDataAlignment.
Usando mecanismos de bloqueio corretamente
Os bloqueios de rotação podem reduzir o desempenho se não forem usados corretamente. Os drivers devem minimizar o uso de bloqueios de rotação usando operações interligadas sempre que possível. No entanto, em alguns casos, um bloqueio de rotação pode ser a melhor opção para algumas finalidades. Por exemplo, se um driver adquire um bloqueio de rotação ao manipular a contagem de referência para o número de pacotes que não foram indicados de volta para o driver, não é necessário usar uma operação interligada. Para obter mais informações, consulte Sincronização e notificação em drivers de rede.
Aqui estão algumas dicas para usar mecanismos de bloqueio com eficiência:
Use funções de lista vinculadas ao NDIS, como as seguintes para gerenciar pools de recursos:
Se você precisar usar bloqueios de rotação, use-os apenas para proteger dados, não código. Não use um bloqueio para proteger todos os dados usados em caminhos comuns. Por exemplo, separe os dados usados nos caminhos de envio e recebimento em duas estruturas de dados para que, quando o caminho de envio precisar bloquear seus dados, o caminho de recebimento não seja afetado.
Se você estiver usando bloqueios de rotação e o caminho já estiver no nível DPC, use as funções NdisDprAcquireSpinLock e NdisDprReleaseSpinLock para evitar código extra ao adquirir e liberar os bloqueios.
Para minimizar o número de aquisições e versões do bloqueio de rotação, use estas funções RWLock do NDIS:
Usando O AMD de 64 bits
DMA de 64 bits Se o adaptador de rede der suporte ao DMA de 64 bits, etapas deverão ser executadas para evitar cópias extras para endereços acima do intervalo de 4 GB. Quando o driver chama NdisMRegisterScatterGatherDma, o sinalizador NDIS_SG_DMA_64_BIT_ADDRESS deve ser definido no parâmetro Flags .
Garantindo o alinhamento adequado do buffer
O alinhamento do buffer em um limite de linha de cache melhora o desempenho ao copiar dados de um buffer para outro. A maioria dos buffers de recebimento do adaptador de rede é alinhada corretamente quando são alocados pela primeira vez, mas os dados do usuário que eventualmente devem ser copiados para o buffer do aplicativo são desalinhados devido ao espaço de cabeçalho consumido. No caso de dados TCP (o cenário mais comum), a mudança devido aos cabeçalhos TCP, IP e Ethernet resulta em uma mudança de 0x36 bytes. Para resolve esse problema, recomendamos que os drivers aloquem um buffer ligeiramente maior e insiram dados de pacote em um deslocamento de 0xA bytes. Isso garantirá que, depois que os buffers forem deslocados por 0x36 bytes para o cabeçalho, os dados do usuário serão alinhados corretamente. Para obter mais informações sobre limites de linha de cache, consulte a seção Comentários para NdisMAllocateSharedMemory.
Usando Scatter-Gather DMA
O DMA de Dispersão/Coleta de NDIS fornece suporte ao hardware para transferir dados de e para intervalos não contíguos de memória física. Scatter-Gather DMA usa uma estrutura SCATTER_GATHER_LIST , que inclui uma matriz de estruturas SCATTER_GATHER_ELEMENT e o número de elementos na matriz. Essa estrutura é recuperada do descritor de pacote passado para a função de envio do driver. Cada elemento da matriz fornece o comprimento e o endereço físico inicial de uma região de Scatter-Gather fisicamente contígua. O driver usa as informações de comprimento e endereço para transferir os dados.
Usar as rotinas de Scatter-Gather para operações de DMA pode melhorar a utilização de recursos do sistema, não bloqueando esses recursos estaticamente, como ocorreria se registros de mapa fossem usados. Para obter mais informações, consulte DMA de dispersão/coleta de NDIS.
Se o adaptador de rede der suporte ao Descarregamento de Segmentação TCP (Descarregamento de Envio Grande), o driver precisará passar o tamanho máximo do buffer que pode obter de TCP/IP para o parâmetro MaximumPhysicalMapping dentro da função NdisMRegisterScatterGatherDma . Isso garantirá que o driver tenha registros de mapa suficientes para criar a lista de Scatter-Gather e eliminar possíveis alocações e cópias de buffer. Para saber mais, consulte esses tópicos:
- Determinando os recursos de descarregamento de tarefas
- Descarregando a segmentação de pacotes TCP grandes
Suporte à limitação do lado do recebimento
Para minimizar interrupções durante a reprodução de mídia em aplicativos multimídia, os drivers NDIS 6.20 e posteriores devem dar suporte ao RST (Limite Lateral de Recebimento) no processamento de interrupções de recebimento. Para obter mais informações, consulte:
Receber limitação lateral no NDIS 6.20 "Enviar e receber caminhos de código" no resumo das alterações necessárias para portar um driver de miniporto para o NDIS 6.20