O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Contribuintes para a latência de áudio

Esta página se concentra nos contribuidores para a latência de saída, mas uma discussão semelhante se aplica à latência de entrada.

Supondo que o circuito analógico não contribua significativamente, os principais contribuintes de nível de superfície para a latência de áudio são os seguintes:

  • Inscrição
  • Número total de buffers no pipeline
  • Tamanho de cada buffer, em quadros
  • Latência adicional após o processador do aplicativo, como de um DSP

Por mais precisa que seja a lista de colaboradores acima, ela também é enganosa. O motivo é que a contagem e o tamanho do buffer são mais um efeito do que uma causa . O que geralmente acontece é que um determinado esquema de buffer é implementado e testado, mas durante o teste, um áudio inferior ou superior é ouvido como um "clique" ou "pop". Para compensar, o projetista do sistema aumenta os tamanhos ou contagens de buffer. Isso tem o resultado desejado de eliminar os underruns ou overruns, mas também tem o efeito colateral indesejado de aumentar a latência. Para obter mais informações sobre tamanhos de buffer, consulte Latência de áudio de vídeo : tamanhos de buffer .

Uma abordagem melhor é entender as causas dos underruns e overruns, e então corrigi-los. Isso elimina os artefatos audíveis e pode permitir buffers ainda menores ou menos e, assim, reduzir a latência.

Em nossa experiência, as causas mais comuns de underruns e overruns incluem:

  • Linux CFS (Completely Fair Scheduler)
  • threads de alta prioridade com agendamento SCHED_FIFO
  • inversão de prioridade
  • longa latência de agendamento
  • manipuladores de interrupção de longa duração
  • longo tempo de desativação de interrupção
  • gerenciamento de energia
  • kernels de segurança

Programação Linux CFS e SCHED_FIFO

O Linux CFS foi projetado para ser justo com cargas de trabalho concorrentes que compartilham um recurso de CPU comum. Essa justiça é representada por um parâmetro legal por thread. O valor agradável varia de -19 (menos bom ou mais tempo de CPU alocado) a 20 (mais bom ou menos tempo de CPU alocado). Em geral, todos os encadeamentos com um determinado valor agradável recebem aproximadamente o mesmo tempo de CPU e os encadeamentos com um valor agradável numericamente inferior devem esperar receber mais tempo de CPU. No entanto, o CFS é "razoável" apenas em períodos relativamente longos de observação. Em janelas de observação de curto prazo, o CFS pode alocar o recurso da CPU de maneiras inesperadas. Por exemplo, pode levar a CPU de um encadeamento com niceness numericamente baixo para um encadeamento com um niceness numericamente alto. No caso do áudio, isso pode resultar em underrun ou overrun.

A solução óbvia é evitar o CFS para threads de áudio de alto desempenho. A partir do Android 4.1, esses threads agora usam a política de agendamento SCHED_FIFO em vez da política de agendamento SCHED_NORMAL (também chamada de SCHED_OTHER ) implementada pelo CFS.

Prioridades SCHED_FIFO

Embora os threads de áudio de alto desempenho agora usem SCHED_FIFO , eles ainda são suscetíveis a outros threads de maior prioridade SCHED_FIFO . Normalmente, são threads de trabalho do kernel, mas também pode haver alguns threads de usuário sem áudio com a política SCHED_FIFO . As prioridades SCHED_FIFO disponíveis variam de 1 a 99. Os threads de áudio são executados na prioridade 2 ou 3. Isso deixa a prioridade 1 disponível para threads de prioridade mais baixa e as prioridades 4 a 99 para threads de prioridade mais alta. Recomendamos que você use a prioridade 1 sempre que possível e reserve as prioridades de 4 a 99 para os threads que têm garantia de conclusão dentro de um determinado período de tempo, são executados com um período mais curto do que o período dos threads de áudio e são conhecidos por não interferir na programação de tópicos de áudio.

Agendamento monotônico de taxa

Para obter mais informações sobre a teoria de atribuição de prioridades fixas, consulte o artigo da Wikipedia Agendamento monotônico de taxas (RMS). Um ponto importante é que as prioridades fixas devem ser alocadas estritamente com base no período, com prioridades mais altas atribuídas a threads de períodos mais curtos, não com base na "importância" percebida. Threads não periódicos podem ser modelados como threads periódicos, usando a frequência máxima de execução e computação máxima por execução. Se um thread não periódico não pode ser modelado como um thread periódico (por exemplo, pode ser executado com frequência ilimitada ou computação ilimitada por execução), então não deve ser atribuída uma prioridade fixa, pois isso seria incompatível com o agendamento de verdadeiros threads periódicos .

Inversão de prioridade

A inversão de prioridade é um modo de falha clássico de sistemas em tempo real, onde uma tarefa de maior prioridade é bloqueada por um tempo ilimitado esperando por uma tarefa de menor prioridade para liberar um recurso como (estado compartilhado protegido por) um mutex . Consulte o artigo " Evitando inversão de prioridade " para técnicas para mitigá-la.

Latência de agendamento

A latência de agendamento é o tempo entre o momento em que um thread fica pronto para ser executado e a conclusão da troca de contexto resultante para que o thread realmente seja executado em uma CPU. Quanto menor a latência, melhor, e qualquer coisa acima de dois milissegundos causa problemas para o áudio. É mais provável que ocorra uma longa latência de agendamento durante as transições de modo, como ligar ou desligar uma CPU, alternar entre um kernel de segurança e o kernel normal, alternar do modo de potência total para o modo de baixa potência ou ajustar a frequência e voltagem do clock da CPU .

Interrupções

Em muitos projetos, a CPU 0 atende a todas as interrupções externas. Portanto, um manipulador de interrupção de longa duração pode atrasar outras interrupções, em particular interrupções de conclusão de acesso direto à memória de áudio (DMA). Projete manipuladores de interrupção para terminar rapidamente e adiar o trabalho demorado para um encadeamento (de preferência um encadeamento CFS ou SCHED_FIFO de prioridade 1).

Da mesma forma, desabilitar interrupções na CPU 0 por um longo período tem o mesmo resultado de atrasar o atendimento de interrupções de áudio. Longos tempos de desativação de interrupção normalmente acontecem durante a espera por um bloqueio de rotação do kernel. Revise esses bloqueios de rotação para garantir que eles sejam limitados.

Gerenciamento de energia, desempenho e térmico

Gerenciamento de energia é um termo amplo que engloba esforços para monitorar e reduzir o consumo de energia enquanto otimiza o desempenho. O gerenciamento térmico e o resfriamento do computador são semelhantes, mas procuram medir e controlar o calor para evitar danos devido ao excesso de calor. No kernel Linux, o governador da CPU é responsável pela política de baixo nível, enquanto o modo de usuário configura a política de alto nível. As técnicas utilizadas incluem:

  • escala de tensão dinâmica
  • escala de frequência dinâmica
  • habilitação de núcleo dinâmico
  • troca de cluster
  • portas de energia
  • hotplug (hotswap)
  • vários modos de hibernação (interromper, parar, inativo, suspender, etc.)
  • migração de processo
  • afinidade de processador

Algumas operações de gerenciamento podem resultar em "paradas de trabalho" ou períodos durante os quais não há trabalho útil executado pelo processador do aplicativo. Essas interrupções no trabalho podem interferir no áudio, portanto, esse gerenciamento deve ser projetado para uma interrupção aceitável do trabalho no pior caso enquanto o áudio está ativo. Claro, quando a fuga térmica é iminente, evitar danos permanentes é mais importante do que o áudio!

Kernels de segurança

Um kernel de segurança para gerenciamento de direitos digitais (DRM) pode ser executado no (s) mesmo (s) núcleo (s) de processador do aplicativo que aqueles usados ​​para o kernel do sistema operacional principal e código do aplicativo. Qualquer momento durante o qual uma operação de kernel de segurança está ativa em um núcleo é efetivamente uma interrupção do trabalho normal que normalmente seria executado naquele núcleo. Em particular, isso pode incluir trabalho de áudio. Por sua natureza, o comportamento interno de um kernel de segurança é inescrutável em camadas de nível superior e, portanto, quaisquer anomalias de desempenho causadas por um kernel de segurança são especialmente perniciosas. Por exemplo, as operações do kernel de segurança normalmente não aparecem nos rastreamentos de troca de contexto. Chamamos isso de "tempo escuro" - tempo que decorre ainda não pode ser observado. Os kernels de segurança devem ser projetados para uma interrupção de trabalho aceitável no pior caso enquanto o áudio está ativo.