หลีกเลี่ยงการผกผันลำดับความสำคัญ

บทความนี้จะอธิบายวิธีที่ระบบเสียงของ Android พยายามหลีกเลี่ยงการกลับลำดับความสำคัญ และเน้นเทคนิคที่คุณสามารถใช้ได้เช่นกัน

เทคนิคเหล่านี้อาจเป็นประโยชน์สำหรับนักพัฒนาแอปเสียงประสิทธิภาพสูง, OEM และผู้ให้บริการ SoC ที่กำลังใช้งาน HAL เสียง โปรดทราบว่าการใช้เทคนิคเหล่านี้ไม่รับประกันว่าจะป้องกันข้อผิดพลาดหรือความล้มเหลวอื่นๆ โดยเฉพาะอย่างยิ่งหากใช้นอกบริบทของเสียง ผลลัพธ์ของคุณอาจแตกต่างกัน และคุณควรดำเนินการประเมินและทดสอบด้วยตนเอง

พื้นหลัง

เซิร์ฟเวอร์เสียง Android AudioFlinger และการใช้งานไคลเอนต์ AudioTrack/AudioRecord กำลังได้รับการออกแบบใหม่เพื่อลดเวลาในการตอบสนอง งานนี้เริ่มต้นใน Android 4.1 และดำเนินการปรับปรุงเพิ่มเติมใน 4.2, 4.3, 4.4 และ 5.0 ต่อไป

เพื่อให้บรรลุถึงเวลาแฝงที่ลดลงนี้ จำเป็นต้องมีการเปลี่ยนแปลงหลายอย่างทั่วทั้งระบบ การเปลี่ยนแปลงที่สำคัญประการหนึ่งคือการกำหนดทรัพยากร CPU ให้กับเธรดที่มีความสำคัญต่อเวลาด้วยนโยบายการกำหนดตารางเวลาที่คาดเดาได้มากขึ้น การกำหนดเวลาที่เชื่อถือได้ทำให้ขนาดและจำนวนบัฟเฟอร์เสียงลดลง ในขณะที่ยังคงหลีกเลี่ยงปัญหาเสียงเกินและความถี่ต่ำ

การกลับลำดับความสำคัญ

การผกผันลำดับความสำคัญ เป็นโหมดความล้มเหลวแบบคลาสสิกของระบบเรียลไทม์ โดยที่งานที่มีลำดับความสำคัญสูงกว่าจะถูกบล็อกเป็นเวลาที่ไม่มีขอบเขตเพื่อรอให้งานที่มีลำดับความสำคัญต่ำกว่าปล่อยทรัพยากร เช่น (สถานะที่ใช้ร่วมกันที่ได้รับการป้องกันโดย) mutex

ในระบบเสียง การกลับลำดับความสำคัญมักปรากฏเป็น ความผิดพลาด (คลิก ป๊อป ดรอปเอาท์) เสียงที่เกิดซ้ำ เมื่อใช้บัฟเฟอร์แบบวงกลม หรือความล่าช้าในการตอบสนองต่อคำสั่ง

วิธีแก้ปัญหาทั่วไปสำหรับการกลับลำดับความสำคัญคือการเพิ่มขนาดบัฟเฟอร์เสียง อย่างไรก็ตาม วิธีนี้จะเพิ่มเวลาแฝงและเพียงซ่อนปัญหาไว้แทนที่จะแก้ไข เป็นการดีกว่าที่จะทำความเข้าใจและป้องกันการกลับลำดับความสำคัญดังที่แสดงด้านล่าง

ในการใช้งานเสียงของ Android การกลับลำดับความสำคัญมักจะเกิดขึ้นในสถานที่เหล่านี้ ดังนั้นคุณควรมุ่งความสนใจของคุณที่นี่:

  • ระหว่างเธรดมิกเซอร์ปกติและเธรดมิกเซอร์เร็วใน AudioFlinger
  • ระหว่างเธรดการเรียกกลับของแอปพลิเคชันสำหรับ AudioTrack ที่รวดเร็วและเธรดตัวผสมที่รวดเร็ว (ทั้งสองมีลำดับความสำคัญที่สูงขึ้น แต่มีลำดับความสำคัญที่แตกต่างกันเล็กน้อย)
  • ระหว่างเธรดการเรียกกลับของแอปพลิเคชันสำหรับ AudioRecord ที่รวดเร็วและเธรดการจับภาพที่รวดเร็ว (คล้ายกับก่อนหน้า)
  • ภายในการใช้งาน Audio Hardware Abstraction Layer (HAL) เช่น สำหรับการโทรศัพท์หรือการยกเลิกเสียงสะท้อน
  • ภายในไดรเวอร์เสียงในเคอร์เนล
  • ระหว่างเธรดการโทรกลับ AudioTrack หรือ AudioRecord และเธรดแอปอื่น ๆ (ซึ่งอยู่นอกเหนือการควบคุมของเรา)

วิธีแก้ปัญหาทั่วไป

โซลูชั่นทั่วไปได้แก่:

  • ปิดการใช้งานการขัดจังหวะ
  • mutexes การสืบทอดลำดับความสำคัญ

การปิดใช้งานการขัดจังหวะไม่สามารถทำได้ในพื้นที่ผู้ใช้ Linux และไม่สามารถใช้ได้กับ Symmetric Multi-Processors (SMP)

Futexes การสืบทอดลำดับความสำคัญ (mutexes พื้นที่ผู้ใช้ที่รวดเร็ว) จะไม่ถูกใช้ในระบบเสียงเนื่องจากมีน้ำหนักค่อนข้างมากและเนื่องจากต้องใช้ไคลเอนต์ที่เชื่อถือได้

เทคนิคที่ใช้โดย Android

การทดลองเริ่มต้นด้วย "ลองล็อค" และล็อคโดยหมดเวลา สิ่งเหล่านี้คือตัวแปรการบล็อกแบบไม่บล็อกและแบบมีขอบเขตของการดำเนินการล็อค mutex ลองล็อกและล็อกด้วยการหมดเวลาซึ่งทำงานได้ค่อนข้างดี แต่อาจเสี่ยงต่อโหมดความล้มเหลวที่ไม่ชัดเจนบางโหมด: ไม่รับประกันว่าเซิร์ฟเวอร์จะสามารถเข้าถึงสถานะที่ใช้ร่วมกันได้หากไคลเอ็นต์ไม่ว่าง และการหมดเวลาสะสมอาจนานเกินไปหาก มีการล็อคที่ไม่เกี่ยวข้องกันเป็นลำดับยาวจนหมดเวลาทั้งหมด

เรายังใช้ การดำเนินการของอะตอม เช่น:

  • เพิ่มขึ้น
  • ระดับบิต "หรือ"
  • ระดับบิต "และ"

ทั้งหมดนี้ส่งคืนค่าก่อนหน้าและรวมถึงอุปสรรค SMP ที่จำเป็น ข้อเสียคืออาจต้องลองใหม่อย่างไม่มีขอบเขต ในทางปฏิบัติ เราพบว่าการลองใหม่ไม่ใช่ปัญหา

หมายเหตุ: การดำเนินการของอะตอมและการโต้ตอบกับอุปสรรคด้านหน่วยความจำมักถูกเข้าใจผิดอย่างฉาวโฉ่และใช้อย่างไม่ถูกต้อง เรารวมวิธีการเหล่านี้ไว้ที่นี่เพื่อความครบถ้วน แต่ขอแนะนำให้คุณอ่านบทความ SMP Primer สำหรับ Android เพื่อดูข้อมูลเพิ่มเติม

เรายังคงมีและใช้เครื่องมือข้างต้นส่วนใหญ่ และเพิ่งเพิ่มเทคนิคเหล่านี้:

  • ใช้ คิว FIFO ของ ตัวอ่านเดี่ยวตัวอ่านเดี่ยวแบบไม่บล็อกสำหรับข้อมูล
  • พยายาม คัดลอก สถานะแทนที่จะ แชร์ สถานะระหว่างโมดูลที่มีลำดับความสำคัญสูงและต่ำ
  • เมื่อจำเป็นต้องแชร์สถานะ ให้จำกัด สถานะ ให้มีขนาดสูงสุดที่สามารถเข้าถึงได้แบบอะตอมมิกในการดำเนินการแบบบัสเดียวโดยไม่ต้องลองใหม่
  • สำหรับสถานะหลายคำที่ซับซ้อน ให้ใช้คิวสถานะ โดยพื้นฐานแล้วคิวสถานะเป็นเพียงคิว FIFO นักเขียนเดี่ยวตัวอ่านเดี่ยวที่ไม่ปิดกั้นซึ่งใช้สำหรับสถานะแทนที่จะเป็นข้อมูล ยกเว้นตัวเขียนจะยุบพุชที่อยู่ติดกันเป็นการพุชเพียงครั้งเดียว
  • ให้ความสนใจกับ อุปสรรคด้านหน่วยความจำ เพื่อความถูกต้องของ SMP
  • เชื่อใจแต่ต้องพิสูจน์ .. เมื่อแชร์ สถานะ ระหว่างกระบวนการ อย่าถือว่าสถานะมีรูปแบบที่ถูกต้อง ตัวอย่างเช่น ตรวจสอบว่าดัชนีอยู่ภายในขอบเขต ไม่จำเป็นต้องมีการตรวจสอบนี้ระหว่างเธรดในกระบวนการเดียวกัน ระหว่างกระบวนการที่ไว้วางใจซึ่งกันและกัน (ซึ่งโดยทั่วไปจะมี UID เดียวกัน) นอกจากนี้ยังไม่จำเป็นสำหรับ ข้อมูล ที่แชร์ เช่น เสียง PCM ซึ่งความเสียหายไม่สำคัญ

อัลกอริธึมที่ไม่ปิดกั้น

อัลกอริธึมที่ไม่ปิดกั้น เป็นหัวข้อของการศึกษาล่าสุด แต่ยกเว้นคิว FIFO แบบตัวอ่านเดี่ยวแบบตัวอ่านเดียว เราพบว่าคิวเหล่านั้นซับซ้อนและเกิดข้อผิดพลาดได้ง่าย

ตั้งแต่ Android 4.2 เป็นต้นไป คุณจะพบคลาสตัวอ่าน/ตัวเขียนเดี่ยวที่ไม่ปิดกั้นของเราในตำแหน่งเหล่านี้:

  • กรอบงาน/av/รวม/สื่อ/nbaio/
  • กรอบงาน/av/สื่อ/libnbaio/
  • กรอบงาน / av / บริการ / audioflinger / StateQueue *

สิ่งเหล่านี้ได้รับการออกแบบมาโดยเฉพาะสำหรับ AudioFlinger และไม่ได้มีวัตถุประสงค์ทั่วไป อัลกอริธึมที่ไม่ปิดกั้นมีชื่อเสียงในด้านการแก้ไขข้อบกพร่องได้ยาก คุณสามารถดูรหัสนี้เป็นแบบจำลองได้ แต่โปรดทราบว่าอาจมีข้อบกพร่อง และไม่รับประกันว่าคลาสจะเหมาะสำหรับวัตถุประสงค์อื่น

สำหรับนักพัฒนา ควรอัปเดตโค้ดแอปพลิเคชัน OpenSL ES ตัวอย่างบางส่วนเพื่อใช้อัลกอริธึมที่ไม่บล็อกหรืออ้างอิงไลบรารีโอเพ่นซอร์สที่ไม่ใช่ Android

เราได้เผยแพร่ตัวอย่างการใช้งาน FIFO แบบไม่ปิดกั้นซึ่งได้รับการออกแบบมาโดยเฉพาะสำหรับโค้ดแอปพลิเคชัน ดูไฟล์เหล่านี้ที่อยู่ในไดเรกทอรีต้นทางของแพลตฟอร์ม frameworks/av/audio_utils :

เครื่องมือ

เท่าที่เราทราบ ไม่มีเครื่องมืออัตโนมัติสำหรับการค้นหาการผกผันของลำดับความสำคัญ โดยเฉพาะอย่างยิ่งก่อนที่มันจะเกิดขึ้น เครื่องมือวิเคราะห์โค้ดคงที่สำหรับการวิจัยบางรายการสามารถค้นหาการกลับลำดับความสำคัญได้หากสามารถเข้าถึงโค้ดเบสทั้งหมดได้ แน่นอนว่า หากเกี่ยวข้องกับรหัสผู้ใช้โดยพลการ (ตามที่มีอยู่ที่นี่สำหรับแอปพลิเคชัน) หรือมีฐานรหัสขนาดใหญ่ (สำหรับเคอร์เนล Linux และไดรเวอร์อุปกรณ์) การวิเคราะห์แบบคงที่อาจไม่สามารถทำได้ สิ่งที่สำคัญที่สุดคือการอ่านโค้ดอย่างระมัดระวังและเข้าใจระบบทั้งหมดและการโต้ตอบเป็นอย่างดี เครื่องมือเช่น systrace และ ps -t -p มีประโยชน์ในการดูการกลับลำดับความสำคัญหลังจากที่มันเกิดขึ้น แต่อย่าแจ้งให้คุณทราบล่วงหน้า

คำสุดท้าย

หลังจากการสนทนาทั้งหมดนี้ อย่ากลัวการกลายพันธุ์ Mutexes คือเพื่อนของคุณสำหรับการใช้งานทั่วไป เมื่อใช้และนำไปใช้อย่างถูกต้องในกรณีการใช้งานทั่วไปที่ไม่มีความสำคัญด้านเวลา แต่ระหว่างงานที่มีลำดับความสำคัญสูงและต่ำ และในระบบที่ไวต่อเวลา mutexes มีแนวโน้มที่จะทำให้เกิดปัญหามากกว่า