تنفيذ ميزة احتساب ذاكرة وحدة معالجة الرسومات وDMABUF في Android 12

توضّح هذه الصفحة التحسينات المختلفة التي تم إدخالها على نظام احتساب الذاكرة في Android 12.

إحصاءات DMA-BUF في sysfs

في نظامَي التشغيل Android 11 وAndroid 12، لا يمكن تركيب debugfs في إصدارات المستخدمين. لذلك، تمت إضافة إحصاءات DMA-BUF إلى sysfs في الدليل /sys/kernel/dmabuf/buffers في نظام التشغيل Android 12.

المسار الوصف
/sys/kernel/dmabuf/buffers يحتوي الدليل /sys/kernel/dmabuf/buffers على لقطة للحالة الداخلية لكل DMA-BUF. يحتوي /sys/kernel/dmabuf/buffers/<inode_number> على إحصاءات DMA-BUF مع رقم inode الفريد <inode_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name يحتوي هذا الملف للقراءة فقط على اسم أداة تصدير DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size يحدّد هذا الملف للقراءة فقط حجم DMA-BUF بالبايت.

تحلّل واجهة برمجة التطبيقات libdmabufinfo إحصاءات sysfs DMA-BUF لعرض إحصاءات لكل عملية تصدير ولكل مخزن مؤقت.

يُرجى العِلم أنّ برامج تشغيل النواة التي تصدّر DMA-BUF يجب أن تضبط الحقل exp_name في struct dma_buf_export_info بشكل صحيح على اسم المصدر قبل استدعاء واجهة برمجة التطبيقات dma_buf_export() لإنشاء DMA-BUF. هذا الإعداد مطلوب لتطبيق libdmabufinfo وأداة dmabuf_dump من أجل استخلاص إحصاءات لكل مصدِّر، ثم عرضها في bugreport.

تم تعديل أداة dmabuf_dump لعرض هذه المعلومات باستخدام وسيطة جديدة، وهي -b.

إحصاءات إطار عمل أكوام DMA-BUF

سيتم إيقاف ION نهائيًا في الإصدار 2.0 من GKI لصالح إطار عمل أكوام DMA-BUF، وهو جزء من نواة Linux المتوافقة مع أحدث إصدار.

يتم تتبُّع إحصاءات ION العامة التالية في Android 11:

  • إجمالي حجم مخازن DMA-BUFs التي تم تصديرها بواسطة كل كومة ION
  • الحجم الإجمالي للذاكرة غير المستخدَمة والمخصّصة مسبقًا والمخزَّنة في كل كومة ION

لا تتوفّر واجهة لعرض إحصاءات الذاكرة المؤقتة لكل ION في نظام التشغيل Android 11.

يقارن الجدول التالي بين واجهات إحصاءات ION ونظيراتها للأجهزة التي تستخدم إطار عمل مكدس DMA-BUF في Android 12.

الأجهزة التي تعمل بالإصدار 11 من نظام التشغيل Android أو الأجهزة التي تتوافق مع ION في الإصدار 12 من نظام التشغيل Android الأجهزة التي تم إطلاقها مع أكوام DMA-BUF في Android 12
إحصاءات ION لكل كومة بدون تحديد نمط تم تحليلها من إحصاءات DMA-BUF sysfs
إجمالي حجم شرائح الجمهور المحدّدة حسب المنطقة الجغرافية (DMA) وشرائح المستخدمين المحدّدة حسب المنطقة (BUA) التي تم تصديرها /sys/kernel/ion/total_heap_size_kb
(لا يشمل حجم ملفات DMA-BUF التي يتم تصديرها من خلال أدوات التصدير غير التابعة لـ ION)
تم تحليلها من إحصاءات sysfs الخاصة بـ DMA-BUF
(تشمل حجم جميع DMA-BUF التي تم تصديرها).
إجمالي الذاكرة المجمّعة حسب أكوام الذاكرة /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

تحسين دقة احتساب ذاكرة الوصول العشوائي (RAM) المفقودة

في السابق، كان يتم حساب مقدار ذاكرة الوصول العشوائي المفقودة على النحو التالي:

المدة النهائية الطويلة lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)

‫- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

‫- kernelUsed - memInfo.getZramTotalSizeKb()

يتضمّن المكوّن totalPss استخدام ذاكرة وحدة معالجة الرسومات (التي تعرضها واجهة getMemory() في Memtrack HAL). يتضمّن المكوّن kernelUsed إجمالي استخدام ذاكرة DMA-BUF. ومع ذلك، بالنسبة إلى أجهزة Android، كانت ذاكرة وحدة معالجة الرسومات تأتي من المصادر التالية:

  • عمليات التخصيص المباشرة التي ينفّذها برنامج تشغيل وحدة معالجة الرسومات باستخدام أداة تخصيص الصفحات الفعلية
  • وحدات تخزين مؤقتة DMA مرتبطة بمساحة عناوين وحدة معالجة الرسومات

لذلك، تم طرح DMA-BUFs التي تم ربطها بالذاكرة في مساحة عناوين وحدة معالجة الرسومات مرتين عند احتساب ذاكرة الوصول العشوائي المفقودة. يتضمّن نظام التشغيل Android 12 حلاً لاحتساب حجم DMA-BUF التي تم ربطها بمساحة عناوين وحدة معالجة الرسومات، ما يعني أنّه يتم احتسابها مرة واحدة فقط في عملية احتساب Lost RAM.

في ما يلي تفاصيل الحل:

  • يجب أن تعرض واجهة برمجة التطبيقات Memtrack HAL getMemory() عند استدعائها باستخدام معرّف العملية 0 إجمالي الذاكرة الخاصة بوحدة معالجة الرسومات على مستوى النظام، وذلك بالنسبة إلى MemtrackType::GL وMemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • يجب ألا يتعذّر تنفيذ getMemory()‎ عند استدعائه مع PID 0 لعنصر MemtrackType غير GL. يجب أن تعرض القيمة 0 بدلاً من ذلك.
  • يحتسب حل نقطة تتبُّع/eBPF لذاكرة وحدة معالجة الرسومات الذي تمت إضافته في Android 12 إجمالي ذاكرة وحدة معالجة الرسومات. يؤدي طرح إجمالي ذاكرة وحدة معالجة الرسومات الخاصة من إجمالي ذاكرة وحدة معالجة الرسومات إلى توفير حجم DMA-BUFs التي تم ربطها بمساحة عناوين وحدة معالجة الرسومات. يمكن بعد ذلك استخدام القيمة لتحسين دقة حسابات Lost RAM من خلال احتساب استخدام ذاكرة وحدة معالجة الرسومات بشكل صحيح.
  • يتم تضمين ذاكرة وحدة معالجة الرسومات الخاصة في totalPss في معظم عمليات تنفيذ Memtrack HAL، وبالتالي يجب إزالة التكرار قبل إزالتها من lostRAM.

يتم توضيح الحلّ الذي تم تنفيذه في القسم التالي.

إزالة التفاوت في Memtrack من ذاكرة الوصول العشوائي المفقودة

بما أنّ عمليات تنفيذ Memtrack HAL يمكن أن تختلف بين الشركاء، فإنّ ذاكرة وحدة معالجة الرسومات المضمّنة في totalPSS من HAL لا تكون متسقة دائمًا. لإزالة التفاوت من lostRAM، تتم إزالة الذاكرة التي تم احتسابها في MemtrackType::GRAPHICS وMemtrackType::GL من totalPss أثناء عملية حساب lostRAM.

تتم إزالة ذاكرة MemtrackType::GRAPHICS من totalPss واستبدالها بذاكرة totalExportedDmabuf في عملية حساب lostRAM في ActivityManagerService.java كما هو موضّح أدناه:

final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();

. . .

final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;

. . .

// Account unmapped dmabufs as part of the kernel memory allocations
kernelUsed += dmabufUnmapped;

// Replace Memtrack HAL reported Graphics category with mapped dmabufs
totalPss -= totalMemtrackGraphics;
totalPss += dmabufMapped;

تتم إزالة ذاكرة MemtrackType::GL من totalPss واستبدالها بذاكرة وحدة معالجة الرسومات الخاصة (gpuPrivateUsage) في عملية احتساب lostRAM في ActivityManagerService.java كما هو موضّح أدناه:

final long gpuUsage = Debug.getGpuTotalUsageKb();

. . .

final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();

. . .

// Replace the Memtrack HAL-reported GL category with private GPU allocations.
// Count it as part of the kernel memory allocations.
totalPss -= totalMemtrackGl;
kernelUsed += gpuPrivateUsage;

تعديل طريقة احتساب ذاكرة الوصول العشوائي المفقودة

يتم تضمين كلّ من إجمالي ذاكرة وحدة معالجة الرسومات الخاصة وإجمالي ذاكرة مخزن DMA التي تم تصديرها في kernelUsed + totalPss الذي تتم إزالته من lostRAM. يؤدي ذلك إلى إزالة كل من احتساب القيم المكرّرة وتفاوت Memtrack من عملية احتساب ذاكرة الوصول العشوائي المفقودة.

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();

التحقُّق

تفرض اختبارات VTS القاعدة التي تنص على أنّ الأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android والتي تستخدم الإصدار 5.4 أو إصدارًا أحدث من نواة Linux تتوافق مع واجهة برمجة التطبيقات getGpuDeviceInfo().

يجب أن تعرض واجهة برمجة التطبيقات الجديدة Memtrack HAL getGpuDeviceInfo() معلومات عن جهاز وحدة معالجة الرسومات المستخدَم.

يتيح ذلك إمكانية احتساب الذاكرة بشكل أفضل والاطّلاع على استخدام ذاكرة وحدة معالجة الرسومات (GPU) ومخزن DMA المؤقت. نفِّذ واجهة HAL الخاصة بـ memtrack AIDL من أجل تحسين احتساب الذاكرة المفقودة وذاكرة الوصول العشوائي. لا تعتمد هذه الميزة على خدمات Google.

التنفيذ

تعتمد هذه الميزة على AIDL Memtrack HAL، وتتضمّن التعليمات الخاصة بتنفيذها في Android 12 في الرمز البرمجي كتعليقات.

من المخطّط تحويل جميع طبقات HAL لواجهة HIDL إلى AIDL في الإصدارات المستقبلية.

تمت إضافة واجهات برمجة التطبيقات التالية إلى core/java/android/os/Debug.java:

   /**
     * Return total memory size in kilobytes for exported DMA-BUFs or -1 if
     * the DMA-BUF sysfs stats at /sys/kernel/dmabuf/buffers could not be read.
     *
     * @hide
     */
    public static native long getDmabufTotalExportedKb();

   /**
     * Return memory size in kilobytes allocated for DMA-BUF heap pools or -1 if
     * /sys/kernel/dma_heap/total_pools_kb could not be read.
     *
     * @hide
     */
    public static native long getDmabufHeapPoolsSizeKb();

لضمان عمل الإصدار على النحو المطلوب، عليك دمج نقاط التتبُّع في برامج تشغيل وحدة معالجة الرسومات (GPU) وتنفيذ واجهة برمجة التطبيقات AIDL memtrack HAL getMemory() لعرض إجمالي الذاكرة الخاصة بوحدة معالجة الرسومات بشكل صحيح عند طلبها باستخدام المعرّف 0 لـ MemtrackType::GL وMemtrackRecord::FLAG_SMAPS_UNACCOUNTED.