फ़ाइलें ऑर्डर करें

ऑर्डर फ़ाइल, लिंक करने की हाल ही की ऑप्टिमाइज़ेशन तकनीक है. ये ऑर्डर फ़ाइलें, टेक्स्ट फ़ाइलें होती हैं. इनमें फ़ंक्शन दिखाने वाले सिंबल होते हैं. एलएलडी जैसे लिंकर, फ़ंक्शन को किसी खास क्रम में लेआउट करने के लिए ऑर्डर फ़ाइलों का इस्तेमाल करते हैं. ऑर्डर किए गए सिंबल वाली ये बाइनरी या लाइब्रेरी, पेज फ़ॉल्ट को कम करती हैं. साथ ही, प्रोग्राम के कोल्ड-स्टार्ट के दौरान सिंबल को बेहतर तरीके से लोड करने की वजह से, प्रोग्राम के लॉन्च होने में लगने वाले समय को कम करती हैं.

ऑर्डर फ़ाइल की सुविधाओं को अपने ऐप्लिकेशन में जोड़ने के लिए, यह तीन चरणों वाली प्रोसेस पूरी करें:

  1. प्रोफ़ाइलें और मैपिंग फ़ाइल जनरेट करना
  2. प्रोफ़ाइलों और मैपिंग फ़ाइल से ऑर्डर फ़ाइल बनाना
  3. सिंबल को लेआउट करने के लिए, रिलीज़ बिल्ड के दौरान ऑर्डर फ़ाइल का इस्तेमाल करें

ऑर्डर फ़ाइल जनरेट करें

ऑर्डर फ़ाइल जनरेट करने के लिए, यह तरीका अपनाएं:

  1. ऐप्लिकेशन का ऐसा वर्शन बनाएं जो ऑर्डर फ़ाइल लिखता हो
  2. प्रोफ़ाइलें जनरेट करने के लिए, ऐप्लिकेशन चलाएं
  3. प्रोफ़ाइलों और मैपिंग फ़ाइल को प्रोसेस करना

इंस्ट्रूमेंट किया गया बिल्ड बनाना

प्रोफ़ाइलें, ऐप्लिकेशन के इंस्ट्रुमेंटेड बिल्ड को चलाकर जनरेट की जाती हैं. इंस्ट्रुमेंट किए गए बिल्ड के लिए, कंपाइलर और लिंकर, दोनों फ़्लैग में -forder-file-instrumentation जोड़ना ज़रूरी है. साथ ही, कंपाइलर फ़्लैग में -mllvm -orderfile-write-mapping=<filename>-mapping.txt जोड़ना भी ज़रूरी है. इंस्ट्रुमेंटेशन फ़्लैग, प्रोफ़ाइलिंग के लिए ऑर्डर फ़ाइल इंस्ट्रुमेंटेशन चालू करता है. साथ ही, प्रोफ़ाइलिंग के लिए ज़रूरी लाइब्रेरी लोड करता है. दूसरी ओर, मैपिंग फ़्लैग सिर्फ़ मैपिंग फ़ाइल को आउटपुट करता है. यह फ़ाइल, बाइनरी या लाइब्रेरी में मौजूद हर फ़ंक्शन के लिए MD5 हैश दिखाती है.

इसके अलावा, पक्का करें कि आपने कोई ऑप्टिमाइज़ेशन फ़्लैग पास किया हो, लेकिन -O0 नहीं, क्योंकि इंस्ट्रुमेंटेशन फ़्लैग और मैपिंग फ़्लैग, दोनों के लिए इसकी ज़रूरत होती है. अगर ऑप्टिमाइज़ेशन का कोई फ़्लैग पास नहीं किया जाता है, तो मैपिंग फ़ाइल जनरेट नहीं होती है. साथ ही, इंस्ट्रुमेंट किए गए बिल्ड से प्रोफ़ाइल फ़ाइल में गलत हैश मिल सकते हैं.

ndk-build

पक्का करें कि आपने APP_OPTIM=release के साथ बनाया हो, ताकि ndk-build, -O0 के अलावा किसी दूसरे ऑप्टिमाइज़ेशन मोड का इस्तेमाल करे. AGP का इस्तेमाल करके रिलीज़ बिल्ड बनाने पर, यह सुविधा अपने-आप चालू हो जाती है.

LOCAL_CFLAGS += \
    -forder-file-instrumentation \
    -mllvm -orderfile-write-mapping=mapping.txt \

LOCAL_LDFLAGS += -forder-file-instrumentation

CMake

पक्का करें कि आपने CMAKE_BUILD_TYPE के अलावा कोई दूसरा फ़्लैग इस्तेमाल किया हो, ताकि CMake, -O0 के अलावा किसी दूसरे ऑप्टिमाइज़ेशन मोड का इस्तेमाल करे.Debug AGP का इस्तेमाल करके रिलीज़ बिल्ड बनाने पर, यह सुविधा अपने-आप चालू हो जाती है.

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 Store वाले एम्युलेटर का इस्तेमाल न करें.

प्रोफ़ाइल और मैपिंग फ़ाइल को पोस्टप्रोसेस करना

प्रोफ़ाइलें मिलने के बाद, आपको मैपिंग फ़ाइल ढूंढनी होगी. इसके बाद, हर प्रोफ़ाइल को हेक्साडेसिमल फ़ॉर्मैट में बदलना होगा. आम तौर पर, आपको मैपिंग फ़ाइल, ऐप्लिकेशन के बिल्ड फ़ोल्डर में मिलती है. अगर आपके पास दोनों फ़ाइलें हैं, तो ऑर्डर फ़ाइल जनरेट करने के लिए, हमारी स्क्रिप्ट का इस्तेमाल किया जा सकता है. इसके लिए, आपको प्रोफ़ाइल फ़ाइल और सही मैपिंग फ़ाइल की ज़रूरत होगी.

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 का इस्तेमाल करके, अपने कोड को कंपाइल करें.

ज़्यादा जानकारी के लिए, ऑर्डर फ़ाइल का उदाहरण देखें.

ऑर्डर फ़ाइल लागू करने से जुड़ी जानकारी

ऑर्डर फ़ाइलें जनरेट करने और उन्हें बनाने के लिए इस्तेमाल करने के कई तरीके हैं. NDK, LLVM के तरीके का इस्तेमाल करता है. इसलिए, यह Java या Kotlin ऐप्लिकेशन के बजाय, आपकी C या C++ शेयर की गई लाइब्रेरी के लिए सबसे ज़्यादा फ़ायदेमंद है. Clang, हर फ़ंक्शन के नाम (सिंबल) को लेता है और उसका MD5 हैश बनाता है. इसके बाद, इस संबंध को मैपिंग फ़ाइल में आउटपुट करता है. जब कोई फ़ंक्शन पहली बार एक्ज़ीक्यूट होता है, तब उस फ़ंक्शन का MD5 हैश, प्रोफ़ाइल फ़ाइल (profraw फ़ॉर्मैट) में लिखा जाता है. फ़ंक्शन के बाद के किसी भी एक्ज़ीक्यूशन में, MD5 हैश को प्रोफ़ाइल फ़ाइल में नहीं लिखा जाता है, क्योंकि यह डुप्लीकेट से बचना चाहता है. इस वजह से, फ़ंक्शन के सिर्फ़ पहले एक्ज़ीक्यूशन को क्रम में रिकॉर्ड किया जाता है. प्रोफ़ाइल फ़ाइल और मैपिंग फ़ाइल की मदद से, हर MD5 हैश को उसके फ़ंक्शन से बदला जा सकता है. इसके बाद, आपको ऑर्डर फ़ाइल मिल जाएगी.

हेक्साडेसिमल फ़ॉर्मैट में प्रोफ़ाइल फ़ाइल और मैपिंग फ़ाइल, दोनों के उदाहरण example.prof और example-mapping.txt के तौर पर देखे जा सकते हैं.