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

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

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

في الإصدارين 11 و12 من نظام التشغيل Android، لا يمكن تثبيت 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_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name يحتوي هذا الملف للقراءة فقط على اسم جهة تصدير DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size يحدد هذا الملف للقراءة فقط حجم DMA-BUF بالبايت.

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

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

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

إحصاءات إطار عمل لقطات لعناصر متعدّدة في DMA-BUF

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

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

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

لا تتوفّر واجهة لعرض إحصاءات الكومة لكل ION في Android 11.

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

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

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

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

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

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

‫- kernelUsed - memInfo.getZramTotalSizeKb()

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

  • عمليات التخصيص المباشرة التي أجراها برنامج تشغيل وحدة معالجة الرسومات باستخدام أداة تخصيص الصفحة الفعلية
  • وحدات DMA-BUF التي تم ربطها بمساحة عناوين وحدة معالجة الرسومات

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

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

  • يجب أن تبلغ واجهة برمجة تطبيقات Memtrack HAL getMemory() عند استدعائها باستخدام PID 0 عن الإجمالي العام للذاكرة الخاصة لوحدة معالجة الرسومات، وذلك بالنسبة إلى MemtrackType::GL وMemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • يجب ألا تتعذّر طريقة getMemory() عند استدعائها باستخدام PID 0 لقيمة MemtrackType غير GL. وبدلاً من ذلك، يجب أن يكون الناتج 0.
  • يرصد حلّ نقطة تتبُّع ذاكرة وحدة معالجة الرسومات/eBPF المُضاف في Android 12 إجمالي ذاكرة وحدة معالجة الرسومات. يؤدي طرح إجمالي الذاكرة الخاصة لوحدة معالجة الرسومات من إجمالي ذاكرة وحدة معالجة الرسومات إلى توفير حجم وحدات DMA-BUF المرتبطة بمساحة عنوان وحدة معالجة الرسومات. يمكن بعد ذلك استخدام القيمة لتحسين دقة العمليات الحسابية لذاكرة الوصول العشوائي المفقودة من خلال حساب استخدام ذاكرة وحدة معالجة الرسومات بشكل صحيح.
  • يتم تضمين ذاكرة وحدة معالجة الرسومات الخاصة في 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;

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

إنّ إجمالي ذاكرة وحدة معالجة الرسومات الخاصة وإجمالي ذاكرة وحدة التخزين المؤقت لوحدة التحكّم المباشر بالذاكرة (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 API getGpuDeviceInfo() معلومات عن وحدة معالجة الرسومات المستخدَمة.

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

التنفيذ

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

ومن المقرر تحويل جميع "HALs" الخاصة بـ 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();

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