ملف الترتيب هو أسلوب حديث لتحسين أداء أداة الربط. ملفات الترتيب هي ملفات نصية تحتوي على رموز تمثّل الدوال. تستخدم أدوات الربط، مثل lld، ملفات الترتيب لترتيب الدوال بترتيب معيّن. تؤدي هذه الملفات الثنائية أو المكتبات التي تحتوي على رموز مرتّبة إلى تقليل أخطاء الصفحات وتحسين وقت تشغيل البرنامج، وذلك بسبب التحميل الفعّال للرموز أثناء بدء تشغيل البرنامج لأول مرة.
يمكنك إضافة ميزات ملف الترتيب إلى تطبيقك باتّباع ثلاث خطوات:
- إنشاء الملفات الشخصية وملف الربط
- إنشاء ملف ترتيب من الملفات الشخصية وملف الربط
- استخدام ملف الترتيب أثناء إنشاء إصدار قناة الإصدار العلني لترتيب الرموز
إنشاء ملف الترتيب
يتطلب إنشاء ملف ترتيب ثلاث خطوات:
- إنشاء إصدار من التطبيق يتضمّن أدوات تتبُّع ويكتب ملف الترتيب
- تشغيل التطبيق لإنشاء الملفات الشخصية
- إجراء عملية ما بعد المعالجة على الملفات الشخصية وملف الربط
إنشاء إصدار يتضمّن أدوات تتبُّع
يتم إنشاء الملفات الشخصية من خلال تشغيل إصدار من التطبيق يتضمّن أدوات تتبُّع.
يتطلب إنشاء إصدار يتضمّن أدوات تتبُّع إضافة -forder-file-instrumentation إلى كل من
علامتَي التحويل البرمجي وأداة الربط، مع
-mllvm -orderfile-write-mapping=<filename>-mapping.txt
إضافتها إلى علامتَي التحويل البرمجي فقط.
تفعِّل علامة قياس حالة التطبيق ملف الترتيب لإنشاء الملفات الشخصية، وتحمِّل المكتبة المحدّدة اللازمة لإنشاء الملفات الشخصية.
من ناحية أخرى، لا تُخرِج علامة التعيين سوى ملف التعيين الذي يعرض تجزئة MD5 لكل دالة ضمن البرنامج الثنائي أو المكتبة.
بالإضافة إلى ذلك، احرص على تمرير أي علامة تحسين باستثناء -O0 لأنّ كلتا علامتَي قياس حالة التطبيق والربط تتطلبان علامة تحسين.
إذا لم يتم تمرير أي علامة تحسين، لن يتم إنشاء ملف الربط وقد يُخرِج الإصدار الذي يتضمّن أدوات تتبُّع تجزئات غير صحيحة إلى ملف الملف الشخصي.
ndk-build
احرص على الإنشاء باستخدام APP_OPTIM=release حتى تستخدم أداة ndk-build وضع تحسين آخر غير -O0. عند الإنشاء باستخدام "استوديو Android"، يتم ذلك تلقائيًا لإصدارات قناة الإصدار العلني.
LOCAL_CFLAGS += \
-forder-file-instrumentation \
-mllvm -orderfile-write-mapping=mapping.txt \
LOCAL_LDFLAGS += -forder-file-instrumentation
CMake
احرص على استخدام CMAKE_BUILD_TYPE آخر غير Debug حتى يستخدم CMake وضع تحسين آخر غير -O0. عند الإنشاء باستخدام "استوديو Android"، يتم ذلك تلقائيًا لإصدارات قناة الإصدار العلني.
target_compile_options(orderfiledemo PRIVATE
-forder-file-instrumentation
-mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)
أنظمة الإنشاء الأخرى
يمكنك تجميع الرمز باستخدام -forder-file-instrumentation -O1 -mllvm
-orderfile-write-mapping=mapping.txt.
ليست هناك حاجة إلى استخدام -O1 تحديدًا، ولكن لا تستخدم -O0.
احذف -mllvm -orderfile-write-mapping=mapping.txt عند الربط.
ليست هناك حاجة إلى استخدام كل هذه العلامات لإنشاء إصدار قناة الإصدار العلني، لذا يجب التحكّم فيها من خلال متغيّر إنشاء. لتسهيل الأمر، يمكنك إعداد كل ذلك في ملف CMakeLists.txt كما في المثال الخاص بنا.
إنشاء مكتبة ملف الترتيب
بالإضافة إلى العلامات، يجب إعداد ملف الملف الشخصي ويجب أن يؤدي البرنامج الثنائي الذي يتضمّن قياس حالة التطبيق إلى تشغيل عملية كتابة ملف شخصي بشكلٍ صريح أثناء تنفيذه.
- استخدِم
__llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw")لـ إعداد مسار الملف الشخصي. على الرغم من أنّ الوسيطة التي تم تمريرها هي<filename>-%m.profraw، يتم حفظ ملف الملف الشخصي باسم<filename>-%m.profraw.order. تأكَّد من أنّ التطبيق يمكنه الكتابة فيPROFILE_DIRوأنّ لديك إذن الوصول إلى الدليل.- بسبب إنشاء الملفات الشخصية للعديد من المكتبات المشترَكة، يكون
%mمفيدًا لأنّه يتوسّع ليصبح توقيع وحدة فريدًا للمكتبة، ما يؤدي إلى إنشاء ملف شخصي منفصل لكل مكتبة. لمزيد من محدّدات الأنماط، يمكنك الاطّلاع على هذا الرابط.
- بسبب إنشاء الملفات الشخصية للعديد من المكتبات المشترَكة، يكون
- استخدِم
__llvm_profile_initialize_file()لإعداد ملف الملف الشخصي. - استخدِم
__llvm_orderfile_dump()للكتابة بشكلٍ صريح في ملف الملف الشخصي.
يتم جمع الملفات الشخصية في الذاكرة وتكتبها دالة التفريغ في الملف. عليك التأكّد من استدعاء دالة التفريغ في نهاية عملية بدء التشغيل حتى يحتوي ملف الملف الشخصي على جميع الرموز حتى نهاية عملية بدء التشغيل.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_initialize_file();
__llvm_orderfile_dump();
return;
}
تشغيل عملية الإنشاء للملفات الشخصية
شغِّل التطبيق الذي يتضمّن أدوات تتبُّع على جهاز فعلي أو جهاز افتراضي لإنشاء الملفات الشخصية.
يمكنك استخراج ملفات الملف الشخصي باستخدام adb pull.
adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .
كما ذكرنا سابقًا، تأكَّد من إمكانية وصولك إلى المجلد الذي يحتوي على ملف الملف الشخصي المكتوب. إذا كان جهازًا افتراضيًا، قد يكون من الأفضل تجنُّب المحاكيات التي تتضمّن "متجر Play" بسبب عدم إمكانية الوصول إلى العديد من المجلدات.
إجراء عملية ما بعد المعالجة على الملف الشخصي وملف الربط
عند الحصول على الملفات الشخصية، عليك العثور على ملف الربط وتحويل كل ملف شخصي إلى تنسيق سداسي عشري. يمكنك عادةً العثور على ملف الربط في مجلد الإنشاء الخاص بالتطبيق. بعد الحصول على كليهما، يمكنك استخدام النص البرمجي لأخذ ملف ملف شخصي وملف الربط الصحيح لإنشاء ملف ترتيب.
Linux/Mac/ChromeOS
hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Windows
certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
إذا أردت قراءة المزيد عن النص البرمجي، يمكنك الاطّلاع على هذا README.
استخدام ملف الترتيب لإنشاء التطبيق
بعد إنشاء ملف ترتيب، عليك إزالة العلامات السابقة ودوال ملف الترتيب لأنّها مخصّصة لخطوات الإنشاء فقط.
ما عليك سوى تمرير -Wl,--symbol-ordering-file=<filename>.orderfile إلى علامتَي التحويل البرمجي وأداة الربط.
في بعض الأحيان، لا يمكن العثور على الرموز أو لا يمكن نقلها وتظهر تحذيرات، لذا يمكنك تمرير -Wl,--no-warn-symbol-ordering لإيقاف هذه التحذيرات.
ndk-build
LOCAL_CFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
LOCAL_LDFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
CMake
target_compile_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
أنظمة الإنشاء الأخرى
يمكنك تجميع الرمز باستخدام -Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering.
لمزيد من المعلومات، يمكنك الاطّلاع على مثال ملف الترتيب.
تفاصيل تنفيذ ملف الترتيب
تتوفّر طرق عديدة لإنشاء ملفات الترتيب واستخدامها للإنشاء. تستخدم حزمة تطوير التطبيقات الأصلية طريقة LLVM، لذا فهي الأكثر فائدةً لمكتباتك المشترَكة بلغة C أو C++ بدلاً من تطبيق Java أو Kotlin الفعلي. يأخذ Clang اسم كل دالة (رمز) وينشئ تجزئة MD5 له ويُخرِج هذه العلاقة إلى ملف ربط. تتم كتابة تجزئة MD5 لدالة في ملف الملف الشخصي (بتنسيق profraw) عند تنفيذ الدالة للمرة الأولى. لا تتم كتابة تجزئة MD5 للدالة في ملف الملف الشخصي في أي عمليات تنفيذ لاحقة للدالة لأنّها تريد تجنُّب النُسخ المكرّرة. نتيجةً لذلك، يتم تسجيل عملية التنفيذ الأولى للدالة فقط بالترتيب. من خلال الانتقال إلى ملف الملف الشخصي وملف الربط، يمكنك أخذ كل تجزئة MD5 واستبدالها بالدالة المقابلة والحصول على ملف ترتيب.
يمكنك العثور على أمثلة لكل من ملف الملف الشخصي بتنسيق سداسي عشري وملف الربط باسم example.prof وexample-mapping.txt على التوالي.