오디오를 지연시키는 요인

이 페이지에서는 출력 지연 시간의 요인을 집중적으로 다루지만, 유사한 내용이 입력 지연 시간에도 적용됩니다.

아날로그 회로가 주된 요인이 아니라고 가정한다면 오디오를 지연시키는 표면적인 수준의 주요 요인은 다음과 같습니다.

  • 애플리케이션
  • 파이프라인의 총 버퍼 수
  • 각 버퍼의 크기(프레임)
  • DSP 등의 앱 프로세서 이후의 추가적인 지연 시간

위의 요인은 정확할 수 있지만 오해의 소지도 있습니다. 이유는 버퍼 수와 버퍼 크기가 원인이라기보다는 효과에 가깝기 때문입니다. 특정 버퍼 체계가 구현 및 테스트를 거치는데 테스트 도중에 오디오 언더런이나 오버런이 '딸깍'하는 소리나 '펑' 터지는 소리로 들리는 일이 주로 발생합니다. 그러면 시스템 설계자는 이를 보완하기 위해 버퍼 크기나 버퍼 수를 늘립니다. 이 경우 언더런이나 오버런을 제거하는 바람직한 결과를 얻을 수 있지만 지연 시간 증가라는 부작용으로 이어질 수도 있습니다. 버퍼 크기에 관한 자세한 내용은 오디오 지연 시간: 버퍼 크기 동영상을 참고하세요.

더 좋은 접근 방식은 언더런과 오버런의 원인을 이해한 다음 이를 수정하는 것입니다. 그러면 오디오 아티팩트가 제거되고 더 작고 적은 수의 버퍼를 허용하여 지연 시간을 줄일 수 있습니다.

경험에 의해 확인된 언더런과 오버런의 가장 일반적인 원인은 다음과 같습니다.

  • Linux CFS(Completely Fair Scheduler)
  • SCHED_FIFO 스케줄링을 포함하는 높은 우선순위의 스레드
  • 우선순위 역전
  • 긴 스케줄링 지연 시간
  • 오래 실행되는 인터럽트 핸들러
  • 긴 인터럽트 금지 시간
  • 전력 관리
  • 보안 커널

Linux CFS 및 SCHED_FIFO 스케줄링

Linux CFS는 범용 CPU 리소스를 공유하는 경쟁 워크로드에 공정하도록 설계되었습니다. 이러한 공정성은 스레드당 nice 매개변수로 표현됩니다. nice 값의 범위는 -19(nice가 가장 적거나 CPU 시간이 가장 많이 할당됨)부터 20(nice가 최대이거나 CPU 시간이 가장 적게 할당됨) 사이입니다. 일반적으로 주어진 nice 값을 포함하는 모든 스레드는 대략적으로 동일한 CPU 시간과 스레드를 얻으며, 수치적으로 낮은 nice 값은 더 많은 CPU 시간을 얻습니다. 하지만 CFS는 상대적으로 긴 관찰 기간 동안에만 '공정'합니다. 짧은 관찰 기간에는 CFS가 예상치 못한 방식으로 CPU 리소스를 할당할 수 있습니다. 예를 들면 CFS에서 CPU를 nice가 수치적으로 낮은 스레드에서 nice가 수치적으로 높은 스레드로 옮길 수 있습니다. 오디오의 경우에는 이로 인해 언더런이나 오버런이 발생할 수 있습니다.

확실한 해결책은 고성능 오디오 스레드에 CFS의 사용을 피하는 것입니다. Android 4.1부터는 이러한 스레드에 CFS에 의해 구현된 SCHED_NORMAL(SCHED_OTHER라고도 함) 스케줄링 정책 대신 SCHED_FIFO 스케줄링 정책이 사용됩니다.

SCHED_FIFO 우선순위

이제는 고성능 오디오 스레드에 SCHED_FIFO가 사용되지만, 그럼에도 우선순위가 더 높은 다른 SCHED_FIFO 스레드의 영향을 받을 수 있습니다. 이는 커널 작업자 스레드인 경우가 일반적이지만, 정책 SCHED_FIFO를 포함하는 몇 개의 비오디오 사용자 스레드일 수도 있습니다. 사용 가능한 SCHED_FIFO 우선순위 범위는 1~99입니다. 오디오 스레드는 우선순위 2 또는 3에서 실행됩니다. 결과적으로는 우선순위 1을 우선순위가 낮은 스레드에, 우선순위 4~99를 높은 수준의 스레드에 사용할 수 있습니다. 가능한 한 우선순위 1을 사용하며, 우선순위 4~99는 제한된 시간 내에 100% 완료되고, 오디오 스레드 기간보다 짧은 기간으로 실행되고, 오디오 스레드의 스케줄링을 방해하지 않는 것으로 알려진 스레드를 위해 남겨 놓는 것을 권장합니다.

비율 단조 스케줄링

고정된 우선순위 할당 이론에 관한 자세한 내용은 Wikipedia의 비율 단조 스케줄링(RMS)을 참고하세요. 핵심은 인지된 '중요성'이 아닌 기간만을 기준으로 고정된 우선순위를 할당해야 하며, 짧은 기간의 스레드에 높은 우선순위를 할당해야 한다는 것입니다. 비주기적 스레드는 실행의 최대 주파수와 실행당 최대 계산을 사용하여 주기적인 스레드로 모델링할 수 있습니다. 비주기적 스레드를 주기적 스레드로 모델링할 수 없는 경우(예: 실행당 무제한 주파수 또는 무제한 계산으로 실행될 수 있음)에는 고정된 우선순위를 할당하면 안 됩니다. 이는 순수한 주기적 스레드의 스케줄링과 호환되지 않기 때문입니다.

우선순위 역전

우선순위 역전은 실시간 시스템의 전형적인 장애 모드입니다. 여기서는 우선순위가 더 낮은 작업이 뮤텍스에 의해 보호되는 공유 상태와 같은 리소스를 방출할 때까지 우선순위가 더 높은 작업이 무기한 대기하며 차단됩니다. 이를 완화하는 방법은 '우선순위 역전 회피' 문서를 참고하세요.

스케줄링 지연 시간

스케줄링 지연 시간은 스레드 실행 준비가 완료된 시점부터 스레드가 실제로 CPU에서 실행될 수 있도록 결과적인 컨텍스트 전환이 완료되는 시점까지의 시간입니다. 지연 시간은 짧을수록 좋으며, 2밀리초보다 길 경우 오디오 문제의 원인이 됩니다. 긴 스케줄링 지연 시간은 CPU를 가동 또는 종료하거나 보안 커널과 일반 커널 간에 전환하거나 전출력에서 저출력 모드로 전환하거나 CPU 클록 주파수 및 전압을 조정하는 등의 모드 전환 도중에 발생할 가능성이 가장 높습니다.

인터럽트

다수의 설계에서는 CPU 0이 모든 외부 인터럽트를 처리합니다. 따라서 오래 실행되는 인터럽트 핸들러가 다른 인터럽트를 지연시킬 수 있으며, 특히 오디오 직접 메모리 액세스(DMA) 완료 인터럽트의 경우 지연 가능성이 더 높습니다. 인터럽트 핸들러가 빠르게 작업을 마무리하고 긴 작업을 스레드(CFS 스레드 또는 우선순위 1의 SCHED_FIFO 스레드 권장)에 미루도록 설계하세요.

마찬가지로 장시간 동안 CPU 0에서의 인터럽트를 금지할 경우 오디오 인터럽트 처리를 지연시키는 것과 동일한 결과가 발생합니다. 긴 인터럽트 금지 시간은 보통 커널 스핀락을 기다리는 동안 발생합니다. 이러한 스핀락에 제한이 있는지 검토하세요.

전력, 성능 및 열 관리

전력 관리는 성능 최적화 도중의 전력 소모 모니터링 및 절감을 위한 노력을 포괄하는 광범위한 용어입니다. 열 관리컴퓨터 냉각은 유사한 개념이지만 열을 측정하고 제어하여 과열에 의한 손상을 피하도록 합니다. Linux 커널에서는 CPU 거버너가 하위 수준 정책을 담당하고 사용자 모드에서 상위 수준 정책을 구성합니다. 사용되는 기법은 다음과 같습니다.

  • 동적 전압 조정
  • 동적 주파수 조정
  • 동적 코어 지원
  • 클러스터 전환
  • 파워게이팅
  • 핫플러그(핫스왑)
  • 다양한 절전 모드(중지, 중단, 유휴, 일시정지 등)
  • 프로세스 이전
  • 프로세서 어피니티

일부 관리 작업은 '작업 중지'나 애플리케이션 프로세서에 의해 유용한 작업이 실행되지 않는 시간으로 이어질 수 있습니다. 이러한 작업 중지는 오디오를 방해할 수 있으므로 이러한 관리는 오디오 활성 상태에서 용인되는 최악의 작업 중지에 대비하여 설계되어야 합니다. 물론 열폭주가 임박한 경우에는 영구적 피해를 피하는 것이 오디오보다 중요합니다.

보안 커널

디지털 권한 관리(DRM)를 위한 보안 커널이 기본 운영체제 커널 및 애플리케이션 코드에 사용되는 것과 동일한 애플리케이션 프로세서 코어에서 실행될 수 있습니다. 보안 커널 작업이 코어에서 활성화된 시간은 실질적으로 이 코어에서 일반적으로 실행되는 일반 작업의 중지라고 보면 됩니다. 특히 여기에는 오디오 작업이 포함될 수 있습니다. 본질적으로 보안 커널의 내부 동작은 상위 수준의 계층에서 불가해합니다. 따라서 보안 커널에 의한 모든 성능 이상은 특히 치명적입니다. 예를 들어 보안 커널 작업은 컨텍스트 전환 트레이스에 나타나지 않는 것이 일반적입니다. 이를 경과하지만 관찰할 수는 없는 '다크 타임'이라고 부릅니다. 보안 커널은 오디오 활성 상태에서 용인되는 최악의 작업 중지에 대비하여 설계되어야 합니다.